Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6:
[AVR32] Initialize phy_mask for both macb devices
[AVR32] Fix atomic_add_unless() and atomic_sub_unless()
[AVR32] Correct misspelled CONFIG_BLK_DEV_INITRD variable.
[AVR32] Fix build error in parse_tag_rdimg()
[AVR32] Don't wire up macb0 unless SW6 is in default position
[AVR32] Wire up SSC platform device 0 as TX on ATSTK1000 board
[AVR32] Add Atmel SSC driver platform device to AT32AP architecture
[AVR32] Remove optimization of unaligned word loads
[AVR32] Make STK1000 mux settings configurable
[AVR32] CPU frequency scaling for AT32AP
[AVR32] Split SM device into PM, RTC, WDT and EIC
[AVR32] faster avr32 unaligned access
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index 4e7614e..ecb47ad 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -9,19 +9,29 @@
Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
Compiling kernel please enable:
-a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
-b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Enable Video for Linux API 1 (DEPRECATED)"
+b.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Video Capture Adapters" => "BT848 Video For Linux"
+c.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
+
+Please use the following options with care as deselection of drivers which are in fact necessary
+may result in DVB devices that cannot be tuned due to lack of driver support:
+You can save RAM by deselecting every frontend module that your DVB card does not need.
+
+First please remove the static dependency of DVB card drivers on all frontend modules for all possible card variants by enabling:
+d.) "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Load and attach frontend modules as needed"
+
+If you know the frontend driver that your card needs please enable:
+e.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Customise DVB Frontends" => "Customise the frontend modules to build"
+ Then please select your card-specific frontend module.
2) Loading Modules
==================
-In default cases bttv is loaded automatically.
-To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
-
- $ modprobe dvb-bt8xx
-
-All frontends will be loaded automatically.
+Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically.
+Exceptions are:
+- Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom.
People running udev please see Documentation/dvb/udev.txt.
In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
@@ -30,7 +40,6 @@
------------------------------
$ modprobe bttv card=113
- $ modprobe dvb-bt8xx
$ modprobe dst
Useful parameters for verbosity level and debugging the dst module:
@@ -65,10 +74,9 @@
Notice: The order of the card ID should be uprising:
Example:
$ modprobe bttv card=113 card=135
- $ modprobe dvb-bt8xx
For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
-In case of further problems send questions to the mailing list: www.linuxdvb.org.
+In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
Authors: Richard Walker,
Jamie Honan,
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 4820366..b4d306a 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -24,7 +24,8 @@
@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
"tda10046lifeview", "av7110", "dec2000t", "dec2540t",
"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
- "or51211", "or51132_qam", "or51132_vsb", "bluebird");
+ "or51211", "or51132_qam", "or51132_vsb", "bluebird",
+ "opera1");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -56,7 +57,7 @@
sub sp8870 {
my $sourcefile = "tt_Premium_217g.zip";
- my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+ my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile";
my $hash = "53970ec17a538945a6d8cb608a7b3899";
my $outfile = "dvb-fe-sp8870.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -210,6 +211,45 @@
$outfile;
}
+sub opera1{
+ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+
+ checkstandard();
+ my $fwfile1="dvb-usb-opera1-fpga-01.fw";
+ my $fwfile2="dvb-usb-opera-01.fw";
+ extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw");
+ extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1");
+ extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2");
+ delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1");
+ delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1");
+ verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70");
+ verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1");
+ verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d");
+
+ my $RES1="\x01\x92\x7f\x00\x01\x00";
+ my $RES0="\x01\x92\x7f\x00\x00\x00";
+ my $DAT1="\x01\x00\xe6\x00\x01\x00";
+ my $DAT0="\x01\x00\xe6\x00\x00\x00";
+ open FW,">$tmpdir/opera.fw";
+ print FW "$RES1";
+ print FW "$DAT1";
+ print FW "$RES1";
+ print FW "$DAT1";
+ appendfile(FW,"$tmpdir/fw1part1-1");
+ print FW "$RES0";
+ print FW "$DAT0";
+ print FW "$RES1";
+ print FW "$DAT1";
+ appendfile(FW,"$tmpdir/fw1part2-1");
+ print FW "$RES1";
+ print FW "$DAT1";
+ print FW "$RES0";
+ print FW "$DAT0";
+ copy ("$tmpdir/opera1-fpga.fw",$fwfile1);
+ copy ("$tmpdir/opera.fw",$fwfile2);
+
+ $fwfile1.",".$fwfile2;
+}
sub vp7041 {
my $sourcefile = "2.422.zip";
@@ -440,6 +480,25 @@
close(INFILE);
}
+sub delzero{
+ my ($infile,$outfile) =@_;
+
+ open INFILE,"<$infile";
+ open OUTFILE,">$outfile";
+ while (1){
+ $rcount=sysread(INFILE,$buf,22);
+ $len=ord(substr($buf,0,1));
+ print OUTFILE substr($buf,0,1);
+ print OUTFILE substr($buf,2,$len+3);
+ last if ($rcount<1);
+ printf OUTFILE "%c",0;
+#print $len." ".length($buf)."\n";
+
+ }
+ close(INFILE);
+ close(OUTFILE);
+}
+
sub syntax() {
print STDERR "syntax: get_dvb_firmware <component>\n";
print STDERR "Supported components:\n";
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
new file mode 100644
index 0000000..93e784c
--- /dev/null
+++ b/Documentation/dvb/opera-firmware.txt
@@ -0,0 +1,27 @@
+To extract the firmware for the Opera DVB-S1 USB-Box
+you need to copy the files:
+
+2830SCap2.sys
+2830SLoad2.sys
+
+from the windriver disk into this directory.
+
+Then run
+
+./get_dvb_firware opera1
+
+and after that you have 2 files:
+
+dvb-usb-opera-01.fw
+dvb-usb-opera1-fpga-01.fw
+
+in here.
+
+Copy them into /lib/firmware/ .
+
+After that the driver can load the firmware
+(if you have enabled firmware loading
+in kernel config and have hotplug running).
+
+
+Marco Gittler <g.marco@freenet.de>
\ No newline at end of file
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index b606391..177159c 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -66,7 +66,7 @@
65 -> Lifeview FlyVideo 2000S LR90
66 -> Terratec TValueRadio [153b:1135,153b:ff3b]
67 -> IODATA GV-BCTV4/PCI [10fc:4050]
- 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA) [121a:3000,10b4:2637]
+ 68 -> 3Dfx VoodooTV FM (Euro) [10b4:2637]
69 -> Active Imaging AIMMS
70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
71 -> Lifeview FlyVideo 98EZ (capture only) LR51 [1851:1851]
@@ -145,3 +145,5 @@
144 -> MagicTV
145 -> SSAI Security Video Interface [4149:5353]
146 -> SSAI Ultrasound Video Interface [414a:5353]
+147 -> VoodooTV 200 (USA) [121a:3000]
+148 -> DViCO FusionHDTV 2 [dbc0:d200]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 60f838b..82ac825 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -55,3 +55,4 @@
54 -> Norwood Micro TV Tuner
55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980]
56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602]
+ 57 -> ADS Tech Instant Video PCI [1421:0390]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 712e8c8..3f8aeab 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -114,3 +114,4 @@
113 -> Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM) [1019:4cb6]
114 -> KWorld DVB-T 210 [17de:7250]
115 -> Sabrent PCMCIA TV-PCB05 [0919:2003]
+116 -> 10MOONS TM300 TV Card [1131:2304]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 44134f0..a88c02d 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -40,7 +40,7 @@
tuner=39 - LG NTSC (newer TAPC series)
tuner=40 - HITACHI V7-J180AT
tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC dual in
+tuner=42 - Philips FCV1236D ATSC/NTSC dual in
tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
tuner=45 - Microtune 4049 FM5
@@ -72,3 +72,4 @@
tuner=71 - Xceive xc3028
tuner=72 - Thomson FE6600
tuner=73 - Samsung TCPG 6121P30A
+tuner=75 - Philips TEA5761 FM Radio
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 279717c..1ffad19 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -436,7 +436,7 @@
HV7131R Hynix Semiconductor | No Yes Yes Yes
MI-0343 Micron Technology | Yes No No No
MI-0360 Micron Technology | No Yes Yes Yes
-OV7630 OmniVision Technologies | Yes Yes No No
+OV7630 OmniVision Technologies | Yes Yes Yes Yes
OV7660 OmniVision Technologies | No No Yes Yes
PAS106B PixArt Imaging | Yes No No No
PAS202B PixArt Imaging | Yes Yes No No
@@ -583,6 +583,7 @@
- Bertrik Sikken, who reverse-engineered and documented the Huffman compression
algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
implemented the first decoder;
+- Ronny Standke for the donation of a webcam;
- Mizuno Takafumi for the donation of a webcam;
- an "anonymous" donator (who didn't want his name to be revealed) for the
donation of a webcam.
diff --git a/Documentation/video4linux/zr364xx.txt b/Documentation/video4linux/zr364xx.txt
index c76992d..4d9a0c3 100644
--- a/Documentation/video4linux/zr364xx.txt
+++ b/Documentation/video4linux/zr364xx.txt
@@ -62,4 +62,4 @@
0x0784 0x0040 Traveler Slimline X5
0x06d6 0x0034 Trust Powerc@m 750
0x0a17 0x0062 Pentax Optio 50L
-
+0x06d6 0x003b Trust Powerc@m 970Z
diff --git a/MAINTAINERS b/MAINTAINERS
index a9615a56..e78f62f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1740,6 +1740,7 @@
i386 SETUP CODE / CPU ERRATA WORKAROUNDS
P: H. Peter Anvin
M: hpa@zytor.com
+T: git.kernel.org:/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git
S: Maintained
IA64 (Itanium) PLATFORM
@@ -2393,7 +2394,7 @@
M: dedekind@infradead.org
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
-T: git git://git.infradead.org/ubi-2.6.git
+T: git git://git.infradead.org/~dedekind/ubi-2.6.git
S: Maintained
MICROTEK X6 SCANNER
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index c7c9c2a..7a11b90 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -222,6 +222,8 @@
However, when run without a hypervisor the kernel is
theoretically slower. If in doubt, say N.
+source "arch/i386/xen/Kconfig"
+
config VMI
bool "VMI Paravirt-ops support"
depends on PARAVIRT
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 181cc29..01f0ff0 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -93,6 +93,9 @@
mcore-$(CONFIG_X86_ES7000) := mach-default
core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/
+# Xen paravirtualization support
+core-$(CONFIG_XEN) += arch/i386/xen/
+
# default subarch .h files
mflags-y += -Iinclude/asm-i386/mach-default
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index 08678a0a..93386a4 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -39,7 +39,7 @@
setup-y += video-vga.o
setup-y += video-vesa.o
setup-y += video-bios.o
-
+targets += $(setup-y)
hostprogs-y := tools/build
HOSTCFLAGS_build.o := $(LINUXINCLUDE)
diff --git a/arch/i386/boot/boot.h b/arch/i386/boot/boot.h
index 0329c4f..dec70c9 100644
--- a/arch/i386/boot/boot.h
+++ b/arch/i386/boot/boot.h
@@ -56,7 +56,7 @@
static inline void outl(u32 v, u16 port)
{
- asm volatile("outl %0,%1" : : "a" (v), "dn" (port));
+ asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
}
static inline u32 inl(u32 port)
{
diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c
index ce4fda2..b0e21c3 100644
--- a/arch/i386/boot/compressed/relocs.c
+++ b/arch/i386/boot/compressed/relocs.c
@@ -31,6 +31,8 @@
"__kernel_rt_sigreturn",
"__kernel_sigreturn",
"SYSENTER_RETURN",
+ "xen_irq_disable_direct_reloc",
+ "xen_save_fl_direct_reloc",
};
static int is_safe_abs_reloc(const char* sym_name)
diff --git a/arch/i386/boot/cpucheck.c b/arch/i386/boot/cpucheck.c
index 8b0f447..991e8ce 100644
--- a/arch/i386/boot/cpucheck.c
+++ b/arch/i386/boot/cpucheck.c
@@ -115,8 +115,8 @@
"pushfl ; "
"popl %1 ; "
"popfl"
- : "=r" (f0), "=r" (f1)
- : "g" (mask));
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (mask));
return !!((f0^f1) & mask);
}
diff --git a/arch/i386/boot/mca.c b/arch/i386/boot/mca.c
index 9b68bd1..68222f2 100644
--- a/arch/i386/boot/mca.c
+++ b/arch/i386/boot/mca.c
@@ -26,7 +26,7 @@
"setc %0 ; "
"movw %%es, %1 ; "
"popw %%es"
- : "=acdSDm" (err), "=acdSDm" (es), "=b" (bx)
+ : "=acd" (err), "=acdSD" (es), "=b" (bx)
: "a" (0xc000));
if (err)
diff --git a/arch/i386/boot/pm.c b/arch/i386/boot/pm.c
index 3fa53e1..1df025c 100644
--- a/arch/i386/boot/pm.c
+++ b/arch/i386/boot/pm.c
@@ -65,7 +65,7 @@
"popw %%ds ; "
"popw %%es"
: "+c" (dwords)
- : "rm" (dst_seg), "rm" (src_seg)
+ : "r" (dst_seg), "r" (src_seg)
: "esi", "edi");
syssize -= paras;
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
index 886f47d8..b424874 100644
--- a/arch/i386/boot/tools/build.c
+++ b/arch/i386/boot/tools/build.c
@@ -5,7 +5,7 @@
*/
/*
- * This file builds a disk-image from three different files:
+ * This file builds a disk-image from two different files:
*
* - setup: 8086 machine code, sets up system parm
* - system: 80386 code for actual system
diff --git a/arch/i386/boot/tty.c b/arch/i386/boot/tty.c
index a8db787..9c668aa 100644
--- a/arch/i386/boot/tty.c
+++ b/arch/i386/boot/tty.c
@@ -31,7 +31,7 @@
/* int $0x10 is known to have bugs involving touching registers
it shouldn't. Be extra conservative... */
- asm volatile("pushal; int $0x10; popal"
+ asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
: : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
}
diff --git a/arch/i386/boot/video.c b/arch/i386/boot/video.c
index 3bb3573..958130e 100644
--- a/arch/i386/boot/video.c
+++ b/arch/i386/boot/video.c
@@ -195,7 +195,7 @@
{
unsigned int font_size, rows;
u16 crtc;
- u8 ov;
+ u8 pt, ov;
set_fs(0);
font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
@@ -206,7 +206,12 @@
crtc = vga_crtc();
+ pt = in_idx(crtc, 0x11);
+ pt &= ~0x80; /* Unlock CR0-7 */
+ out_idx(pt, crtc, 0x11);
+
out_idx((u8)rows, crtc, 0x12); /* Lower height register */
+
ov = in_idx(crtc, 0x07); /* Overflow register */
ov &= 0xbd;
ov |= (rows >> (8-1)) & 0x02;
@@ -411,7 +416,7 @@
"1: rep;stosl ; "
"popw %%es"
: "+D" (dst), "+c" (npad)
- : "bdSm" (video_segment),
+ : "bdS" (video_segment),
"a" (0x07200720));
}
diff --git a/arch/i386/boot/video.h b/arch/i386/boot/video.h
index 29eca17..b92447d 100644
--- a/arch/i386/boot/video.h
+++ b/arch/i386/boot/video.h
@@ -117,8 +117,15 @@
* int $0x10 is notorious for touching registers it shouldn't.
* gcc doesn't like %ebp being clobbered, so define it as a push/pop
* sequence here.
+ *
+ * A number of systems, including the original PC can clobber %bp in
+ * certain circumstances, like when scrolling. There exists at least
+ * one Trident video card which could clobber DS under a set of
+ * circumstances that we are unlikely to encounter (scrolling when
+ * using an extended graphics mode of more than 800x600 pixels), but
+ * it's cheap insurance to deal with that here.
*/
-#define INT10 "pushl %%ebp; int $0x10; popl %%ebp"
+#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
/* Accessing VGA indexed registers */
static inline u8 in_idx(u16 port, u8 index)
diff --git a/arch/i386/boot/voyager.c b/arch/i386/boot/voyager.c
index 9221614..61c8fe0 100644
--- a/arch/i386/boot/voyager.c
+++ b/arch/i386/boot/voyager.c
@@ -32,7 +32,7 @@
"setc %0 ; "
"movw %%es, %1 ; "
"popw %%es"
- : "=qm" (err), "=rm" (es), "=D" (di)
+ : "=q" (err), "=r" (es), "=D" (di)
: "a" (0xffc0));
if (err)
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
index 27a776c..25f7eb5 100644
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -17,6 +17,8 @@
#include <asm/thread_info.h>
#include <asm/elf.h>
+#include <xen/interface/xen.h>
+
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -59,6 +61,7 @@
OFFSET(TI_addr_limit, thread_info, addr_limit);
OFFSET(TI_restart_block, thread_info, restart_block);
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+ OFFSET(TI_cpu, thread_info, cpu);
BLANK();
OFFSET(GDS_size, Xgt_desc_struct, size);
@@ -115,4 +118,10 @@
OFFSET(PARAVIRT_iret, paravirt_ops, iret);
OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
#endif
+
+#ifdef CONFIG_XEN
+ BLANK();
+ OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+ OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 3c3c220..a714d6b 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -409,8 +409,6 @@
1: INTERRUPT_RETURN
.section .fixup,"ax"
iret_exc:
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
pushl $0 # no error code
pushl $do_iret_error
jmp error_code
@@ -1023,6 +1021,91 @@
CFI_ENDPROC
ENDPROC(kernel_thread_helper)
+#ifdef CONFIG_XEN
+ENTRY(xen_hypervisor_callback)
+ CFI_STARTPROC
+ pushl $0
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+ TRACE_IRQS_OFF
+
+ /* Check to see if we got the event in the critical
+ region in xen_iret_direct, after we've reenabled
+ events and checked for pending events. This simulates
+ iret instruction's behaviour where it delivers a
+ pending interrupt when enabling interrupts. */
+ movl PT_EIP(%esp),%eax
+ cmpl $xen_iret_start_crit,%eax
+ jb 1f
+ cmpl $xen_iret_end_crit,%eax
+ jae 1f
+
+ call xen_iret_crit_fixup
+
+1: mov %esp, %eax
+ call xen_evtchn_do_upcall
+ jmp ret_from_intr
+ CFI_ENDPROC
+ENDPROC(xen_hypervisor_callback)
+
+# Hypervisor uses this for application faults while it executes.
+# We get here for two reasons:
+# 1. Fault while reloading DS, ES, FS or GS
+# 2. Fault while executing IRET
+# Category 1 we fix up by reattempting the load, and zeroing the segment
+# register if the load fails.
+# Category 2 we fix up by jumping to do_iret_error. We cannot use the
+# normal Linux return path in this case because if we use the IRET hypercall
+# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+# We distinguish between categories by maintaining a status value in EAX.
+ENTRY(xen_failsafe_callback)
+ CFI_STARTPROC
+ pushl %eax
+ CFI_ADJUST_CFA_OFFSET 4
+ movl $1,%eax
+1: mov 4(%esp),%ds
+2: mov 8(%esp),%es
+3: mov 12(%esp),%fs
+4: mov 16(%esp),%gs
+ testl %eax,%eax
+ popl %eax
+ CFI_ADJUST_CFA_OFFSET -4
+ lea 16(%esp),%esp
+ CFI_ADJUST_CFA_OFFSET -16
+ jz 5f
+ addl $16,%esp
+ jmp iret_exc # EAX != 0 => Category 2 (Bad IRET)
+5: pushl $0 # EAX == 0 => Category 1 (Bad segment)
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+ jmp ret_from_exception
+ CFI_ENDPROC
+
+.section .fixup,"ax"
+6: xorl %eax,%eax
+ movl %eax,4(%esp)
+ jmp 1b
+7: xorl %eax,%eax
+ movl %eax,8(%esp)
+ jmp 2b
+8: xorl %eax,%eax
+ movl %eax,12(%esp)
+ jmp 3b
+9: xorl %eax,%eax
+ movl %eax,16(%esp)
+ jmp 4b
+.previous
+.section __ex_table,"a"
+ .align 4
+ .long 1b,6b
+ .long 2b,7b
+ .long 3b,8b
+ .long 4b,9b
+.previous
+ENDPROC(xen_failsafe_callback)
+
+#endif /* CONFIG_XEN */
+
.section .rodata,"a"
#include "syscall_table.S"
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 8271466..7c52b22 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -510,7 +510,8 @@
/*
* BSS section
*/
-.section ".bss.page_aligned","w"
+.section ".bss.page_aligned","wa"
+ .align PAGE_SIZE_asm
ENTRY(swapper_pg_dir)
.fill 1024,4,0
ENTRY(swapper_pg_pmd)
@@ -538,6 +539,8 @@
.ascii "Int %d: CR2 %p err %p EIP %p CS %p flags %p\n"
.asciz "Stack: %p %p %p %p %p %p %p %p\n"
+#include "../xen/xen-head.S"
+
/*
* The IDT and GDT 'descriptors' are a strange 48-bit object
* only used by the lidt and lgdt instructions. They are not
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index faab09a..53f07a8 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -228,6 +228,41 @@
}
core_initcall(print_banner);
+static struct resource reserve_ioports = {
+ .start = 0,
+ .end = IO_SPACE_LIMIT,
+ .name = "paravirt-ioport",
+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
+};
+
+static struct resource reserve_iomem = {
+ .start = 0,
+ .end = -1,
+ .name = "paravirt-iomem",
+ .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+};
+
+/*
+ * Reserve the whole legacy IO space to prevent any legacy drivers
+ * from wasting time probing for their hardware. This is a fairly
+ * brute-force approach to disabling all non-virtual drivers.
+ *
+ * Note that this must be called very early to have any effect.
+ */
+int paravirt_disable_iospace(void)
+{
+ int ret;
+
+ ret = request_resource(&ioport_resource, &reserve_ioports);
+ if (ret == 0) {
+ ret = request_resource(&iomem_resource, &reserve_iomem);
+ if (ret)
+ release_resource(&reserve_ioports);
+ }
+
+ return ret;
+}
+
struct paravirt_ops paravirt_ops = {
.name = "bare hardware",
.paravirt_enabled = 0,
@@ -267,7 +302,7 @@
.write_msr = native_write_msr_safe,
.read_tsc = native_read_tsc,
.read_pmc = native_read_pmc,
- .get_scheduled_cycles = native_read_tsc,
+ .sched_clock = native_sched_clock,
.get_cpu_khz = native_calculate_cpu_khz,
.load_tr_desc = native_load_tr_desc,
.set_ldt = native_set_ldt,
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 1c075f5..0c8f00e 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -164,14 +164,22 @@
u32 *desc;
unsigned long base;
- down(&child->mm->context.sem);
- desc = child->mm->context.ldt + (seg & ~7);
- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+ seg &= ~7UL;
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
+ down(&child->mm->context.sem);
+ if (unlikely((seg >> 3) >= child->mm->context.size))
+ addr = -1L; /* bogus selector, access would fault */
+ else {
+ desc = child->mm->context.ldt + seg;
+ base = ((desc[0] >> 16) |
+ ((desc[1] & 0xff) << 16) |
+ (desc[1] & 0xff000000));
+
+ /* 16-bit code segment? */
+ if (!((desc[1] >> 22) & 1))
+ addr &= 0xffff;
+ addr += base;
+ }
up(&child->mm->context.sem);
}
return addr;
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 2d61e65..74871d0 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -601,6 +601,8 @@
* NOTE: at this point the bootmem allocator is fully available.
*/
+ paravirt_post_allocator_init();
+
dmi_scan_machine();
#ifdef CONFIG_X86_GENERICARCH
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 6299c08..2d35d85 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -22,6 +22,7 @@
#include <asm/mtrr.h>
#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
#include <mach_apic.h>
/*
@@ -249,13 +250,13 @@
static DEFINE_SPINLOCK(tlbstate_lock);
/*
- * We cannot call mmdrop() because we are in interrupt context,
+ * We cannot call mmdrop() because we are in interrupt context,
* instead update mm->cpu_vm_mask.
*
* We need to reload %cr3 since the page tables may be going
* away from under us..
*/
-static inline void leave_mm (unsigned long cpu)
+void leave_mm(unsigned long cpu)
{
if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
BUG();
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 0b29545..5910d3f 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -148,7 +148,7 @@
* a given CPU
*/
-static void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
{
struct cpuinfo_x86 *c = cpu_data + id;
@@ -308,8 +308,7 @@
/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;
-static inline void
-set_cpu_sibling_map(int cpu)
+void set_cpu_sibling_map(int cpu)
{
int i;
struct cpuinfo_x86 *c = cpu_data;
@@ -1144,8 +1143,7 @@
}
#ifdef CONFIG_HOTPLUG_CPU
-static void
-remove_siblinginfo(int cpu)
+void remove_siblinginfo(int cpu)
{
int sibling;
struct cpuinfo_x86 *c = cpu_data;
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index bf6adce..8344c70 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -323,3 +323,4 @@
.long sys_signalfd
.long sys_timerfd
.long sys_eventfd
+ .long sys_fallocate
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 18c1c28..d32fd4b 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -518,10 +518,12 @@
do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
}
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
siginfo_t info; \
+ if (irq) \
+ local_irq_enable(); \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
@@ -561,13 +563,13 @@
#endif
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip)
+DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0)
DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
+DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
fastcall void __kprobes do_general_protection(struct pt_regs * regs,
long error_code)
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index ea63a30..252f901 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -84,7 +84,7 @@
*
* -johnstul@us.ibm.com "math is hard, lets go shopping!"
*/
-static unsigned long cyc2ns_scale __read_mostly;
+unsigned long cyc2ns_scale __read_mostly;
#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
@@ -93,15 +93,10 @@
cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
}
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
- return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
/*
* Scheduler clock - returns current time in nanosec units.
*/
-unsigned long long sched_clock(void)
+unsigned long long native_sched_clock(void)
{
unsigned long long this_offset;
@@ -118,12 +113,24 @@
return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
/* read the Time Stamp Counter: */
- get_scheduled_cycles(this_offset);
+ rdtscll(this_offset);
/* return the value in ns */
return cycles_2_ns(this_offset);
}
+/* We need to define a real function for sched_clock, to override the
+ weak default version */
+#ifdef CONFIG_PARAVIRT
+unsigned long long sched_clock(void)
+{
+ return paravirt_sched_clock();
+}
+#else
+unsigned long long sched_clock(void)
+ __attribute__((alias("native_sched_clock")));
+#endif
+
unsigned long native_calculate_cpu_khz(void)
{
unsigned long long start, end;
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c
index c12720d..72042bb 100644
--- a/arch/i386/kernel/vmi.c
+++ b/arch/i386/kernel/vmi.c
@@ -362,7 +362,7 @@
}
#endif
-static void vmi_allocate_pt(u32 pfn)
+static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn)
{
vmi_set_page_type(pfn, VMI_PAGE_L1);
vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
@@ -891,7 +891,7 @@
paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
#endif
- paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
+ paravirt_ops.sched_clock = vmi_sched_clock;
paravirt_ops.get_cpu_khz = vmi_cpu_khz;
/* We have true wallclock functions; disable CMOS clock sync */
diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock.c
index 26a37f8..f9b845f 100644
--- a/arch/i386/kernel/vmiclock.c
+++ b/arch/i386/kernel/vmiclock.c
@@ -64,10 +64,10 @@
return 0;
}
-/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
-unsigned long long vmi_get_sched_cycles(void)
+/* paravirt_ops.sched_clock = vmi_sched_clock */
+unsigned long long vmi_sched_clock(void)
{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+ return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
}
/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index aa87b06..00f1bc4 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -88,6 +88,7 @@
. = ALIGN(4096);
.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+ *(.data.page_aligned)
*(.data.idt)
}
diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S
index d4b5be4..271f16a 100644
--- a/arch/i386/kernel/vsyscall-note.S
+++ b/arch/i386/kernel/vsyscall-note.S
@@ -3,23 +3,40 @@
* Here we can supply some information useful to userland.
*/
-#include <linux/uts.h>
#include <linux/version.h>
+#include <linux/elfnote.h>
-#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
- .section name, flags; \
- .balign 4; \
- .long 1f - 0f; /* name length */ \
- .long 3f - 2f; /* data length */ \
- .long type; /* note type */ \
-0: .asciz vendor; /* vendor name */ \
-1: .balign 4; \
-2:
-
-#define ASM_ELF_NOTE_END \
-3: .balign 4; /* pad out section */ \
- .previous
-
- ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+/* Ideally this would use UTS_NAME, but using a quoted string here
+ doesn't work. Remember to change this when changing the
+ kernel's name. */
+ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
- ASM_ELF_NOTE_END
+ELFNOTE_END
+
+#ifdef CONFIG_XEN
+
+/*
+ * Add a special note telling glibc's dynamic linker a fake hardware
+ * flavor that it will use to choose the search path for libraries in the
+ * same way it uses real hardware capabilities like "mmx".
+ * We supply "nosegneg" as the fake capability, to indicate that we
+ * do not like negative offsets in instructions using segment overrides,
+ * since we implement those inefficiently. This makes it possible to
+ * install libraries optimized to avoid those access patterns in someplace
+ * like /lib/i686/tls/nosegneg. Note that an /etc/ld.so.conf.d/file
+ * corresponding to the bits here is needed to make ldconfig work right.
+ * It should contain:
+ * hwcap 1 nosegneg
+ * to match the mapping of bit to name that we give here.
+ */
+
+/* Bit used for the pseudo-hwcap for non-negative segments. We use
+ bit 1 to avoid bugs in some versions of glibc when bit 0 is
+ used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT 1
+
+ELFNOTE_START(GNU, 2, "a")
+ .long 1, 1<<VDSO_NOTE_NONEGSEG_BIT /* ncaps, mask */
+ .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */
+ELFNOTE_END
+#endif
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
index b4b24e0..f9d5953 100644
--- a/arch/i386/mach-voyager/voyager_thread.c
+++ b/arch/i386/mach-voyager/voyager_thread.c
@@ -52,7 +52,7 @@
NULL,
};
- if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) {
+ if ((ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC)) != 0) {
printk(KERN_ERR "Voyager failed to run \"%s\": %i\n",
string, ret);
}
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 7135946..6a68b1a 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -87,7 +87,7 @@
if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
+ paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
BUG_ON(page_table != pte_offset_kernel(pmd, 0));
}
@@ -473,6 +473,7 @@
static int disable_nx __initdata = 0;
u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
/*
* noexec = on|off
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 2eb14a7..37992ff 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -60,7 +60,7 @@
address = __pa(address);
addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
- paravirt_alloc_pt(page_to_pfn(base));
+ paravirt_alloc_pt(&init_mm, page_to_pfn(base));
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
addr == address ? prot : ref_prot));
diff --git a/arch/i386/xen/Kconfig b/arch/i386/xen/Kconfig
new file mode 100644
index 0000000..9df99e1
--- /dev/null
+++ b/arch/i386/xen/Kconfig
@@ -0,0 +1,11 @@
+#
+# This Kconfig describes xen options
+#
+
+config XEN
+ bool "Enable support for Xen hypervisor"
+ depends on PARAVIRT && X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES
+ help
+ This is the Linux Xen port. Enabling this will allow the
+ kernel to boot in a paravirtualized environment under the
+ Xen hypervisor.
diff --git a/arch/i386/xen/Makefile b/arch/i386/xen/Makefile
new file mode 100644
index 0000000..343df24
--- /dev/null
+++ b/arch/i386/xen/Makefile
@@ -0,0 +1,4 @@
+obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \
+ events.o time.o manage.o xen-asm.o
+
+obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
new file mode 100644
index 0000000..9a8c118
--- /dev/null
+++ b/arch/i386/xen/enlighten.c
@@ -0,0 +1,1144 @@
+/*
+ * Core of Xen paravirt_ops implementation.
+ *
+ * This file contains the xen_paravirt_ops structure itself, and the
+ * implementations for:
+ * - privileged instructions
+ * - interrupt flags
+ * - segment operations
+ * - booting and setup
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/preempt.h>
+#include <linux/hardirq.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/start_kernel.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/vcpu.h>
+#include <xen/interface/sched.h>
+#include <xen/features.h>
+#include <xen/page.h>
+
+#include <asm/paravirt.h>
+#include <asm/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/fixmap.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/reboot.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+#include "multicalls.h"
+
+EXPORT_SYMBOL_GPL(hypercall_page);
+
+DEFINE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+DEFINE_PER_CPU(unsigned long, xen_cr3);
+
+struct start_info *xen_start_info;
+EXPORT_SYMBOL_GPL(xen_start_info);
+
+static /* __initdata */ struct shared_info dummy_shared_info;
+
+/*
+ * Point at some empty memory to start with. We map the real shared_info
+ * page as soon as fixmap is up and running.
+ */
+struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
+
+/*
+ * Flag to determine whether vcpu info placement is available on all
+ * VCPUs. We assume it is to start with, and then set it to zero on
+ * the first failure. This is because it can succeed on some VCPUs
+ * and not others, since it can involve hypervisor memory allocation,
+ * or because the guest failed to guarantee all the appropriate
+ * constraints on all VCPUs (ie buffer can't cross a page boundary).
+ *
+ * Note that any particular CPU may be using a placed vcpu structure,
+ * but we can only optimise if the all are.
+ *
+ * 0: not available, 1: available
+ */
+static int have_vcpu_info_placement = 1;
+
+static void __init xen_vcpu_setup(int cpu)
+{
+ struct vcpu_register_vcpu_info info;
+ int err;
+ struct vcpu_info *vcpup;
+
+ per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+
+ if (!have_vcpu_info_placement)
+ return; /* already tested, not available */
+
+ vcpup = &per_cpu(xen_vcpu_info, cpu);
+
+ info.mfn = virt_to_mfn(vcpup);
+ info.offset = offset_in_page(vcpup);
+
+ printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %x, offset %d\n",
+ cpu, vcpup, info.mfn, info.offset);
+
+ /* Check to see if the hypervisor will put the vcpu_info
+ structure where we want it, which allows direct access via
+ a percpu-variable. */
+ err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+
+ if (err) {
+ printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
+ have_vcpu_info_placement = 0;
+ } else {
+ /* This cpu is using the registered vcpu info, even if
+ later ones fail to. */
+ per_cpu(xen_vcpu, cpu) = vcpup;
+
+ printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
+ cpu, vcpup);
+ }
+}
+
+static void __init xen_banner(void)
+{
+ printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
+ paravirt_ops.name);
+ printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic);
+}
+
+static void xen_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ unsigned maskedx = ~0;
+
+ /*
+ * Mask out inconvenient features, to try and disable as many
+ * unsupported kernel subsystems as possible.
+ */
+ if (*eax == 1)
+ maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
+ (1 << X86_FEATURE_ACPI) | /* disable ACPI */
+ (1 << X86_FEATURE_ACC)); /* thermal monitoring */
+
+ asm(XEN_EMULATE_PREFIX "cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (*eax), "2" (*ecx));
+ *edx &= maskedx;
+}
+
+static void xen_set_debugreg(int reg, unsigned long val)
+{
+ HYPERVISOR_set_debugreg(reg, val);
+}
+
+static unsigned long xen_get_debugreg(int reg)
+{
+ return HYPERVISOR_get_debugreg(reg);
+}
+
+static unsigned long xen_save_fl(void)
+{
+ struct vcpu_info *vcpu;
+ unsigned long flags;
+
+ vcpu = x86_read_percpu(xen_vcpu);
+
+ /* flag has opposite sense of mask */
+ flags = !vcpu->evtchn_upcall_mask;
+
+ /* convert to IF type flag
+ -0 -> 0x00000000
+ -1 -> 0xffffffff
+ */
+ return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+ struct vcpu_info *vcpu;
+
+ /* convert from IF type flag */
+ flags = !(flags & X86_EFLAGS_IF);
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = flags;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ if (flags == 0) {
+ preempt_check_resched();
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ force_evtchn_callback();
+ }
+}
+
+static void xen_irq_disable(void)
+{
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+ preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+ struct vcpu_info *vcpu;
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = 0;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+ /* Blocking includes an implicit local_irq_enable(). */
+ if (HYPERVISOR_sched_op(SCHEDOP_block, 0) != 0)
+ BUG();
+}
+
+static void xen_halt(void)
+{
+ if (irqs_disabled())
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ else
+ xen_safe_halt();
+}
+
+static void xen_set_lazy_mode(enum paravirt_lazy_mode mode)
+{
+ BUG_ON(preemptible());
+
+ switch (mode) {
+ case PARAVIRT_LAZY_NONE:
+ BUG_ON(x86_read_percpu(xen_lazy_mode) == PARAVIRT_LAZY_NONE);
+ break;
+
+ case PARAVIRT_LAZY_MMU:
+ case PARAVIRT_LAZY_CPU:
+ BUG_ON(x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE);
+ break;
+
+ case PARAVIRT_LAZY_FLUSH:
+ /* flush if necessary, but don't change state */
+ if (x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE)
+ xen_mc_flush();
+ return;
+ }
+
+ xen_mc_flush();
+ x86_write_percpu(xen_lazy_mode, mode);
+}
+
+static unsigned long xen_store_tr(void)
+{
+ return 0;
+}
+
+static void xen_set_ldt(const void *addr, unsigned entries)
+{
+ unsigned long linear_addr = (unsigned long)addr;
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_SET_LDT;
+ if (linear_addr) {
+ /* ldt my be vmalloced, use arbitrary_virt_to_machine */
+ xmaddr_t maddr;
+ maddr = arbitrary_virt_to_machine((unsigned long)addr);
+ linear_addr = (unsigned long)maddr.maddr;
+ }
+ op->arg1.linear_addr = linear_addr;
+ op->arg2.nr_ents = entries;
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+ unsigned long *frames;
+ unsigned long va = dtr->address;
+ unsigned int size = dtr->size + 1;
+ unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ int f;
+ struct multicall_space mcs;
+
+ /* A GDT can be up to 64k in size, which corresponds to 8192
+ 8-byte entries, or 16 4k pages.. */
+
+ BUG_ON(size > 65536);
+ BUG_ON(va & ~PAGE_MASK);
+
+ mcs = xen_mc_entry(sizeof(*frames) * pages);
+ frames = mcs.args;
+
+ for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
+ frames[f] = virt_to_mfn(va);
+ make_lowmem_page_readonly((void *)va);
+ }
+
+ MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void load_TLS_descriptor(struct thread_struct *t,
+ unsigned int cpu, unsigned int i)
+{
+ struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+ xmaddr_t maddr = virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]);
+ struct multicall_space mc = __xen_mc_entry(0);
+
+ MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]);
+}
+
+static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+ xen_mc_batch();
+
+ load_TLS_descriptor(t, cpu, 0);
+ load_TLS_descriptor(t, cpu, 1);
+ load_TLS_descriptor(t, cpu, 2);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+
+ /*
+ * XXX sleazy hack: If we're being called in a lazy-cpu zone,
+ * it means we're in a context switch, and %gs has just been
+ * saved. This means we can zero it out to prevent faults on
+ * exit from the hypervisor if the next process has no %gs.
+ * Either way, it has been saved, and the new value will get
+ * loaded properly. This will go away as soon as Xen has been
+ * modified to not save/restore %gs for normal hypercalls.
+ */
+ if (xen_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+ loadsegment(gs, 0);
+}
+
+static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
+ u32 low, u32 high)
+{
+ unsigned long lp = (unsigned long)&dt[entrynum];
+ xmaddr_t mach_lp = virt_to_machine(lp);
+ u64 entry = (u64)high << 32 | low;
+
+ preempt_disable();
+
+ xen_mc_flush();
+ if (HYPERVISOR_update_descriptor(mach_lp.maddr, entry))
+ BUG();
+
+ preempt_enable();
+}
+
+static int cvt_gate_to_trap(int vector, u32 low, u32 high,
+ struct trap_info *info)
+{
+ u8 type, dpl;
+
+ type = (high >> 8) & 0x1f;
+ dpl = (high >> 13) & 3;
+
+ if (type != 0xf && type != 0xe)
+ return 0;
+
+ info->vector = vector;
+ info->address = (high & 0xffff0000) | (low & 0x0000ffff);
+ info->cs = low >> 16;
+ info->flags = dpl;
+ /* interrupt gates clear IF */
+ if (type == 0xe)
+ info->flags |= 4;
+
+ return 1;
+}
+
+/* Locations of each CPU's IDT */
+static DEFINE_PER_CPU(struct Xgt_desc_struct, idt_desc);
+
+/* Set an IDT entry. If the entry is part of the current IDT, then
+ also update Xen. */
+static void xen_write_idt_entry(struct desc_struct *dt, int entrynum,
+ u32 low, u32 high)
+{
+ unsigned long p = (unsigned long)&dt[entrynum];
+ unsigned long start, end;
+
+ preempt_disable();
+
+ start = __get_cpu_var(idt_desc).address;
+ end = start + __get_cpu_var(idt_desc).size + 1;
+
+ xen_mc_flush();
+
+ write_dt_entry(dt, entrynum, low, high);
+
+ if (p >= start && (p + 8) <= end) {
+ struct trap_info info[2];
+
+ info[1].address = 0;
+
+ if (cvt_gate_to_trap(entrynum, low, high, &info[0]))
+ if (HYPERVISOR_set_trap_table(info))
+ BUG();
+ }
+
+ preempt_enable();
+}
+
+static void xen_convert_trap_info(const struct Xgt_desc_struct *desc,
+ struct trap_info *traps)
+{
+ unsigned in, out, count;
+
+ count = (desc->size+1) / 8;
+ BUG_ON(count > 256);
+
+ for (in = out = 0; in < count; in++) {
+ const u32 *entry = (u32 *)(desc->address + in * 8);
+
+ if (cvt_gate_to_trap(in, entry[0], entry[1], &traps[out]))
+ out++;
+ }
+ traps[out].address = 0;
+}
+
+void xen_copy_trap_info(struct trap_info *traps)
+{
+ const struct Xgt_desc_struct *desc = &__get_cpu_var(idt_desc);
+
+ xen_convert_trap_info(desc, traps);
+}
+
+/* Load a new IDT into Xen. In principle this can be per-CPU, so we
+ hold a spinlock to protect the static traps[] array (static because
+ it avoids allocation, and saves stack space). */
+static void xen_load_idt(const struct Xgt_desc_struct *desc)
+{
+ static DEFINE_SPINLOCK(lock);
+ static struct trap_info traps[257];
+
+ spin_lock(&lock);
+
+ __get_cpu_var(idt_desc) = *desc;
+
+ xen_convert_trap_info(desc, traps);
+
+ xen_mc_flush();
+ if (HYPERVISOR_set_trap_table(traps))
+ BUG();
+
+ spin_unlock(&lock);
+}
+
+/* Write a GDT descriptor entry. Ignore LDT descriptors, since
+ they're handled differently. */
+static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
+ u32 low, u32 high)
+{
+ preempt_disable();
+
+ switch ((high >> 8) & 0xff) {
+ case DESCTYPE_LDT:
+ case DESCTYPE_TSS:
+ /* ignore */
+ break;
+
+ default: {
+ xmaddr_t maddr = virt_to_machine(&dt[entry]);
+ u64 desc = (u64)high << 32 | low;
+
+ xen_mc_flush();
+ if (HYPERVISOR_update_descriptor(maddr.maddr, desc))
+ BUG();
+ }
+
+ }
+
+ preempt_enable();
+}
+
+static void xen_load_esp0(struct tss_struct *tss,
+ struct thread_struct *thread)
+{
+ struct multicall_space mcs = xen_mc_entry(0);
+ MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->esp0);
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_set_iopl_mask(unsigned mask)
+{
+ struct physdev_set_iopl set_iopl;
+
+ /* Force the change at ring 0. */
+ set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
+ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+}
+
+static void xen_io_delay(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long xen_apic_read(unsigned long reg)
+{
+ return 0;
+}
+
+static void xen_apic_write(unsigned long reg, unsigned long val)
+{
+ /* Warn to see if there's any stray references */
+ WARN_ON(1);
+}
+#endif
+
+static void xen_flush_tlb(void)
+{
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_single(unsigned long addr)
+{
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_INVLPG_LOCAL;
+ op->arg1.linear_addr = addr & PAGE_MASK;
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
+ unsigned long va)
+{
+ struct {
+ struct mmuext_op op;
+ cpumask_t mask;
+ } *args;
+ cpumask_t cpumask = *cpus;
+ struct multicall_space mcs;
+
+ /*
+ * A couple of (to be removed) sanity checks:
+ *
+ * - current CPU must not be in mask
+ * - mask must exist :)
+ */
+ BUG_ON(cpus_empty(cpumask));
+ BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+ BUG_ON(!mm);
+
+ /* If a CPU which we ran on has gone down, OK. */
+ cpus_and(cpumask, cpumask, cpu_online_map);
+ if (cpus_empty(cpumask))
+ return;
+
+ mcs = xen_mc_entry(sizeof(*args));
+ args = mcs.args;
+ args->mask = cpumask;
+ args->op.arg2.vcpumask = &args->mask;
+
+ if (va == TLB_FLUSH_ALL) {
+ args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
+ } else {
+ args->op.cmd = MMUEXT_INVLPG_MULTI;
+ args->op.arg1.linear_addr = va;
+ }
+
+ MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_write_cr2(unsigned long cr2)
+{
+ x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
+}
+
+static unsigned long xen_read_cr2(void)
+{
+ return x86_read_percpu(xen_vcpu)->arch.cr2;
+}
+
+static unsigned long xen_read_cr2_direct(void)
+{
+ return x86_read_percpu(xen_vcpu_info.arch.cr2);
+}
+
+static void xen_write_cr4(unsigned long cr4)
+{
+ /* never allow TSC to be disabled */
+ native_write_cr4(cr4 & ~X86_CR4_TSD);
+}
+
+static unsigned long xen_read_cr3(void)
+{
+ return x86_read_percpu(xen_cr3);
+}
+
+static void xen_write_cr3(unsigned long cr3)
+{
+ BUG_ON(preemptible());
+
+ if (cr3 == x86_read_percpu(xen_cr3)) {
+ /* just a simple tlb flush */
+ xen_flush_tlb();
+ return;
+ }
+
+ x86_write_percpu(xen_cr3, cr3);
+
+
+ {
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+ unsigned long mfn = pfn_to_mfn(PFN_DOWN(cr3));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_NEW_BASEPTR;
+ op->arg1.mfn = mfn;
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+ }
+}
+
+/* Early in boot, while setting up the initial pagetable, assume
+ everything is pinned. */
+static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+{
+ BUG_ON(mem_map); /* should only be used early */
+ make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+}
+
+/* This needs to make sure the new pte page is pinned iff its being
+ attached to a pinned pagetable. */
+static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+
+ if (PagePinned(virt_to_page(mm->pgd))) {
+ SetPagePinned(page);
+
+ if (!PageHighMem(page))
+ make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+ else
+ /* make sure there are no stray mappings of
+ this page */
+ kmap_flush_unused();
+ }
+}
+
+/* This should never happen until we're OK to use struct page */
+static void xen_release_pt(u32 pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+
+ if (PagePinned(page)) {
+ if (!PageHighMem(page))
+ make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+ }
+}
+
+#ifdef CONFIG_HIGHPTE
+static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
+{
+ pgprot_t prot = PAGE_KERNEL;
+
+ if (PagePinned(page))
+ prot = PAGE_KERNEL_RO;
+
+ if (0 && PageHighMem(page))
+ printk("mapping highpte %lx type %d prot %s\n",
+ page_to_pfn(page), type,
+ (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
+
+ return kmap_atomic_prot(page, type, prot);
+}
+#endif
+
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+ /* If there's an existing pte, then don't allow _PAGE_RW to be set */
+ if (pte_val_ma(*ptep) & _PAGE_PRESENT)
+ pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
+ pte_val_ma(pte));
+
+ return pte;
+}
+
+/* Init-time set_pte while constructing initial pagetables, which
+ doesn't allow RO pagetable pages to be remapped RW */
+static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+{
+ pte = mask_rw_pte(ptep, pte);
+
+ xen_set_pte(ptep, pte);
+}
+
+static __init void xen_pagetable_setup_start(pgd_t *base)
+{
+ pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
+
+ /* special set_pte for pagetable initialization */
+ paravirt_ops.set_pte = xen_set_pte_init;
+
+ init_mm.pgd = base;
+ /*
+ * copy top-level of Xen-supplied pagetable into place. For
+ * !PAE we can use this as-is, but for PAE it is a stand-in
+ * while we copy the pmd pages.
+ */
+ memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+ if (PTRS_PER_PMD > 1) {
+ int i;
+ /*
+ * For PAE, need to allocate new pmds, rather than
+ * share Xen's, since Xen doesn't like pmd's being
+ * shared between address spaces.
+ */
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
+ pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+
+ memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
+ PAGE_SIZE);
+
+ make_lowmem_page_readonly(pmd);
+
+ set_pgd(&base[i], __pgd(1 + __pa(pmd)));
+ } else
+ pgd_clear(&base[i]);
+ }
+ }
+
+ /* make sure zero_page is mapped RO so we can use it in pagetables */
+ make_lowmem_page_readonly(empty_zero_page);
+ make_lowmem_page_readonly(base);
+ /*
+ * Switch to new pagetable. This is done before
+ * pagetable_init has done anything so that the new pages
+ * added to the table can be prepared properly for Xen.
+ */
+ xen_write_cr3(__pa(base));
+}
+
+static __init void xen_pagetable_setup_done(pgd_t *base)
+{
+ /* This will work as long as patching hasn't happened yet
+ (which it hasn't) */
+ paravirt_ops.alloc_pt = xen_alloc_pt;
+ paravirt_ops.set_pte = xen_set_pte;
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /*
+ * Create a mapping for the shared info page.
+ * Should be set_fixmap(), but shared_info is a machine
+ * address with no corresponding pseudo-phys address.
+ */
+ set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
+ PFN_DOWN(xen_start_info->shared_info),
+ PAGE_KERNEL);
+
+ HYPERVISOR_shared_info =
+ (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
+
+ } else
+ HYPERVISOR_shared_info =
+ (struct shared_info *)__va(xen_start_info->shared_info);
+
+ /* Actually pin the pagetable down, but we can't set PG_pinned
+ yet because the page structures don't exist yet. */
+ {
+ struct mmuext_op op;
+#ifdef CONFIG_X86_PAE
+ op.cmd = MMUEXT_PIN_L3_TABLE;
+#else
+ op.cmd = MMUEXT_PIN_L3_TABLE;
+#endif
+ op.arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(base)));
+ if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+ BUG();
+ }
+}
+
+/* This is called once we have the cpu_possible_map */
+void __init xen_setup_vcpu_info_placement(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ xen_vcpu_setup(cpu);
+
+ /* xen_vcpu_setup managed to place the vcpu_info within the
+ percpu area for all cpus, so make use of it */
+ if (have_vcpu_info_placement) {
+ printk(KERN_INFO "Xen: using vcpu_info placement\n");
+
+ paravirt_ops.save_fl = xen_save_fl_direct;
+ paravirt_ops.restore_fl = xen_restore_fl_direct;
+ paravirt_ops.irq_disable = xen_irq_disable_direct;
+ paravirt_ops.irq_enable = xen_irq_enable_direct;
+ paravirt_ops.read_cr2 = xen_read_cr2_direct;
+ paravirt_ops.iret = xen_iret_direct;
+ }
+}
+
+static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len)
+{
+ char *start, *end, *reloc;
+ unsigned ret;
+
+ start = end = reloc = NULL;
+
+#define SITE(x) \
+ case PARAVIRT_PATCH(x): \
+ if (have_vcpu_info_placement) { \
+ start = (char *)xen_##x##_direct; \
+ end = xen_##x##_direct_end; \
+ reloc = xen_##x##_direct_reloc; \
+ } \
+ goto patch_site
+
+ switch (type) {
+ SITE(irq_enable);
+ SITE(irq_disable);
+ SITE(save_fl);
+ SITE(restore_fl);
+#undef SITE
+
+ patch_site:
+ if (start == NULL || (end-start) > len)
+ goto default_patch;
+
+ ret = paravirt_patch_insns(insns, len, start, end);
+
+ /* Note: because reloc is assigned from something that
+ appears to be an array, gcc assumes it's non-null,
+ but doesn't know its relationship with start and
+ end. */
+ if (reloc > start && reloc < end) {
+ int reloc_off = reloc - start;
+ long *relocp = (long *)(insns + reloc_off);
+ long delta = start - (char *)insns;
+
+ *relocp += delta;
+ }
+ break;
+
+ default_patch:
+ default:
+ ret = paravirt_patch_default(type, clobbers, insns, len);
+ break;
+ }
+
+ return ret;
+}
+
+static const struct paravirt_ops xen_paravirt_ops __initdata = {
+ .paravirt_enabled = 1,
+ .shared_kernel_pmd = 0,
+
+ .name = "Xen",
+ .banner = xen_banner,
+
+ .patch = xen_patch,
+
+ .memory_setup = xen_memory_setup,
+ .arch_setup = xen_arch_setup,
+ .init_IRQ = xen_init_IRQ,
+ .post_allocator_init = xen_mark_init_mm_pinned,
+
+ .time_init = xen_time_init,
+ .set_wallclock = xen_set_wallclock,
+ .get_wallclock = xen_get_wallclock,
+ .get_cpu_khz = xen_cpu_khz,
+ .sched_clock = xen_sched_clock,
+
+ .cpuid = xen_cpuid,
+
+ .set_debugreg = xen_set_debugreg,
+ .get_debugreg = xen_get_debugreg,
+
+ .clts = native_clts,
+
+ .read_cr0 = native_read_cr0,
+ .write_cr0 = native_write_cr0,
+
+ .read_cr2 = xen_read_cr2,
+ .write_cr2 = xen_write_cr2,
+
+ .read_cr3 = xen_read_cr3,
+ .write_cr3 = xen_write_cr3,
+
+ .read_cr4 = native_read_cr4,
+ .read_cr4_safe = native_read_cr4_safe,
+ .write_cr4 = xen_write_cr4,
+
+ .save_fl = xen_save_fl,
+ .restore_fl = xen_restore_fl,
+ .irq_disable = xen_irq_disable,
+ .irq_enable = xen_irq_enable,
+ .safe_halt = xen_safe_halt,
+ .halt = xen_halt,
+ .wbinvd = native_wbinvd,
+
+ .read_msr = native_read_msr_safe,
+ .write_msr = native_write_msr_safe,
+ .read_tsc = native_read_tsc,
+ .read_pmc = native_read_pmc,
+
+ .iret = (void *)&hypercall_page[__HYPERVISOR_iret],
+ .irq_enable_sysexit = NULL, /* never called */
+
+ .load_tr_desc = paravirt_nop,
+ .set_ldt = xen_set_ldt,
+ .load_gdt = xen_load_gdt,
+ .load_idt = xen_load_idt,
+ .load_tls = xen_load_tls,
+
+ .store_gdt = native_store_gdt,
+ .store_idt = native_store_idt,
+ .store_tr = xen_store_tr,
+
+ .write_ldt_entry = xen_write_ldt_entry,
+ .write_gdt_entry = xen_write_gdt_entry,
+ .write_idt_entry = xen_write_idt_entry,
+ .load_esp0 = xen_load_esp0,
+
+ .set_iopl_mask = xen_set_iopl_mask,
+ .io_delay = xen_io_delay,
+
+#ifdef CONFIG_X86_LOCAL_APIC
+ .apic_write = xen_apic_write,
+ .apic_write_atomic = xen_apic_write,
+ .apic_read = xen_apic_read,
+ .setup_boot_clock = paravirt_nop,
+ .setup_secondary_clock = paravirt_nop,
+ .startup_ipi_hook = paravirt_nop,
+#endif
+
+ .flush_tlb_user = xen_flush_tlb,
+ .flush_tlb_kernel = xen_flush_tlb,
+ .flush_tlb_single = xen_flush_tlb_single,
+ .flush_tlb_others = xen_flush_tlb_others,
+
+ .pte_update = paravirt_nop,
+ .pte_update_defer = paravirt_nop,
+
+ .pagetable_setup_start = xen_pagetable_setup_start,
+ .pagetable_setup_done = xen_pagetable_setup_done,
+
+ .alloc_pt = xen_alloc_pt_init,
+ .release_pt = xen_release_pt,
+ .alloc_pd = paravirt_nop,
+ .alloc_pd_clone = paravirt_nop,
+ .release_pd = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+ .kmap_atomic_pte = xen_kmap_atomic_pte,
+#endif
+
+ .set_pte = NULL, /* see xen_pagetable_setup_* */
+ .set_pte_at = xen_set_pte_at,
+ .set_pmd = xen_set_pmd,
+
+ .pte_val = xen_pte_val,
+ .pgd_val = xen_pgd_val,
+
+ .make_pte = xen_make_pte,
+ .make_pgd = xen_make_pgd,
+
+#ifdef CONFIG_X86_PAE
+ .set_pte_atomic = xen_set_pte_atomic,
+ .set_pte_present = xen_set_pte_at,
+ .set_pud = xen_set_pud,
+ .pte_clear = xen_pte_clear,
+ .pmd_clear = xen_pmd_clear,
+
+ .make_pmd = xen_make_pmd,
+ .pmd_val = xen_pmd_val,
+#endif /* PAE */
+
+ .activate_mm = xen_activate_mm,
+ .dup_mmap = xen_dup_mmap,
+ .exit_mmap = xen_exit_mmap,
+
+ .set_lazy_mode = xen_set_lazy_mode,
+};
+
+#ifdef CONFIG_SMP
+static const struct smp_ops xen_smp_ops __initdata = {
+ .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
+ .smp_prepare_cpus = xen_smp_prepare_cpus,
+ .cpu_up = xen_cpu_up,
+ .smp_cpus_done = xen_smp_cpus_done,
+
+ .smp_send_stop = xen_smp_send_stop,
+ .smp_send_reschedule = xen_smp_send_reschedule,
+ .smp_call_function_mask = xen_smp_call_function_mask,
+};
+#endif /* CONFIG_SMP */
+
+static void xen_reboot(int reason)
+{
+#ifdef CONFIG_SMP
+ smp_send_stop();
+#endif
+
+ if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+ BUG();
+}
+
+static void xen_restart(char *msg)
+{
+ xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_emergency_restart(void)
+{
+ xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_machine_halt(void)
+{
+ xen_reboot(SHUTDOWN_poweroff);
+}
+
+static void xen_crash_shutdown(struct pt_regs *regs)
+{
+ xen_reboot(SHUTDOWN_crash);
+}
+
+static const struct machine_ops __initdata xen_machine_ops = {
+ .restart = xen_restart,
+ .halt = xen_machine_halt,
+ .power_off = xen_machine_halt,
+ .shutdown = xen_machine_halt,
+ .crash_shutdown = xen_crash_shutdown,
+ .emergency_restart = xen_emergency_restart,
+};
+
+
+/* First C function to be called on Xen boot */
+asmlinkage void __init xen_start_kernel(void)
+{
+ pgd_t *pgd;
+
+ if (!xen_start_info)
+ return;
+
+ BUG_ON(memcmp(xen_start_info->magic, "xen-3.0", 7) != 0);
+
+ /* Install Xen paravirt ops */
+ paravirt_ops = xen_paravirt_ops;
+ machine_ops = xen_machine_ops;
+
+#ifdef CONFIG_SMP
+ smp_ops = xen_smp_ops;
+#endif
+
+ xen_setup_features();
+
+ /* Get mfn list */
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
+ phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
+
+ pgd = (pgd_t *)xen_start_info->pt_base;
+
+ init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
+
+ init_mm.pgd = pgd; /* use the Xen pagetables to start */
+
+ /* keep using Xen gdt for now; no urgent need to change it */
+
+ x86_write_percpu(xen_cr3, __pa(pgd));
+
+#ifdef CONFIG_SMP
+ /* Don't do the full vcpu_info placement stuff until we have a
+ possible map. */
+ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+#else
+ /* May as well do it now, since there's no good time to call
+ it later on UP. */
+ xen_setup_vcpu_info_placement();
+#endif
+
+ paravirt_ops.kernel_rpl = 1;
+ if (xen_feature(XENFEAT_supervisor_mode_kernel))
+ paravirt_ops.kernel_rpl = 0;
+
+ /* set the limit of our address space */
+ reserve_top_address(-HYPERVISOR_VIRT_START + 2 * PAGE_SIZE);
+
+ /* set up basic CPUID stuff */
+ cpu_detect(&new_cpu_data);
+ new_cpu_data.hard_math = 1;
+ new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+ /* Poke various useful things into boot_params */
+ LOADER_TYPE = (9 << 4) | 0;
+ INITRD_START = xen_start_info->mod_start ? __pa(xen_start_info->mod_start) : 0;
+ INITRD_SIZE = xen_start_info->mod_len;
+
+ /* Start the world */
+ start_kernel();
+}
diff --git a/arch/i386/xen/events.c b/arch/i386/xen/events.c
new file mode 100644
index 0000000..8904acc
--- /dev/null
+++ b/arch/i386/xen/events.c
@@ -0,0 +1,590 @@
+/*
+ * Xen event channels
+ *
+ * Xen models interrupts with abstract event channels. Because each
+ * domain gets 1024 event channels, but NR_IRQ is not that large, we
+ * must dynamically map irqs<->event channels. The event channels
+ * interface with the rest of the kernel by defining a xen interrupt
+ * chip. When an event is recieved, it is mapped to an irq and sent
+ * through the normal interrupt processing path.
+ *
+ * There are four kinds of events which can be mapped to an event
+ * channel:
+ *
+ * 1. Inter-domain notifications. This includes all the virtual
+ * device events, since they're driven by front-ends in another domain
+ * (typically dom0).
+ * 2. VIRQs, typically used for timers. These are per-cpu events.
+ * 3. IPIs.
+ * 4. Hardware interrupts. Not supported at present.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/sync_bitops.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+
+#include "xen-ops.h"
+
+/*
+ * This lock protects updates to the following mapping and reference-count
+ * arrays. The lock does not need to be acquired to read the mapping tables.
+ */
+static DEFINE_SPINLOCK(irq_mapping_update_lock);
+
+/* IRQ <-> VIRQ mapping. */
+static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+
+/* IRQ <-> IPI mapping */
+static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+
+/* Packed IRQ information: binding type, sub-type index, and event channel. */
+struct packed_irq
+{
+ unsigned short evtchn;
+ unsigned char index;
+ unsigned char type;
+};
+
+static struct packed_irq irq_info[NR_IRQS];
+
+/* Binding types. */
+enum {
+ IRQT_UNBOUND,
+ IRQT_PIRQ,
+ IRQT_VIRQ,
+ IRQT_IPI,
+ IRQT_EVTCHN
+};
+
+/* Convenient shorthand for packed representation of an unbound IRQ. */
+#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
+
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+ [0 ... NR_EVENT_CHANNELS-1] = -1
+};
+static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+/* Xen will never allocate port zero for any purpose. */
+#define VALID_EVTCHN(chn) ((chn) != 0)
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void force_evtchn_callback(void)
+{
+ (void)HYPERVISOR_xen_version(0, NULL);
+}
+EXPORT_SYMBOL_GPL(force_evtchn_callback);
+
+static struct irq_chip xen_dynamic_chip;
+
+/* Constructor for packed IRQ information. */
+static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn)
+{
+ return (struct packed_irq) { evtchn, index, type };
+}
+
+/*
+ * Accessors for packed IRQ information.
+ */
+static inline unsigned int evtchn_from_irq(int irq)
+{
+ return irq_info[irq].evtchn;
+}
+
+static inline unsigned int index_from_irq(int irq)
+{
+ return irq_info[irq].index;
+}
+
+static inline unsigned int type_from_irq(int irq)
+{
+ return irq_info[irq].type;
+}
+
+static inline unsigned long active_evtchns(unsigned int cpu,
+ struct shared_info *sh,
+ unsigned int idx)
+{
+ return (sh->evtchn_pending[idx] &
+ cpu_evtchn_mask[cpu][idx] &
+ ~sh->evtchn_mask[idx]);
+}
+
+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+ int irq = evtchn_to_irq[chn];
+
+ BUG_ON(irq == -1);
+#ifdef CONFIG_SMP
+ irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+#endif
+
+ __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
+ __set_bit(chn, cpu_evtchn_mask[cpu]);
+
+ cpu_evtchn[chn] = cpu;
+}
+
+static void init_evtchn_cpu_bindings(void)
+{
+#ifdef CONFIG_SMP
+ int i;
+ /* By default all event channels notify CPU#0. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_desc[i].affinity = cpumask_of_cpu(0);
+#endif
+
+ memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
+ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+}
+
+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
+{
+ return cpu_evtchn[evtchn];
+}
+
+static inline void clear_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void set_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_pending[0]);
+}
+
+
+/**
+ * notify_remote_via_irq - send event to remote end of event channel via irq
+ * @irq: irq of event channel to send event to
+ *
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently
+ * dropped.
+ */
+void notify_remote_via_irq(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ notify_remote_via_evtchn(evtchn);
+}
+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
+
+static void mask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_mask[0]);
+}
+
+static void unmask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ unsigned int cpu = get_cpu();
+
+ BUG_ON(!irqs_disabled());
+
+ /* Slow path (hypercall) if this is a non-local port. */
+ if (unlikely(cpu != cpu_from_evtchn(port))) {
+ struct evtchn_unmask unmask = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
+ } else {
+ struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+
+ sync_clear_bit(port, &s->evtchn_mask[0]);
+
+ /*
+ * The following is basically the equivalent of
+ * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
+ * the interrupt edge' if the channel is masked.
+ */
+ if (sync_test_bit(port, &s->evtchn_pending[0]) &&
+ !sync_test_and_set_bit(port / BITS_PER_LONG,
+ &vcpu_info->evtchn_pending_sel))
+ vcpu_info->evtchn_upcall_pending = 1;
+ }
+
+ put_cpu();
+}
+
+static int find_unbound_irq(void)
+{
+ int irq;
+
+ /* Only allocate from dynirq range */
+ for (irq = 0; irq < NR_IRQS; irq++)
+ if (irq_bindcount[irq] == 0)
+ break;
+
+ if (irq == NR_IRQS)
+ panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+ return irq;
+}
+
+int bind_evtchn_to_irq(unsigned int evtchn)
+{
+ int irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = evtchn_to_irq[evtchn];
+
+ if (irq == -1) {
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "event");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+{
+ struct evtchn_bind_ipi bind_ipi;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(ipi_to_irq, cpu)[ipi];
+ if (irq == -1) {
+ irq = find_unbound_irq();
+ if (irq < 0)
+ goto out;
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "ipi");
+
+ bind_ipi.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+ &bind_ipi) != 0)
+ BUG();
+ evtchn = bind_ipi.port;
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+
+ per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+ return irq;
+}
+
+
+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+{
+ struct evtchn_bind_virq bind_virq;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(virq_to_irq, cpu)[virq];
+
+ if (irq == -1) {
+ bind_virq.virq = virq;
+ bind_virq.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+ &bind_virq) != 0)
+ BUG();
+ evtchn = bind_virq.port;
+
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "virq");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+static void unbind_from_irq(unsigned int irq)
+{
+ struct evtchn_close close;
+ int evtchn = evtchn_from_irq(irq);
+
+ spin_lock(&irq_mapping_update_lock);
+
+ if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+ close.port = evtchn;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
+ BUG();
+
+ switch (type_from_irq(irq)) {
+ case IRQT_VIRQ:
+ per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
+ [index_from_irq(irq)] = -1;
+ break;
+ default:
+ break;
+ }
+
+ /* Closed ports are implicitly re-bound to VCPU0. */
+ bind_evtchn_to_cpu(evtchn, 0);
+
+ evtchn_to_irq[evtchn] = -1;
+ irq_info[irq] = IRQ_UNBOUND;
+
+ dynamic_irq_init(irq);
+ }
+
+ spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long irqflags,
+ const char *devname, void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_evtchn_to_irq(evtchn);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
+
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long irqflags, const char *devname, void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_virq_to_irq(virq, cpu);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
+
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
+{
+ int irq, retval;
+
+ irq = bind_ipi_to_irq(ipi, cpu);
+ if (irq < 0)
+ return irq;
+
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+ free_irq(irq, dev_id);
+ unbind_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
+{
+ int irq = per_cpu(ipi_to_irq, cpu)[vector];
+ BUG_ON(irq < 0);
+ notify_remote_via_irq(irq);
+}
+
+
+/*
+ * Search the CPUs pending events bitmasks. For each one found, map
+ * the event number to an irq, and feed it into do_IRQ() for
+ * handling.
+ *
+ * Xen uses a two-level bitmap to speed searching. The first level is
+ * a bitset of words which contain pending event bits. The second
+ * level is a bitset of pending events themselves.
+ */
+fastcall void xen_evtchn_do_upcall(struct pt_regs *regs)
+{
+ int cpu = get_cpu();
+ struct shared_info *s = HYPERVISOR_shared_info;
+ struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+ unsigned long pending_words;
+
+ vcpu_info->evtchn_upcall_pending = 0;
+
+ /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
+ pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+ while (pending_words != 0) {
+ unsigned long pending_bits;
+ int word_idx = __ffs(pending_words);
+ pending_words &= ~(1UL << word_idx);
+
+ while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
+ int bit_idx = __ffs(pending_bits);
+ int port = (word_idx * BITS_PER_LONG) + bit_idx;
+ int irq = evtchn_to_irq[port];
+
+ if (irq != -1) {
+ regs->orig_eax = ~irq;
+ do_IRQ(regs);
+ }
+ }
+ }
+
+ put_cpu();
+}
+
+/* Rebind an evtchn so that it gets delivered to a specific cpu */
+static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+{
+ struct evtchn_bind_vcpu bind_vcpu;
+ int evtchn = evtchn_from_irq(irq);
+
+ if (!VALID_EVTCHN(evtchn))
+ return;
+
+ /* Send future instances of this interrupt to other vcpu. */
+ bind_vcpu.port = evtchn;
+ bind_vcpu.vcpu = tcpu;
+
+ /*
+ * If this fails, it usually just indicates that we're dealing with a
+ * virq or IPI channel, which don't actually need to be rebound. Ignore
+ * it, but don't do the xenlinux-level rebind in that case.
+ */
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+ bind_evtchn_to_cpu(evtchn, tcpu);
+}
+
+
+static void set_affinity_irq(unsigned irq, cpumask_t dest)
+{
+ unsigned tcpu = first_cpu(dest);
+ rebind_irq_to_cpu(irq, tcpu);
+}
+
+static void enable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ unmask_evtchn(evtchn);
+}
+
+static void disable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ mask_evtchn(evtchn);
+}
+
+static void ack_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ move_native_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ clear_evtchn(evtchn);
+}
+
+static int retrigger_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+ int ret = 0;
+
+ if (VALID_EVTCHN(evtchn)) {
+ set_evtchn(evtchn);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static struct irq_chip xen_dynamic_chip __read_mostly = {
+ .name = "xen-dyn",
+ .mask = disable_dynirq,
+ .unmask = enable_dynirq,
+ .ack = ack_dynirq,
+ .set_affinity = set_affinity_irq,
+ .retrigger = retrigger_dynirq,
+};
+
+void __init xen_init_IRQ(void)
+{
+ int i;
+
+ init_evtchn_cpu_bindings();
+
+ /* No event channels are 'live' right now. */
+ for (i = 0; i < NR_EVENT_CHANNELS; i++)
+ mask_evtchn(i);
+
+ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_bindcount[i] = 0;
+
+ irq_ctx_init(smp_processor_id());
+}
diff --git a/arch/i386/xen/features.c b/arch/i386/xen/features.c
new file mode 100644
index 0000000..0707714
--- /dev/null
+++ b/arch/i386/xen/features.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * features.c
+ *
+ * Xen feature flags.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/features.h>
+
+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
+EXPORT_SYMBOL_GPL(xen_features);
+
+void xen_setup_features(void)
+{
+ struct xen_feature_info fi;
+ int i, j;
+
+ for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+ fi.submap_idx = i;
+ if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+ break;
+ for (j = 0; j < 32; j++)
+ xen_features[i * 32 + j] = !!(fi.submap & 1<<j);
+ }
+}
diff --git a/arch/i386/xen/manage.c b/arch/i386/xen/manage.c
new file mode 100644
index 0000000..aa7af9e
--- /dev/null
+++ b/arch/i386/xen/manage.c
@@ -0,0 +1,143 @@
+/*
+ * Handle extern requests for shutdown, reboot and sysrq
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+
+#include <xen/xenbus.h>
+
+#define SHUTDOWN_INVALID -1
+#define SHUTDOWN_POWEROFF 0
+#define SHUTDOWN_SUSPEND 2
+/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
+ * report a crash, not be instructed to crash!
+ * HALT is the same as POWEROFF, as far as we're concerned. The tools use
+ * the distinction when we return the reason code to them.
+ */
+#define SHUTDOWN_HALT 4
+
+/* Ignore multiple shutdown requests. */
+static int shutting_down = SHUTDOWN_INVALID;
+
+static void shutdown_handler(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ char *str;
+ struct xenbus_transaction xbt;
+ int err;
+
+ if (shutting_down != SHUTDOWN_INVALID)
+ return;
+
+ again:
+ err = xenbus_transaction_start(&xbt);
+ if (err)
+ return;
+
+ str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
+ /* Ignore read errors and empty reads. */
+ if (XENBUS_IS_ERR_READ(str)) {
+ xenbus_transaction_end(xbt, 1);
+ return;
+ }
+
+ xenbus_write(xbt, "control", "shutdown", "");
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN) {
+ kfree(str);
+ goto again;
+ }
+
+ if (strcmp(str, "poweroff") == 0 ||
+ strcmp(str, "halt") == 0)
+ orderly_poweroff(false);
+ else if (strcmp(str, "reboot") == 0)
+ ctrl_alt_del();
+ else {
+ printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
+ shutting_down = SHUTDOWN_INVALID;
+ }
+
+ kfree(str);
+}
+
+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
+ unsigned int len)
+{
+ char sysrq_key = '\0';
+ struct xenbus_transaction xbt;
+ int err;
+
+ again:
+ err = xenbus_transaction_start(&xbt);
+ if (err)
+ return;
+ if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
+ printk(KERN_ERR "Unable to read sysrq code in "
+ "control/sysrq\n");
+ xenbus_transaction_end(xbt, 1);
+ return;
+ }
+
+ if (sysrq_key != '\0')
+ xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+
+ if (sysrq_key != '\0')
+ handle_sysrq(sysrq_key, NULL);
+}
+
+static struct xenbus_watch shutdown_watch = {
+ .node = "control/shutdown",
+ .callback = shutdown_handler
+};
+
+static struct xenbus_watch sysrq_watch = {
+ .node = "control/sysrq",
+ .callback = sysrq_handler
+};
+
+static int setup_shutdown_watcher(void)
+{
+ int err;
+
+ err = register_xenbus_watch(&shutdown_watch);
+ if (err) {
+ printk(KERN_ERR "Failed to set shutdown watcher\n");
+ return err;
+ }
+
+ err = register_xenbus_watch(&sysrq_watch);
+ if (err) {
+ printk(KERN_ERR "Failed to set sysrq watcher\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int shutdown_event(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ setup_shutdown_watcher();
+ return NOTIFY_DONE;
+}
+
+static int __init setup_shutdown_event(void)
+{
+ static struct notifier_block xenstore_notifier = {
+ .notifier_call = shutdown_event
+ };
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+
+subsys_initcall(setup_shutdown_event);
diff --git a/arch/i386/xen/mmu.c b/arch/i386/xen/mmu.c
new file mode 100644
index 0000000..4ae038a
--- /dev/null
+++ b/arch/i386/xen/mmu.c
@@ -0,0 +1,564 @@
+/*
+ * Xen mmu operations
+ *
+ * This file contains the various mmu fetch and update operations.
+ * The most important job they must perform is the mapping between the
+ * domain's pfn and the overall machine mfns.
+ *
+ * Xen allows guests to directly update the pagetable, in a controlled
+ * fashion. In other words, the guest modifies the same pagetable
+ * that the CPU actually uses, which eliminates the overhead of having
+ * a separate shadow pagetable.
+ *
+ * In order to allow this, it falls on the guest domain to map its
+ * notion of a "physical" pfn - which is just a domain-local linear
+ * address - into a real "machine address" which the CPU's MMU can
+ * use.
+ *
+ * A pgd_t/pmd_t/pte_t will typically contain an mfn, and so can be
+ * inserted directly into the pagetable. When creating a new
+ * pte/pmd/pgd, it converts the passed pfn into an mfn. Conversely,
+ * when reading the content back with __(pgd|pmd|pte)_val, it converts
+ * the mfn back into a pfn.
+ *
+ * The other constraint is that all pages which make up a pagetable
+ * must be mapped read-only in the guest. This prevents uncontrolled
+ * guest updates to the pagetable. Xen strictly enforces this, and
+ * will disallow any pagetable update which will end up mapping a
+ * pagetable page RW, and will disallow using any writable page as a
+ * pagetable.
+ *
+ * Naively, when loading %cr3 with the base of a new pagetable, Xen
+ * would need to validate the whole pagetable before going on.
+ * Naturally, this is quite slow. The solution is to "pin" a
+ * pagetable, which enforces all the constraints on the pagetable even
+ * when it is not actively in use. This menas that Xen can be assured
+ * that it is still valid when you do load it into %cr3, and doesn't
+ * need to revalidate it.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/bug.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/paravirt.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+
+#include "multicalls.h"
+#include "mmu.h"
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address)
+{
+ pte_t *pte = lookup_address(address);
+ unsigned offset = address & PAGE_MASK;
+
+ BUG_ON(pte == NULL);
+
+ return XMADDR((pte_mfn(*pte) << PAGE_SHIFT) + offset);
+}
+
+void make_lowmem_page_readonly(void *vaddr)
+{
+ pte_t *pte, ptev;
+ unsigned long address = (unsigned long)vaddr;
+
+ pte = lookup_address(address);
+ BUG_ON(pte == NULL);
+
+ ptev = pte_wrprotect(*pte);
+
+ if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+ BUG();
+}
+
+void make_lowmem_page_readwrite(void *vaddr)
+{
+ pte_t *pte, ptev;
+ unsigned long address = (unsigned long)vaddr;
+
+ pte = lookup_address(address);
+ BUG_ON(pte == NULL);
+
+ ptev = pte_mkwrite(*pte);
+
+ if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+ BUG();
+}
+
+
+void xen_set_pmd(pmd_t *ptr, pmd_t val)
+{
+ struct multicall_space mcs;
+ struct mmu_update *u;
+
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*u));
+ u = mcs.args;
+ u->ptr = virt_to_machine(ptr).maddr;
+ u->val = pmd_val_ma(val);
+ MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
+}
+
+/*
+ * Associate a virtual page frame with a given physical page frame
+ * and protection flags for that frame.
+ */
+void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ if (pgd_none(*pgd)) {
+ BUG();
+ return;
+ }
+ pud = pud_offset(pgd, vaddr);
+ if (pud_none(*pud)) {
+ BUG();
+ return;
+ }
+ pmd = pmd_offset(pud, vaddr);
+ if (pmd_none(*pmd)) {
+ BUG();
+ return;
+ }
+ pte = pte_offset_kernel(pmd, vaddr);
+ /* <mfn,flags> stored as-is, to permit clearing entries */
+ xen_set_pte(pte, mfn_pte(mfn, flags));
+
+ /*
+ * It's enough to flush this one mapping.
+ * (PGE mappings get flushed as well)
+ */
+ __flush_tlb_one(vaddr);
+}
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ if (mm == current->mm || mm == &init_mm) {
+ if (xen_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+ struct multicall_space mcs;
+ mcs = xen_mc_entry(0);
+
+ MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+ return;
+ } else
+ if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
+ return;
+ }
+ xen_set_pte(ptep, pteval);
+}
+
+#ifdef CONFIG_X86_PAE
+void xen_set_pud(pud_t *ptr, pud_t val)
+{
+ struct multicall_space mcs;
+ struct mmu_update *u;
+
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*u));
+ u = mcs.args;
+ u->ptr = virt_to_machine(ptr).maddr;
+ u->val = pud_val_ma(val);
+ MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
+}
+
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+ ptep->pte_high = pte.pte_high;
+ smp_wmb();
+ ptep->pte_low = pte.pte_low;
+}
+
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+ set_64bit((u64 *)ptep, pte_val_ma(pte));
+}
+
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ ptep->pte_low = 0;
+ smp_wmb(); /* make sure low gets written first */
+ ptep->pte_high = 0;
+}
+
+void xen_pmd_clear(pmd_t *pmdp)
+{
+ xen_set_pmd(pmdp, __pmd(0));
+}
+
+unsigned long long xen_pte_val(pte_t pte)
+{
+ unsigned long long ret = 0;
+
+ if (pte.pte_low) {
+ ret = ((unsigned long long)pte.pte_high << 32) | pte.pte_low;
+ ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+ }
+
+ return ret;
+}
+
+unsigned long long xen_pmd_val(pmd_t pmd)
+{
+ unsigned long long ret = pmd.pmd;
+ if (ret)
+ ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+ return ret;
+}
+
+unsigned long long xen_pgd_val(pgd_t pgd)
+{
+ unsigned long long ret = pgd.pgd;
+ if (ret)
+ ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+ return ret;
+}
+
+pte_t xen_make_pte(unsigned long long pte)
+{
+ if (pte & 1)
+ pte = phys_to_machine(XPADDR(pte)).maddr;
+
+ return (pte_t){ pte, pte >> 32 };
+}
+
+pmd_t xen_make_pmd(unsigned long long pmd)
+{
+ if (pmd & 1)
+ pmd = phys_to_machine(XPADDR(pmd)).maddr;
+
+ return (pmd_t){ pmd };
+}
+
+pgd_t xen_make_pgd(unsigned long long pgd)
+{
+ if (pgd & _PAGE_PRESENT)
+ pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+ return (pgd_t){ pgd };
+}
+#else /* !PAE */
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+ *ptep = pte;
+}
+
+unsigned long xen_pte_val(pte_t pte)
+{
+ unsigned long ret = pte.pte_low;
+
+ if (ret & _PAGE_PRESENT)
+ ret = machine_to_phys(XMADDR(ret)).paddr;
+
+ return ret;
+}
+
+unsigned long xen_pgd_val(pgd_t pgd)
+{
+ unsigned long ret = pgd.pgd;
+ if (ret)
+ ret = machine_to_phys(XMADDR(ret)).paddr | 1;
+ return ret;
+}
+
+pte_t xen_make_pte(unsigned long pte)
+{
+ if (pte & _PAGE_PRESENT)
+ pte = phys_to_machine(XPADDR(pte)).maddr;
+
+ return (pte_t){ pte };
+}
+
+pgd_t xen_make_pgd(unsigned long pgd)
+{
+ if (pgd & _PAGE_PRESENT)
+ pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+ return (pgd_t){ pgd };
+}
+#endif /* CONFIG_X86_PAE */
+
+
+
+/*
+ (Yet another) pagetable walker. This one is intended for pinning a
+ pagetable. This means that it walks a pagetable and calls the
+ callback function on each page it finds making up the page table,
+ at every level. It walks the entire pagetable, but it only bothers
+ pinning pte pages which are below pte_limit. In the normal case
+ this will be TASK_SIZE, but at boot we need to pin up to
+ FIXADDR_TOP. But the important bit is that we don't pin beyond
+ there, because then we start getting into Xen's ptes.
+*/
+static int pgd_walk(pgd_t *pgd_base, int (*func)(struct page *, unsigned),
+ unsigned long limit)
+{
+ pgd_t *pgd = pgd_base;
+ int flush = 0;
+ unsigned long addr = 0;
+ unsigned long pgd_next;
+
+ BUG_ON(limit > FIXADDR_TOP);
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 0;
+
+ for (; addr != FIXADDR_TOP; pgd++, addr = pgd_next) {
+ pud_t *pud;
+ unsigned long pud_limit, pud_next;
+
+ pgd_next = pud_limit = pgd_addr_end(addr, FIXADDR_TOP);
+
+ if (!pgd_val(*pgd))
+ continue;
+
+ pud = pud_offset(pgd, 0);
+
+ if (PTRS_PER_PUD > 1) /* not folded */
+ flush |= (*func)(virt_to_page(pud), 0);
+
+ for (; addr != pud_limit; pud++, addr = pud_next) {
+ pmd_t *pmd;
+ unsigned long pmd_limit;
+
+ pud_next = pud_addr_end(addr, pud_limit);
+
+ if (pud_next < limit)
+ pmd_limit = pud_next;
+ else
+ pmd_limit = limit;
+
+ if (pud_none(*pud))
+ continue;
+
+ pmd = pmd_offset(pud, 0);
+
+ if (PTRS_PER_PMD > 1) /* not folded */
+ flush |= (*func)(virt_to_page(pmd), 0);
+
+ for (; addr != pmd_limit; pmd++) {
+ addr += (PAGE_SIZE * PTRS_PER_PTE);
+ if ((pmd_limit-1) < (addr-1)) {
+ addr = pmd_limit;
+ break;
+ }
+
+ if (pmd_none(*pmd))
+ continue;
+
+ flush |= (*func)(pmd_page(*pmd), 0);
+ }
+ }
+ }
+
+ flush |= (*func)(virt_to_page(pgd_base), UVMF_TLB_FLUSH);
+
+ return flush;
+}
+
+static int pin_page(struct page *page, unsigned flags)
+{
+ unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags);
+ int flush;
+
+ if (pgfl)
+ flush = 0; /* already pinned */
+ else if (PageHighMem(page))
+ /* kmaps need flushing if we found an unpinned
+ highpage */
+ flush = 1;
+ else {
+ void *pt = lowmem_page_address(page);
+ unsigned long pfn = page_to_pfn(page);
+ struct multicall_space mcs = __xen_mc_entry(0);
+
+ flush = 0;
+
+ MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+ pfn_pte(pfn, PAGE_KERNEL_RO),
+ flags);
+ }
+
+ return flush;
+}
+
+/* This is called just after a mm has been created, but it has not
+ been used yet. We need to make sure that its pagetable is all
+ read-only, and can be pinned. */
+void xen_pgd_pin(pgd_t *pgd)
+{
+ struct multicall_space mcs;
+ struct mmuext_op *op;
+
+ xen_mc_batch();
+
+ if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
+ /* re-enable interrupts for kmap_flush_unused */
+ xen_mc_issue(0);
+ kmap_flush_unused();
+ xen_mc_batch();
+ }
+
+ mcs = __xen_mc_entry(sizeof(*op));
+ op = mcs.args;
+
+#ifdef CONFIG_X86_PAE
+ op->cmd = MMUEXT_PIN_L3_TABLE;
+#else
+ op->cmd = MMUEXT_PIN_L2_TABLE;
+#endif
+ op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(0);
+}
+
+/* The init_mm pagetable is really pinned as soon as its created, but
+ that's before we have page structures to store the bits. So do all
+ the book-keeping now. */
+static __init int mark_pinned(struct page *page, unsigned flags)
+{
+ SetPagePinned(page);
+ return 0;
+}
+
+void __init xen_mark_init_mm_pinned(void)
+{
+ pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+}
+
+static int unpin_page(struct page *page, unsigned flags)
+{
+ unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags);
+
+ if (pgfl && !PageHighMem(page)) {
+ void *pt = lowmem_page_address(page);
+ unsigned long pfn = page_to_pfn(page);
+ struct multicall_space mcs = __xen_mc_entry(0);
+
+ MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+ pfn_pte(pfn, PAGE_KERNEL),
+ flags);
+ }
+
+ return 0; /* never need to flush on unpin */
+}
+
+/* Release a pagetables pages back as normal RW */
+static void xen_pgd_unpin(pgd_t *pgd)
+{
+ struct mmuext_op *op;
+ struct multicall_space mcs;
+
+ xen_mc_batch();
+
+ mcs = __xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_UNPIN_TABLE;
+ op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ pgd_walk(pgd, unpin_page, TASK_SIZE);
+
+ xen_mc_issue(0);
+}
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ spin_lock(&next->page_table_lock);
+ xen_pgd_pin(next->pgd);
+ spin_unlock(&next->page_table_lock);
+}
+
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+ spin_lock(&mm->page_table_lock);
+ xen_pgd_pin(mm->pgd);
+ spin_unlock(&mm->page_table_lock);
+}
+
+
+#ifdef CONFIG_SMP
+/* Another cpu may still have their %cr3 pointing at the pagetable, so
+ we need to repoint it somewhere else before we can unpin it. */
+static void drop_other_mm_ref(void *info)
+{
+ struct mm_struct *mm = info;
+
+ if (__get_cpu_var(cpu_tlbstate).active_mm == mm)
+ leave_mm(smp_processor_id());
+}
+
+static void drop_mm_ref(struct mm_struct *mm)
+{
+ if (current->active_mm == mm) {
+ if (current->mm == mm)
+ load_cr3(swapper_pg_dir);
+ else
+ leave_mm(smp_processor_id());
+ }
+
+ if (!cpus_empty(mm->cpu_vm_mask))
+ xen_smp_call_function_mask(mm->cpu_vm_mask, drop_other_mm_ref,
+ mm, 1);
+}
+#else
+static void drop_mm_ref(struct mm_struct *mm)
+{
+ if (current->active_mm == mm)
+ load_cr3(swapper_pg_dir);
+}
+#endif
+
+/*
+ * While a process runs, Xen pins its pagetables, which means that the
+ * hypervisor forces it to be read-only, and it controls all updates
+ * to it. This means that all pagetable updates have to go via the
+ * hypervisor, which is moderately expensive.
+ *
+ * Since we're pulling the pagetable down, we switch to use init_mm,
+ * unpin old process pagetable and mark it all read-write, which
+ * allows further operations on it to be simple memory accesses.
+ *
+ * The only subtle point is that another CPU may be still using the
+ * pagetable because of lazy tlb flushing. This means we need need to
+ * switch all CPUs off this pagetable before we can unpin it.
+ */
+void xen_exit_mmap(struct mm_struct *mm)
+{
+ get_cpu(); /* make sure we don't move around */
+ drop_mm_ref(mm);
+ put_cpu();
+
+ spin_lock(&mm->page_table_lock);
+ xen_pgd_unpin(mm->pgd);
+ spin_unlock(&mm->page_table_lock);
+}
diff --git a/arch/i386/xen/mmu.h b/arch/i386/xen/mmu.h
new file mode 100644
index 0000000..c9ff27f
--- /dev/null
+++ b/arch/i386/xen/mmu.h
@@ -0,0 +1,60 @@
+#ifndef _XEN_MMU_H
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ *
+ * Note that Xen is using the fact that the pagetable base is always
+ * page-aligned, and putting the 12 MSB of the address into the 12 LSB
+ * of cr3.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
+
+void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
+
+void xen_set_pte(pte_t *ptep, pte_t pteval);
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
+void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+void xen_exit_mmap(struct mm_struct *mm);
+
+void xen_pgd_pin(pgd_t *pgd);
+//void xen_pgd_unpin(pgd_t *pgd);
+
+#ifdef CONFIG_X86_PAE
+unsigned long long xen_pte_val(pte_t);
+unsigned long long xen_pmd_val(pmd_t);
+unsigned long long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long long);
+pmd_t xen_make_pmd(unsigned long long);
+pgd_t xen_make_pgd(unsigned long long);
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
+void xen_set_pud(pud_t *ptr, pud_t val);
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+void xen_pmd_clear(pmd_t *pmdp);
+
+
+#else
+unsigned long xen_pte_val(pte_t);
+unsigned long xen_pmd_val(pmd_t);
+unsigned long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long);
+pmd_t xen_make_pmd(unsigned long);
+pgd_t xen_make_pgd(unsigned long);
+#endif
+
+#endif /* _XEN_MMU_H */
diff --git a/arch/i386/xen/multicalls.c b/arch/i386/xen/multicalls.c
new file mode 100644
index 0000000..c837e8e
--- /dev/null
+++ b/arch/i386/xen/multicalls.c
@@ -0,0 +1,90 @@
+/*
+ * Xen hypercall batching.
+ *
+ * Xen allows multiple hypercalls to be issued at once, using the
+ * multicall interface. This allows the cost of trapping into the
+ * hypervisor to be amortized over several calls.
+ *
+ * This file implements a simple interface for multicalls. There's a
+ * per-cpu buffer of outstanding multicalls. When you want to queue a
+ * multicall for issuing, you can allocate a multicall slot for the
+ * call and its arguments, along with storage for space which is
+ * pointed to by the arguments (for passing pointers to structures,
+ * etc). When the multicall is actually issued, all the space for the
+ * commands and allocated memory is freed for reuse.
+ *
+ * Multicalls are flushed whenever any of the buffers get full, or
+ * when explicitly requested. There's no way to get per-multicall
+ * return results back. It will BUG if any of the multicalls fail.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+
+#include <asm/xen/hypercall.h>
+
+#include "multicalls.h"
+
+#define MC_BATCH 32
+#define MC_ARGS (MC_BATCH * 16 / sizeof(u64))
+
+struct mc_buffer {
+ struct multicall_entry entries[MC_BATCH];
+ u64 args[MC_ARGS];
+ unsigned mcidx, argidx;
+};
+
+static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
+DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+void xen_mc_flush(void)
+{
+ struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+ int ret = 0;
+ unsigned long flags;
+
+ BUG_ON(preemptible());
+
+ /* Disable interrupts in case someone comes in and queues
+ something in the middle */
+ local_irq_save(flags);
+
+ if (b->mcidx) {
+ int i;
+
+ if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
+ BUG();
+ for (i = 0; i < b->mcidx; i++)
+ if (b->entries[i].result < 0)
+ ret++;
+ b->mcidx = 0;
+ b->argidx = 0;
+ } else
+ BUG_ON(b->argidx != 0);
+
+ local_irq_restore(flags);
+
+ BUG_ON(ret);
+}
+
+struct multicall_space __xen_mc_entry(size_t args)
+{
+ struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+ struct multicall_space ret;
+ unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64);
+
+ BUG_ON(preemptible());
+ BUG_ON(argspace > MC_ARGS);
+
+ if (b->mcidx == MC_BATCH ||
+ (b->argidx + argspace) > MC_ARGS)
+ xen_mc_flush();
+
+ ret.mc = &b->entries[b->mcidx];
+ b->mcidx++;
+ ret.args = &b->args[b->argidx];
+ b->argidx += argspace;
+
+ return ret;
+}
diff --git a/arch/i386/xen/multicalls.h b/arch/i386/xen/multicalls.h
new file mode 100644
index 0000000..e6f7530
--- /dev/null
+++ b/arch/i386/xen/multicalls.h
@@ -0,0 +1,45 @@
+#ifndef _XEN_MULTICALLS_H
+#define _XEN_MULTICALLS_H
+
+#include "xen-ops.h"
+
+/* Multicalls */
+struct multicall_space
+{
+ struct multicall_entry *mc;
+ void *args;
+};
+
+/* Allocate room for a multicall and its args */
+struct multicall_space __xen_mc_entry(size_t args);
+
+DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+/* Call to start a batch of multiple __xen_mc_entry()s. Must be
+ paired with xen_mc_issue() */
+static inline void xen_mc_batch(void)
+{
+ /* need to disable interrupts until this entry is complete */
+ local_irq_save(__get_cpu_var(xen_mc_irq_flags));
+}
+
+static inline struct multicall_space xen_mc_entry(size_t args)
+{
+ xen_mc_batch();
+ return __xen_mc_entry(args);
+}
+
+/* Flush all pending multicalls */
+void xen_mc_flush(void);
+
+/* Issue a multicall if we're not in a lazy mode */
+static inline void xen_mc_issue(unsigned mode)
+{
+ if ((xen_get_lazy_mode() & mode) == 0)
+ xen_mc_flush();
+
+ /* restore flags saved in xen_mc_batch */
+ local_irq_restore(x86_read_percpu(xen_mc_irq_flags));
+}
+
+#endif /* _XEN_MULTICALLS_H */
diff --git a/arch/i386/xen/setup.c b/arch/i386/xen/setup.c
new file mode 100644
index 0000000..2fe6eac
--- /dev/null
+++ b/arch/i386/xen/setup.c
@@ -0,0 +1,96 @@
+/*
+ * Machine specific setup for xen
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+
+#include <asm/elf.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/interface/physdev.h>
+#include <xen/features.h>
+
+#include "xen-ops.h"
+
+/* These are code, but not functions. Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+unsigned long *phys_to_machine_mapping;
+EXPORT_SYMBOL(phys_to_machine_mapping);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ **/
+
+char * __init xen_memory_setup(void)
+{
+ unsigned long max_pfn = xen_start_info->nr_pages;
+
+ e820.nr_map = 0;
+ add_memory_region(0, PFN_PHYS(max_pfn), E820_RAM);
+
+ return "Xen";
+}
+
+static void xen_idle(void)
+{
+ local_irq_disable();
+
+ if (need_resched())
+ local_irq_enable();
+ else {
+ current_thread_info()->status &= ~TS_POLLING;
+ smp_mb__after_clear_bit();
+ safe_halt();
+ current_thread_info()->status |= TS_POLLING;
+ }
+}
+
+void __init xen_arch_setup(void)
+{
+ struct physdev_set_iopl set_iopl;
+ int rc;
+
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+
+ HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
+ __KERNEL_CS, (unsigned long)xen_failsafe_callback);
+
+ set_iopl.iopl = 1;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+ if (rc != 0)
+ printk(KERN_INFO "physdev_op failed %d\n", rc);
+
+#ifdef CONFIG_ACPI
+ if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
+ printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
+ disable_acpi();
+ }
+#endif
+
+ memcpy(boot_command_line, xen_start_info->cmd_line,
+ MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
+ COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
+
+ pm_idle = xen_idle;
+
+#ifdef CONFIG_SMP
+ /* fill cpus_possible with all available cpus */
+ xen_fill_possible_map();
+#endif
+
+ paravirt_disable_iospace();
+}
diff --git a/arch/i386/xen/smp.c b/arch/i386/xen/smp.c
new file mode 100644
index 0000000..557b8e2
--- /dev/null
+++ b/arch/i386/xen/smp.c
@@ -0,0 +1,404 @@
+/*
+ * Xen SMP support
+ *
+ * This file implements the Xen versions of smp_ops. SMP under Xen is
+ * very straightforward. Bringing a CPU up is simply a matter of
+ * loading its initial context and setting it running.
+ *
+ * IPIs are handled through the Xen event mechanism.
+ *
+ * Because virtual CPUs can be scheduled onto any real CPU, there's no
+ * useful topology information for the kernel to make use of. As a
+ * result, all CPUs are treated as if they're single-core and
+ * single-threaded.
+ *
+ * This does not handle HOTPLUG_CPU yet.
+ */
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/smp.h>
+
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/cpu.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/interface.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/page.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+
+static cpumask_t cpu_initialized_map;
+static DEFINE_PER_CPU(int, resched_irq);
+static DEFINE_PER_CPU(int, callfunc_irq);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static DEFINE_SPINLOCK(call_lock);
+
+struct call_data_struct {
+ void (*func) (void *info);
+ void *info;
+ atomic_t started;
+ atomic_t finished;
+ int wait;
+};
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
+
+static struct call_data_struct *call_data;
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+ int cpu = smp_processor_id();
+
+ cpu_init();
+
+ preempt_disable();
+ per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+ xen_setup_cpu_clockevents();
+
+ /* We can take interrupts now: we're officially "up". */
+ local_irq_enable();
+
+ wmb(); /* make sure everything is out */
+ cpu_idle();
+}
+
+static int xen_smp_intr_init(unsigned int cpu)
+{
+ int rc;
+ const char *resched_name, *callfunc_name;
+
+ per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
+
+ resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+ rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
+ cpu,
+ xen_reschedule_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ resched_name,
+ NULL);
+ if (rc < 0)
+ goto fail;
+ per_cpu(resched_irq, cpu) = rc;
+
+ callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+ rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
+ cpu,
+ xen_call_function_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ callfunc_name,
+ NULL);
+ if (rc < 0)
+ goto fail;
+ per_cpu(callfunc_irq, cpu) = rc;
+
+ return 0;
+
+ fail:
+ if (per_cpu(resched_irq, cpu) >= 0)
+ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+ if (per_cpu(callfunc_irq, cpu) >= 0)
+ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+ return rc;
+}
+
+void __init xen_fill_possible_map(void)
+{
+ int i, rc;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
+ if (rc >= 0)
+ cpu_set(i, cpu_possible_map);
+ }
+}
+
+void __init xen_smp_prepare_boot_cpu(void)
+{
+ int cpu;
+
+ BUG_ON(smp_processor_id() != 0);
+ native_smp_prepare_boot_cpu();
+
+ /* We've switched to the "real" per-cpu gdt, so make sure the
+ old memory can be recycled */
+ make_lowmem_page_readwrite(&per_cpu__gdt_page);
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ }
+
+ xen_setup_vcpu_info_placement();
+}
+
+void __init xen_smp_prepare_cpus(unsigned int max_cpus)
+{
+ unsigned cpu;
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ }
+
+ smp_store_cpu_info(0);
+ set_cpu_sibling_map(0);
+
+ if (xen_smp_intr_init(0))
+ BUG();
+
+ cpu_initialized_map = cpumask_of_cpu(0);
+
+ /* Restrict the possible_map according to max_cpus. */
+ while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
+ for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
+ continue;
+ cpu_clear(cpu, cpu_possible_map);
+ }
+
+ for_each_possible_cpu (cpu) {
+ struct task_struct *idle;
+
+ if (cpu == 0)
+ continue;
+
+ idle = fork_idle(cpu);
+ if (IS_ERR(idle))
+ panic("failed fork for CPU %d", cpu);
+
+ cpu_set(cpu, cpu_present_map);
+ }
+
+ //init_xenbus_allowed_cpumask();
+}
+
+static __cpuinit int
+cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
+{
+ struct vcpu_guest_context *ctxt;
+ struct gdt_page *gdt = &per_cpu(gdt_page, cpu);
+
+ if (cpu_test_and_set(cpu, cpu_initialized_map))
+ return 0;
+
+ ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ if (ctxt == NULL)
+ return -ENOMEM;
+
+ ctxt->flags = VGCF_IN_KERNEL;
+ ctxt->user_regs.ds = __USER_DS;
+ ctxt->user_regs.es = __USER_DS;
+ ctxt->user_regs.fs = __KERNEL_PERCPU;
+ ctxt->user_regs.gs = 0;
+ ctxt->user_regs.ss = __KERNEL_DS;
+ ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+ ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+
+ memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+ xen_copy_trap_info(ctxt->trap_ctxt);
+
+ ctxt->ldt_ents = 0;
+
+ BUG_ON((unsigned long)gdt->gdt & ~PAGE_MASK);
+ make_lowmem_page_readonly(gdt->gdt);
+
+ ctxt->gdt_frames[0] = virt_to_mfn(gdt->gdt);
+ ctxt->gdt_ents = ARRAY_SIZE(gdt->gdt);
+
+ ctxt->user_regs.cs = __KERNEL_CS;
+ ctxt->user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
+
+ ctxt->kernel_ss = __KERNEL_DS;
+ ctxt->kernel_sp = idle->thread.esp0;
+
+ ctxt->event_callback_cs = __KERNEL_CS;
+ ctxt->event_callback_eip = (unsigned long)xen_hypervisor_callback;
+ ctxt->failsafe_callback_cs = __KERNEL_CS;
+ ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback;
+
+ per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
+ ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
+ BUG();
+
+ kfree(ctxt);
+ return 0;
+}
+
+int __cpuinit xen_cpu_up(unsigned int cpu)
+{
+ struct task_struct *idle = idle_task(cpu);
+ int rc;
+
+#if 0
+ rc = cpu_up_check(cpu);
+ if (rc)
+ return rc;
+#endif
+
+ init_gdt(cpu);
+ per_cpu(current_task, cpu) = idle;
+ irq_ctx_init(cpu);
+ xen_setup_timer(cpu);
+
+ /* make sure interrupts start blocked */
+ per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;
+
+ rc = cpu_initialize_context(cpu, idle);
+ if (rc)
+ return rc;
+
+ if (num_online_cpus() == 1)
+ alternatives_smp_switch(1);
+
+ rc = xen_smp_intr_init(cpu);
+ if (rc)
+ return rc;
+
+ smp_store_cpu_info(cpu);
+ set_cpu_sibling_map(cpu);
+ /* This must be done before setting cpu_online_map */
+ wmb();
+
+ cpu_set(cpu, cpu_online_map);
+
+ rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
+ BUG_ON(rc);
+
+ return 0;
+}
+
+void xen_smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+static void stop_self(void *v)
+{
+ int cpu = smp_processor_id();
+
+ /* make sure we're not pinning something down */
+ load_cr3(swapper_pg_dir);
+ /* should set up a minimal gdt */
+
+ HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
+ BUG();
+}
+
+void xen_smp_send_stop(void)
+{
+ smp_call_function(stop_self, NULL, 0, 0);
+}
+
+void xen_smp_send_reschedule(int cpu)
+{
+ xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
+}
+
+
+static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
+{
+ unsigned cpu;
+
+ cpus_and(mask, mask, cpu_online_map);
+
+ for_each_cpu_mask(cpu, mask)
+ xen_send_IPI_one(cpu, vector);
+}
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
+{
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+
+ /*
+ * Notify initiating CPU that I've grabbed the data and am
+ * about to execute the function
+ */
+ mb();
+ atomic_inc(&call_data->started);
+ /*
+ * At this point the info structure may be out of scope unless wait==1
+ */
+ irq_enter();
+ (*func)(info);
+ irq_exit();
+
+ if (wait) {
+ mb(); /* commit everything before setting finished */
+ atomic_inc(&call_data->finished);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+ void *info, int wait)
+{
+ struct call_data_struct data;
+ int cpus;
+
+ /* Holding any lock stops cpus from going down. */
+ spin_lock(&call_lock);
+
+ cpu_clear(smp_processor_id(), mask);
+
+ cpus = cpus_weight(mask);
+ if (!cpus) {
+ spin_unlock(&call_lock);
+ return 0;
+ }
+
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ call_data = &data;
+ mb(); /* write everything before IPI */
+
+ /* Send a message to other CPUs and wait for them to respond */
+ xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
+
+ /* Make sure other vcpus get a chance to run.
+ XXX too severe? Maybe we should check the other CPU's states? */
+ HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+
+ /* Wait for response */
+ while (atomic_read(&data.started) != cpus ||
+ (wait && atomic_read(&data.finished) != cpus))
+ cpu_relax();
+
+ spin_unlock(&call_lock);
+
+ return 0;
+}
diff --git a/arch/i386/xen/time.c b/arch/i386/xen/time.c
new file mode 100644
index 0000000..51fdabf
--- /dev/null
+++ b/arch/i386/xen/time.c
@@ -0,0 +1,590 @@
+/*
+ * Xen time implementation.
+ *
+ * This is implemented in terms of a clocksource driver which uses
+ * the hypervisor clock as a nanosecond timebase, and a clockevent
+ * driver which uses the hypervisor's timer mechanism.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include "xen-ops.h"
+
+#define XEN_SHIFT 22
+
+/* Xen may fire a timer up to this many ns early */
+#define TIMER_SLOP 100000
+#define NS_PER_TICK (1000000000LL / HZ)
+
+static cycle_t xen_clocksource_read(void);
+
+/* These are perodically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+ u64 tsc_timestamp; /* TSC at last update of time vals. */
+ u64 system_timestamp; /* Time, in nanosecs, since boot. */
+ u32 tsc_to_nsec_mul;
+ int tsc_shift;
+ u32 version;
+};
+
+static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+
+/* snapshots of runstate info */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+
+/* unused ns of stolen and blocked time */
+static DEFINE_PER_CPU(u64, residual_stolen);
+static DEFINE_PER_CPU(u64, residual_blocked);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+ u64 ret;
+
+ if (BITS_PER_LONG < 64) {
+ u32 *p32 = (u32 *)p;
+ u32 h, l;
+
+ /*
+ * Read high then low, and then make sure high is
+ * still the same; this will only loop if low wraps
+ * and carries into high.
+ * XXX some clean way to make this endian-proof?
+ */
+ do {
+ h = p32[1];
+ barrier();
+ l = p32[0];
+ barrier();
+ } while (p32[1] != h);
+
+ ret = (((u64)h) << 32) | l;
+ } else
+ ret = *p;
+
+ return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+static void get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+ u64 state_time;
+ struct vcpu_runstate_info *state;
+
+ BUG_ON(preemptible());
+
+ state = &__get_cpu_var(runstate);
+
+ /*
+ * The runstate info is always updated by the hypervisor on
+ * the current CPU, so there's no need to use anything
+ * stronger than a compiler barrier when fetching it.
+ */
+ do {
+ state_time = get64(&state->state_entry_time);
+ barrier();
+ *res = *state;
+ barrier();
+ } while (get64(&state->state_entry_time) != state_time);
+}
+
+static void setup_runstate_info(int cpu)
+{
+ struct vcpu_register_runstate_memory_area area;
+
+ area.addr.v = &per_cpu(runstate, cpu);
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+ cpu, &area))
+ BUG();
+}
+
+static void do_stolen_accounting(void)
+{
+ struct vcpu_runstate_info state;
+ struct vcpu_runstate_info *snap;
+ s64 blocked, runnable, offline, stolen;
+ cputime_t ticks;
+
+ get_runstate_snapshot(&state);
+
+ WARN_ON(state.state != RUNSTATE_running);
+
+ snap = &__get_cpu_var(runstate_snapshot);
+
+ /* work out how much time the VCPU has not been runn*ing* */
+ blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
+ runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
+ offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
+
+ *snap = state;
+
+ /* Add the appropriate number of ticks of stolen time,
+ including any left-overs from last time. Passing NULL to
+ account_steal_time accounts the time as stolen. */
+ stolen = runnable + offline + __get_cpu_var(residual_stolen);
+
+ if (stolen < 0)
+ stolen = 0;
+
+ ticks = 0;
+ while (stolen >= NS_PER_TICK) {
+ ticks++;
+ stolen -= NS_PER_TICK;
+ }
+ __get_cpu_var(residual_stolen) = stolen;
+ account_steal_time(NULL, ticks);
+
+ /* Add the appropriate number of ticks of blocked time,
+ including any left-overs from last time. Passing idle to
+ account_steal_time accounts the time as idle/wait. */
+ blocked += __get_cpu_var(residual_blocked);
+
+ if (blocked < 0)
+ blocked = 0;
+
+ ticks = 0;
+ while (blocked >= NS_PER_TICK) {
+ ticks++;
+ blocked -= NS_PER_TICK;
+ }
+ __get_cpu_var(residual_blocked) = blocked;
+ account_steal_time(idle_task(smp_processor_id()), ticks);
+}
+
+/*
+ * Xen sched_clock implementation. Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+unsigned long long xen_sched_clock(void)
+{
+ struct vcpu_runstate_info state;
+ cycle_t now;
+ u64 ret;
+ s64 offset;
+
+ /*
+ * Ideally sched_clock should be called on a per-cpu basis
+ * anyway, so preempt should already be disabled, but that's
+ * not current practice at the moment.
+ */
+ preempt_disable();
+
+ now = xen_clocksource_read();
+
+ get_runstate_snapshot(&state);
+
+ WARN_ON(state.state != RUNSTATE_running);
+
+ offset = now - state.state_entry_time;
+ if (offset < 0)
+ offset = 0;
+
+ ret = state.time[RUNSTATE_blocked] +
+ state.time[RUNSTATE_running] +
+ offset;
+
+ preempt_enable();
+
+ return ret;
+}
+
+
+/* Get the CPU speed from Xen */
+unsigned long xen_cpu_khz(void)
+{
+ u64 cpu_khz = 1000000ULL << 32;
+ const struct vcpu_time_info *info =
+ &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+ do_div(cpu_khz, info->tsc_to_system_mul);
+ if (info->tsc_shift < 0)
+ cpu_khz <<= -info->tsc_shift;
+ else
+ cpu_khz >>= info->tsc_shift;
+
+ return cpu_khz;
+}
+
+/*
+ * Reads a consistent set of time-base values from Xen, into a shadow data
+ * area.
+ */
+static unsigned get_time_values_from_xen(void)
+{
+ struct vcpu_time_info *src;
+ struct shadow_time_info *dst;
+
+ /* src is shared memory with the hypervisor, so we need to
+ make sure we get a consistent snapshot, even in the face of
+ being preempted. */
+ src = &__get_cpu_var(xen_vcpu)->time;
+ dst = &__get_cpu_var(shadow_time);
+
+ do {
+ dst->version = src->version;
+ rmb(); /* fetch version before data */
+ dst->tsc_timestamp = src->tsc_timestamp;
+ dst->system_timestamp = src->system_time;
+ dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
+ dst->tsc_shift = src->tsc_shift;
+ rmb(); /* test version after fetching data */
+ } while ((src->version & 1) | (dst->version ^ src->version));
+
+ return dst->version;
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+ u64 product;
+#ifdef __i386__
+ u32 tmp1, tmp2;
+#endif
+
+ if (shift < 0)
+ delta >>= -shift;
+ else
+ delta <<= shift;
+
+#ifdef __i386__
+ __asm__ (
+ "mul %5 ; "
+ "mov %4,%%eax ; "
+ "mov %%edx,%4 ; "
+ "mul %5 ; "
+ "xor %5,%5 ; "
+ "add %4,%%eax ; "
+ "adc %5,%%edx ; "
+ : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+ : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif __x86_64__
+ __asm__ (
+ "mul %%rdx ; shrd $32,%%rdx,%%rax"
+ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+ return product;
+}
+
+static u64 get_nsec_offset(struct shadow_time_info *shadow)
+{
+ u64 now, delta;
+ now = native_read_tsc();
+ delta = now - shadow->tsc_timestamp;
+ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+}
+
+static cycle_t xen_clocksource_read(void)
+{
+ struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+ cycle_t ret;
+ unsigned version;
+
+ do {
+ version = get_time_values_from_xen();
+ barrier();
+ ret = shadow->system_timestamp + get_nsec_offset(shadow);
+ barrier();
+ } while (version != __get_cpu_var(xen_vcpu)->time.version);
+
+ put_cpu_var(shadow_time);
+
+ return ret;
+}
+
+static void xen_read_wallclock(struct timespec *ts)
+{
+ const struct shared_info *s = HYPERVISOR_shared_info;
+ u32 version;
+ u64 delta;
+ struct timespec now;
+
+ /* get wallclock at system boot */
+ do {
+ version = s->wc_version;
+ rmb(); /* fetch version before time */
+ now.tv_sec = s->wc_sec;
+ now.tv_nsec = s->wc_nsec;
+ rmb(); /* fetch time before checking version */
+ } while ((s->wc_version & 1) | (version ^ s->wc_version));
+
+ delta = xen_clocksource_read(); /* time since system boot */
+ delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+ now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+ now.tv_sec = delta;
+
+ set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
+
+unsigned long xen_get_wallclock(void)
+{
+ struct timespec ts;
+
+ xen_read_wallclock(&ts);
+
+ return ts.tv_sec;
+}
+
+int xen_set_wallclock(unsigned long now)
+{
+ /* do nothing for domU */
+ return -1;
+}
+
+static struct clocksource xen_clocksource __read_mostly = {
+ .name = "xen",
+ .rating = 400,
+ .read = xen_clocksource_read,
+ .mask = ~0,
+ .mult = 1<<XEN_SHIFT, /* time directly in nanoseconds */
+ .shift = XEN_SHIFT,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ Xen clockevent implementation
+
+ Xen has two clockevent implementations:
+
+ The old timer_op one works with all released versions of Xen prior
+ to version 3.0.4. This version of the hypervisor provides a
+ single-shot timer with nanosecond resolution. However, sharing the
+ same event channel is a 100Hz tick which is delivered while the
+ vcpu is running. We don't care about or use this tick, but it will
+ cause the core time code to think the timer fired too soon, and
+ will end up resetting it each time. It could be filtered, but
+ doing so has complications when the ktime clocksource is not yet
+ the xen clocksource (ie, at boot time).
+
+ The new vcpu_op-based timer interface allows the tick timer period
+ to be changed or turned off. The tick timer is not useful as a
+ periodic timer because events are only delivered to running vcpus.
+ The one-shot timer can report when a timeout is in the past, so
+ set_next_event is capable of returning -ETIME when appropriate.
+ This interface is used when available.
+*/
+
+
+/*
+ Get a hypervisor absolute time. In theory we could maintain an
+ offset between the kernel's time and the hypervisor's time, and
+ apply that to a kernel's absolute timeout. Unfortunately the
+ hypervisor and kernel times can drift even if the kernel is using
+ the Xen clocksource, because ntp can warp the kernel's clocksource.
+*/
+static s64 get_abs_timeout(unsigned long delta)
+{
+ return xen_clocksource_read() + delta;
+}
+
+static void xen_timerop_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* unsupported */
+ WARN_ON(1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ HYPERVISOR_set_timer_op(0); /* cancel timeout */
+ break;
+ }
+}
+
+static int xen_timerop_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
+ BUG();
+
+ /* We may have missed the deadline, but there's no real way of
+ knowing for sure. If the event was in the past, then we'll
+ get an immediate interrupt. */
+
+ return 0;
+}
+
+static const struct clock_event_device xen_timerop_clockevent = {
+ .name = "xen",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+
+ .max_delta_ns = 0xffffffff,
+ .min_delta_ns = TIMER_SLOP,
+
+ .mult = 1,
+ .shift = 0,
+ .rating = 500,
+
+ .set_mode = xen_timerop_set_mode,
+ .set_next_event = xen_timerop_set_next_event,
+};
+
+
+
+static void xen_vcpuop_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ int cpu = smp_processor_id();
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ WARN_ON(1); /* unsupported */
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+ BUG();
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
+ HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+ BUG();
+ break;
+ }
+}
+
+static int xen_vcpuop_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ int cpu = smp_processor_id();
+ struct vcpu_set_singleshot_timer single;
+ int ret;
+
+ WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ single.timeout_abs_ns = get_abs_timeout(delta);
+ single.flags = VCPU_SSHOTTMR_future;
+
+ ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
+
+ BUG_ON(ret != 0 && ret != -ETIME);
+
+ return ret;
+}
+
+static const struct clock_event_device xen_vcpuop_clockevent = {
+ .name = "xen",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+
+ .max_delta_ns = 0xffffffff,
+ .min_delta_ns = TIMER_SLOP,
+
+ .mult = 1,
+ .shift = 0,
+ .rating = 500,
+
+ .set_mode = xen_vcpuop_set_mode,
+ .set_next_event = xen_vcpuop_set_next_event,
+};
+
+static const struct clock_event_device *xen_clockevent =
+ &xen_timerop_clockevent;
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+
+static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+ irqreturn_t ret;
+
+ ret = IRQ_NONE;
+ if (evt->event_handler) {
+ evt->event_handler(evt);
+ ret = IRQ_HANDLED;
+ }
+
+ do_stolen_accounting();
+
+ return ret;
+}
+
+void xen_setup_timer(int cpu)
+{
+ const char *name;
+ struct clock_event_device *evt;
+ int irq;
+
+ printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
+
+ name = kasprintf(GFP_KERNEL, "timer%d", cpu);
+ if (!name)
+ name = "<timer kasprintf failed>";
+
+ irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ name, NULL);
+
+ evt = &per_cpu(xen_clock_events, cpu);
+ memcpy(evt, xen_clockevent, sizeof(*evt));
+
+ evt->cpumask = cpumask_of_cpu(cpu);
+ evt->irq = irq;
+
+ setup_runstate_info(cpu);
+}
+
+void xen_setup_cpu_clockevents(void)
+{
+ BUG_ON(preemptible());
+
+ clockevents_register_device(&__get_cpu_var(xen_clock_events));
+}
+
+__init void xen_time_init(void)
+{
+ int cpu = smp_processor_id();
+
+ get_time_values_from_xen();
+
+ clocksource_register(&xen_clocksource);
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
+ /* Successfully turned off 100Hz tick, so we have the
+ vcpuop-based timer interface */
+ printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
+ xen_clockevent = &xen_vcpuop_clockevent;
+ }
+
+ /* Set initial system time with full resolution */
+ xen_read_wallclock(&xtime);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ tsc_disable = 0;
+
+ xen_setup_timer(cpu);
+ xen_setup_cpu_clockevents();
+}
diff --git a/arch/i386/xen/xen-asm.S b/arch/i386/xen/xen-asm.S
new file mode 100644
index 0000000..1a43b60
--- /dev/null
+++ b/arch/i386/xen/xen-asm.S
@@ -0,0 +1,291 @@
+/*
+ Asm versions of Xen pv-ops, suitable for either direct use or inlining.
+ The inline versions are the same as the direct-use versions, with the
+ pre- and post-amble chopped off.
+
+ This code is encoded for size rather than absolute efficiency,
+ with a view to being able to inline as much as possible.
+
+ We only bother with direct forms (ie, vcpu in pda) of the operations
+ here; the indirect forms are better handled in C, since they're
+ generally too large to inline anyway.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/percpu.h>
+#include <asm/processor-flags.h>
+#include <asm/segment.h>
+
+#include <xen/interface/xen.h>
+
+#define RELOC(x, v) .globl x##_reloc; x##_reloc=v
+#define ENDPATCH(x) .globl x##_end; x##_end=.
+
+/* Pseudo-flag used for virtual NMI, which we don't implement yet */
+#define XEN_EFLAGS_NMI 0x80000000
+
+/*
+ Enable events. This clears the event mask and tests the pending
+ event status with one and operation. If there are pending
+ events, then enter the hypervisor to get them handled.
+ */
+ENTRY(xen_irq_enable_direct)
+ /* Clear mask and test pending */
+ andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+ /* Preempt here doesn't matter because that will deal with
+ any pending interrupts. The pending check may end up being
+ run on the wrong CPU, but that doesn't hurt. */
+ jz 1f
+2: call check_events
+1:
+ENDPATCH(xen_irq_enable_direct)
+ ret
+ ENDPROC(xen_irq_enable_direct)
+ RELOC(xen_irq_enable_direct, 2b+1)
+
+
+/*
+ Disabling events is simply a matter of making the event mask
+ non-zero.
+ */
+ENTRY(xen_irq_disable_direct)
+ movb $1, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ENDPATCH(xen_irq_disable_direct)
+ ret
+ ENDPROC(xen_irq_disable_direct)
+ RELOC(xen_irq_disable_direct, 0)
+
+/*
+ (xen_)save_fl is used to get the current interrupt enable status.
+ Callers expect the status to be in X86_EFLAGS_IF, and other bits
+ may be set in the return value. We take advantage of this by
+ making sure that X86_EFLAGS_IF has the right value (and other bits
+ in that byte are 0), but other bits in the return value are
+ undefined. We need to toggle the state of the bit, because
+ Xen and x86 use opposite senses (mask vs enable).
+ */
+ENTRY(xen_save_fl_direct)
+ testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ setz %ah
+ addb %ah,%ah
+ENDPATCH(xen_save_fl_direct)
+ ret
+ ENDPROC(xen_save_fl_direct)
+ RELOC(xen_save_fl_direct, 0)
+
+
+/*
+ In principle the caller should be passing us a value return
+ from xen_save_fl_direct, but for robustness sake we test only
+ the X86_EFLAGS_IF flag rather than the whole byte. After
+ setting the interrupt mask state, it checks for unmasked
+ pending events and enters the hypervisor to get them delivered
+ if so.
+ */
+ENTRY(xen_restore_fl_direct)
+ testb $X86_EFLAGS_IF>>8, %ah
+ setz PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ /* Preempt here doesn't matter because that will deal with
+ any pending interrupts. The pending check may end up being
+ run on the wrong CPU, but that doesn't hurt. */
+
+ /* check for unmasked and pending */
+ cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+ jz 1f
+2: call check_events
+1:
+ENDPATCH(xen_restore_fl_direct)
+ ret
+ ENDPROC(xen_restore_fl_direct)
+ RELOC(xen_restore_fl_direct, 2b+1)
+
+/*
+ This is run where a normal iret would be run, with the same stack setup:
+ 8: eflags
+ 4: cs
+ esp-> 0: eip
+
+ This attempts to make sure that any pending events are dealt
+ with on return to usermode, but there is a small window in
+ which an event can happen just before entering usermode. If
+ the nested interrupt ends up setting one of the TIF_WORK_MASK
+ pending work flags, they will not be tested again before
+ returning to usermode. This means that a process can end up
+ with pending work, which will be unprocessed until the process
+ enters and leaves the kernel again, which could be an
+ unbounded amount of time. This means that a pending signal or
+ reschedule event could be indefinitely delayed.
+
+ The fix is to notice a nested interrupt in the critical
+ window, and if one occurs, then fold the nested interrupt into
+ the current interrupt stack frame, and re-process it
+ iteratively rather than recursively. This means that it will
+ exit via the normal path, and all pending work will be dealt
+ with appropriately.
+
+ Because the nested interrupt handler needs to deal with the
+ current stack state in whatever form its in, we keep things
+ simple by only using a single register which is pushed/popped
+ on the stack.
+
+ Non-direct iret could be done in the same way, but it would
+ require an annoying amount of code duplication. We'll assume
+ that direct mode will be the common case once the hypervisor
+ support becomes commonplace.
+ */
+ENTRY(xen_iret_direct)
+ /* test eflags for special cases */
+ testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
+ jnz hyper_iret
+
+ push %eax
+ ESP_OFFSET=4 # bytes pushed onto stack
+
+ /* Store vcpu_info pointer for easy access. Do it this
+ way to avoid having to reload %fs */
+#ifdef CONFIG_SMP
+ GET_THREAD_INFO(%eax)
+ movl TI_cpu(%eax),%eax
+ movl __per_cpu_offset(,%eax,4),%eax
+ lea per_cpu__xen_vcpu_info(%eax),%eax
+#else
+ movl $per_cpu__xen_vcpu_info, %eax
+#endif
+
+ /* check IF state we're restoring */
+ testb $X86_EFLAGS_IF>>8, 8+1+ESP_OFFSET(%esp)
+
+ /* Maybe enable events. Once this happens we could get a
+ recursive event, so the critical region starts immediately
+ afterwards. However, if that happens we don't end up
+ resuming the code, so we don't have to be worried about
+ being preempted to another CPU. */
+ setz XEN_vcpu_info_mask(%eax)
+xen_iret_start_crit:
+
+ /* check for unmasked and pending */
+ cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+
+ /* If there's something pending, mask events again so we
+ can jump back into xen_hypervisor_callback */
+ sete XEN_vcpu_info_mask(%eax)
+
+ popl %eax
+
+ /* From this point on the registers are restored and the stack
+ updated, so we don't need to worry about it if we're preempted */
+iret_restore_end:
+
+ /* Jump to hypervisor_callback after fixing up the stack.
+ Events are masked, so jumping out of the critical
+ region is OK. */
+ je xen_hypervisor_callback
+
+ iret
+xen_iret_end_crit:
+
+hyper_iret:
+ /* put this out of line since its very rarely used */
+ jmp hypercall_page + __HYPERVISOR_iret * 32
+
+ .globl xen_iret_start_crit, xen_iret_end_crit
+
+/*
+ This is called by xen_hypervisor_callback in entry.S when it sees
+ that the EIP at the time of interrupt was between xen_iret_start_crit
+ and xen_iret_end_crit. We're passed the EIP in %eax so we can do
+ a more refined determination of what to do.
+
+ The stack format at this point is:
+ ----------------
+ ss : (ss/esp may be present if we came from usermode)
+ esp :
+ eflags } outer exception info
+ cs }
+ eip }
+ ---------------- <- edi (copy dest)
+ eax : outer eax if it hasn't been restored
+ ----------------
+ eflags } nested exception info
+ cs } (no ss/esp because we're nested
+ eip } from the same ring)
+ orig_eax }<- esi (copy src)
+ - - - - - - - -
+ fs }
+ es }
+ ds } SAVE_ALL state
+ eax }
+ : :
+ ebx }
+ ----------------
+ return addr <- esp
+ ----------------
+
+ In order to deliver the nested exception properly, we need to shift
+ everything from the return addr up to the error code so it
+ sits just under the outer exception info. This means that when we
+ handle the exception, we do it in the context of the outer exception
+ rather than starting a new one.
+
+ The only caveat is that if the outer eax hasn't been
+ restored yet (ie, it's still on stack), we need to insert
+ its value into the SAVE_ALL state before going on, since
+ it's usermode state which we eventually need to restore.
+ */
+ENTRY(xen_iret_crit_fixup)
+ /* offsets +4 for return address */
+
+ /*
+ Paranoia: Make sure we're really coming from userspace.
+ One could imagine a case where userspace jumps into the
+ critical range address, but just before the CPU delivers a GP,
+ it decides to deliver an interrupt instead. Unlikely?
+ Definitely. Easy to avoid? Yes. The Intel documents
+ explicitly say that the reported EIP for a bad jump is the
+ jump instruction itself, not the destination, but some virtual
+ environments get this wrong.
+ */
+ movl PT_CS+4(%esp), %ecx
+ andl $SEGMENT_RPL_MASK, %ecx
+ cmpl $USER_RPL, %ecx
+ je 2f
+
+ lea PT_ORIG_EAX+4(%esp), %esi
+ lea PT_EFLAGS+4(%esp), %edi
+
+ /* If eip is before iret_restore_end then stack
+ hasn't been restored yet. */
+ cmp $iret_restore_end, %eax
+ jae 1f
+
+ movl 0+4(%edi),%eax /* copy EAX */
+ movl %eax, PT_EAX+4(%esp)
+
+ lea ESP_OFFSET(%edi),%edi /* move dest up over saved regs */
+
+ /* set up the copy */
+1: std
+ mov $(PT_EIP+4) / 4, %ecx /* copy ret+saved regs up to orig_eax */
+ rep movsl
+ cld
+
+ lea 4(%edi),%esp /* point esp to new frame */
+2: ret
+
+
+/*
+ Force an event check by making a hypercall,
+ but preserve regs before making the call.
+ */
+check_events:
+ push %eax
+ push %ecx
+ push %edx
+ call force_evtchn_callback
+ pop %edx
+ pop %ecx
+ pop %eax
+ ret
diff --git a/arch/i386/xen/xen-head.S b/arch/i386/xen/xen-head.S
new file mode 100644
index 0000000..2998d55
--- /dev/null
+++ b/arch/i386/xen/xen-head.S
@@ -0,0 +1,36 @@
+/* Xen-specific pieces of head.S, intended to be included in the right
+ place in head.S */
+
+#ifdef CONFIG_XEN
+
+#include <linux/elfnote.h>
+#include <asm/boot.h>
+#include <xen/interface/elfnote.h>
+
+ENTRY(startup_xen)
+ movl %esi,xen_start_info
+ cld
+ movl $(init_thread_union+THREAD_SIZE),%esp
+ jmp xen_start_kernel
+
+.pushsection ".bss.page_aligned"
+ .align PAGE_SIZE_asm
+ENTRY(hypercall_page)
+ .skip 0x1000
+.popsection
+
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6")
+ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0")
+ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long __PAGE_OFFSET)
+ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_xen)
+ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page)
+ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "!writable_page_tables|pae_pgdir_above_4gb")
+#ifdef CONFIG_X86_PAE
+ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes")
+#else
+ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "no")
+#endif
+ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
+
+#endif /*CONFIG_XEN */
diff --git a/arch/i386/xen/xen-ops.h b/arch/i386/xen/xen-ops.h
new file mode 100644
index 0000000..b9aaea4
--- /dev/null
+++ b/arch/i386/xen/xen-ops.h
@@ -0,0 +1,71 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <linux/init.h>
+
+/* These are code, but not functions. Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+void xen_copy_trap_info(struct trap_info *traps);
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DECLARE_PER_CPU(unsigned long, xen_cr3);
+
+extern struct start_info *xen_start_info;
+extern struct shared_info *HYPERVISOR_shared_info;
+
+char * __init xen_memory_setup(void);
+void __init xen_arch_setup(void);
+void __init xen_init_IRQ(void);
+
+void xen_setup_timer(int cpu);
+void xen_setup_cpu_clockevents(void);
+unsigned long xen_cpu_khz(void);
+void __init xen_time_init(void);
+unsigned long xen_get_wallclock(void);
+int xen_set_wallclock(unsigned long time);
+unsigned long long xen_sched_clock(void);
+
+void xen_mark_init_mm_pinned(void);
+
+DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+static inline unsigned xen_get_lazy_mode(void)
+{
+ return x86_read_percpu(xen_lazy_mode);
+}
+
+void __init xen_fill_possible_map(void);
+
+void __init xen_setup_vcpu_info_placement(void);
+void xen_smp_prepare_boot_cpu(void);
+void xen_smp_prepare_cpus(unsigned int max_cpus);
+int xen_cpu_up(unsigned int cpu);
+void xen_smp_cpus_done(unsigned int max_cpus);
+
+void xen_smp_send_stop(void);
+void xen_smp_send_reschedule(int cpu);
+int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+ int wait);
+int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int nonatomic, int wait);
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+ void *info, int wait);
+
+
+/* Declare an asm function, along with symbols needed to make it
+ inlineable */
+#define DECL_ASM(ret, name, ...) \
+ ret name(__VA_ARGS__); \
+ extern char name##_end[]; \
+ extern char name##_reloc[] \
+
+DECL_ASM(void, xen_irq_enable_direct, void);
+DECL_ASM(void, xen_irq_disable_direct, void);
+DECL_ASM(unsigned long, xen_save_fl_direct, void);
+DECL_ASM(void, xen_restore_fl_direct, unsigned long);
+
+void xen_iret_direct(void);
+#endif /* XEN_OPS_H */
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index faf5ef3..94b4a02 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -156,11 +156,14 @@
#endif /* CONFIG_PPC_OF */
/* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
+int pcibios_add_platform_entries(struct pci_dev *pdev)
{
#ifdef CONFIG_PPC_OF
- device_create_file(&pdev->dev, &dev_attr_devspec);
+ return device_create_file(&pdev->dev, &dev_attr_devspec);
+#else
+ return 0;
#endif /* CONFIG_PPC_OF */
+
}
char __init *pcibios_setup(char *str)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index bc43bba..6018178 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -350,11 +350,13 @@
{
DBG(" -> setup_system()\n");
- /* Apply CPUs-specific fixups to kernel text (nop out sections
- * not relevant to this CPU)
+ /* Apply the CPUs-specific and firmware specific fixups to kernel
+ * text (nop out sections not relevant to this CPU or this firmware)
*/
do_feature_fixups(cur_cpu_spec->cpu_features,
&__start___ftr_fixup, &__stop___ftr_fixup);
+ do_feature_fixups(powerpc_firmware_features,
+ &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
/*
* Unflatten the device-tree passed by prom_init or kexec
@@ -392,12 +394,6 @@
if (ppc_md.init_early)
ppc_md.init_early();
- /* Apply firmware specific fixups to kernel text (nop out
- * sections not relevant to this firmware)
- */
- do_feature_fixups(powerpc_firmware_features,
- &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
-
/*
* We can discover serial ports now since the above did setup the
* hash table management for us, thus ioremap works. We do that early
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index b42cbf1..bd85b5f 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -773,6 +773,13 @@
return sys_truncate(path, (high << 32) | low);
}
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+ ((loff_t)lenhi << 32) | lenlo);
+}
+
asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high,
unsigned long low)
{
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 73df711..603d83a 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -21,6 +21,9 @@
bool
default y
+config ARCH_NO_VIRT_TO_BUS
+ def_bool y
+
source "init/Kconfig"
menu "General machine setup"
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index b84b6af..df6ee71 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -62,6 +62,9 @@
bool
default y
+config ARCH_NO_VIRT_TO_BUS
+ def_bool y
+
choice
prompt "Kernel page size"
default SPARC64_PAGE_SIZE_8KB
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index ba01533..fa1f04d 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -1013,6 +1013,19 @@
dp->hs_state = DS_HS_START;
}
+static void ds_reset(struct ds_info *dp)
+{
+ int i;
+
+ dp->hs_state = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+ struct ds_cap_state *cp = &ds_states[i];
+
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+}
+
static void ds_event(void *arg, int event)
{
struct ds_info *dp = arg;
@@ -1028,6 +1041,12 @@
return;
}
+ if (event == LDC_EVENT_RESET) {
+ ds_reset(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
if (event != LDC_EVENT_DATA_READY) {
printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
spin_unlock_irqrestore(&ds_lock, flags);
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index de5310f..302ba5e 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -137,7 +137,7 @@
sizeof(struct mdesc_hdr) +
mdesc_size);
- base = kmalloc(handle_size + 15, GFP_KERNEL);
+ base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
if (base) {
struct mdesc_handle *hp;
unsigned long addr;
@@ -214,18 +214,83 @@
}
EXPORT_SYMBOL(mdesc_release);
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
+
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
+{
+ u64 node;
+
+ mutex_lock(&mdesc_mutex);
+ client->next = client_list;
+ client_list = client;
+
+ mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+ client->add(cur_mdesc, node);
+
+ mutex_unlock(&mdesc_mutex);
+}
+
+/* Run 'func' on nodes which are in A but not in B. */
+static void invoke_on_missing(const char *name,
+ struct mdesc_handle *a,
+ struct mdesc_handle *b,
+ void (*func)(struct mdesc_handle *, u64))
+{
+ u64 node;
+
+ mdesc_for_each_node_by_name(a, node, name) {
+ const u64 *id = mdesc_get_property(a, node, "id", NULL);
+ int found = 0;
+ u64 fnode;
+
+ mdesc_for_each_node_by_name(b, fnode, name) {
+ const u64 *fid = mdesc_get_property(b, fnode,
+ "id", NULL);
+
+ if (*id == *fid) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ func(a, node);
+ }
+}
+
+static void notify_one(struct mdesc_notifier_client *p,
+ struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
+{
+ invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+ invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
+
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
+{
+ struct mdesc_notifier_client *p = client_list;
+
+ while (p) {
+ notify_one(p, old_hp, new_hp);
+ p = p->next;
+ }
+}
+
void mdesc_update(void)
{
unsigned long len, real_len, status;
struct mdesc_handle *hp, *orig_hp;
unsigned long flags;
+ mutex_lock(&mdesc_mutex);
+
(void) sun4v_mach_desc(0UL, 0UL, &len);
hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
if (!hp) {
printk(KERN_ERR "MD: mdesc alloc fails\n");
- return;
+ goto out;
}
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +299,25 @@
status);
atomic_dec(&hp->refcnt);
mdesc_free(hp);
- return;
+ goto out;
}
spin_lock_irqsave(&mdesc_lock, flags);
orig_hp = cur_mdesc;
cur_mdesc = hp;
+ spin_unlock_irqrestore(&mdesc_lock, flags);
+ mdesc_notify_clients(orig_hp, hp);
+
+ spin_lock_irqsave(&mdesc_lock, flags);
if (atomic_dec_and_test(&orig_hp->refcnt))
mdesc_free(orig_hp);
else
list_add(&orig_hp->list, &mdesc_zombie_list);
spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+ mutex_unlock(&mdesc_mutex);
}
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 49569b4..8d3cc4f 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -201,10 +201,11 @@
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
struct device *parent)
{
- const char *type, *compat;
+ const char *type, *compat, *bus_id_name;
struct device_node *dp;
struct vio_dev *vdev;
int err, tlen, clen;
+ const u64 *id;
type = mdesc_get_property(hp, mp, "device-type", &tlen);
if (!type) {
@@ -220,6 +221,16 @@
return NULL;
}
+ bus_id_name = type;
+ if (!strcmp(type, "domain-services-port"))
+ bus_id_name = "ds";
+
+ if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+ printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+ bus_id_name);
+ return NULL;
+ }
+
compat = mdesc_get_property(hp, mp, "device-type", &clen);
if (!compat) {
clen = 0;
@@ -249,7 +260,14 @@
vio_fill_channel_info(hp, mp, vdev);
- snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
+ id = mdesc_get_property(hp, mp, "id", NULL);
+ if (!id)
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+ bus_id_name);
+ else
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+ bus_id_name, *id);
+
vdev->dev.parent = parent;
vdev->dev.bus = &vio_bus_type;
vdev->dev.release = vio_dev_release;
@@ -269,6 +287,8 @@
}
vdev->dp = dp;
+ printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
+
err = device_register(&vdev->dev);
if (err) {
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,45 +303,45 @@
return vdev;
}
-static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
+static void vio_add(struct mdesc_handle *hp, u64 node)
{
- u64 a;
+ (void) vio_create_one(hp, node, &root_vdev->dev);
+}
- mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
- struct vio_dev *vdev;
- u64 target;
+static int vio_md_node_match(struct device *dev, void *arg)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
- target = mdesc_arc_target(hp, a);
- vdev = vio_create_one(hp, target, &parent->dev);
- if (vdev)
- walk_tree(hp, target, vdev);
+ if (vdev->mp == (u64) arg)
+ return 1;
+
+ return 0;
+}
+
+static void vio_remove(struct mdesc_handle *hp, u64 node)
+{
+ struct device *dev;
+
+ dev = device_find_child(&root_vdev->dev, (void *) node,
+ vio_md_node_match);
+ if (dev) {
+ printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
+
+ device_unregister(dev);
}
}
-static void create_devices(struct mdesc_handle *hp, u64 root)
-{
- u64 mp;
+static struct mdesc_notifier_client vio_device_notifier = {
+ .add = vio_add,
+ .remove = vio_remove,
+ .node_name = "virtual-device-port",
+};
- root_vdev = vio_create_one(hp, root, NULL);
- if (!root_vdev) {
- printk(KERN_ERR "VIO: Coult not create root device.\n");
- return;
- }
-
- walk_tree(hp, root, root_vdev);
-
- /* Domain services is odd as it doesn't sit underneath the
- * channel-devices node, so we plug it in manually.
- */
- mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
- if (mp != MDESC_NODE_NULL) {
- struct vio_dev *parent = vio_create_one(hp, mp,
- &root_vdev->dev);
-
- if (parent)
- walk_tree(hp, mp, parent);
- }
-}
+static struct mdesc_notifier_client vio_ds_notifier = {
+ .add = vio_add,
+ .remove = vio_remove,
+ .node_name = "domain-services-port",
+};
const char *channel_devices_node = "channel-devices";
const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
@@ -381,11 +401,19 @@
cdev_cfg_handle = *cfg_handle;
- create_devices(hp, root);
+ root_vdev = vio_create_one(hp, root, NULL);
+ err = -ENODEV;
+ if (!root_vdev) {
+ printk(KERN_ERR "VIO: Coult not create root device.\n");
+ goto out_release;
+ }
+
+ mdesc_register_notifier(&vio_device_notifier);
+ mdesc_register_notifier(&vio_ds_notifier);
mdesc_release(hp);
- return 0;
+ return err;
out_release:
mdesc_release(hp);
diff --git a/arch/sparc64/kernel/viohs.c b/arch/sparc64/kernel/viohs.c
index 15613ad..09126fc 100644
--- a/arch/sparc64/kernel/viohs.c
+++ b/arch/sparc64/kernel/viohs.c
@@ -78,6 +78,24 @@
return 0;
}
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr;
+ u64 ident;
+
+ BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+ ident = dr->ident;
+
+ BUG_ON(!vio->desc_buf);
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+
+ memset(dr, 0, sizeof(*dr));
+ dr->ident = ident;
+}
+
void vio_link_state_change(struct vio_driver_state *vio, int event)
{
if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@
break;
}
start_handshake(vio);
+ } else if (event == LDC_EVENT_RESET) {
+ vio->hs_state = VIO_HS_INVALID;
+
+ if (vio->dr_state & VIO_DR_STATE_RXREG)
+ flush_rx_dring(vio);
+
+ vio->dr_state = 0x00;
+ memset(&vio->ver, 0, sizeof(vio->ver));
+
+ ldc_disconnect(vio->lp);
}
}
EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@
if (vio->dr_state & VIO_DR_STATE_RXREG)
goto send_nack;
+ BUG_ON(vio->desc_buf);
+
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
if (!vio->desc_buf)
goto send_nack;
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 782dea8..3f66e970 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -719,4 +719,5 @@
.quad compat_sys_signalfd
.quad compat_sys_timerfd
.quad sys_eventfd
+ .quad sys32_fallocate
ia32_syscall_end:
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 99a78a3..bee96d6 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -879,3 +879,11 @@
return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
len, advice);
}
+
+asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
+ unsigned offset_hi, unsigned len_lo,
+ unsigned len_hi)
+{
+ return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
+ ((u64)len_hi << 32) | len_lo);
+}
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 296d2b0..fd9aff3 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -6,6 +6,7 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/fcntl.h>
+#include <xen/hvc-console.h>
/* Simple VGA output */
@@ -242,6 +243,10 @@
simnow_init(buf + 6);
early_console = &simnow_console;
keep_early = 1;
+#ifdef CONFIG_HVC_XEN
+ } else if (!strncmp(buf, "xen", 3)) {
+ early_console = &xenboot_console;
+#endif
}
if (keep_early)
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index aa1d159..f3fb817 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -174,7 +174,7 @@
if (events != atomic_read(&mce_logged) && trigger[0]) {
/* Small race window, but should be harmless. */
atomic_set(&mce_logged, events);
- call_usermodehelper(trigger, trigger_argv, NULL, -1);
+ call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
}
}
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index fa6775e..e83cc67 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -102,16 +102,25 @@
u32 *desc;
unsigned long base;
- down(&child->mm->context.sem);
- desc = child->mm->context.ldt + (seg & ~7);
- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+ seg &= ~7UL;
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
+ down(&child->mm->context.sem);
+ if (unlikely((seg >> 3) >= child->mm->context.size))
+ addr = -1L; /* bogus selector, access would fault */
+ else {
+ desc = child->mm->context.ldt + seg;
+ base = ((desc[0] >> 16) |
+ ((desc[1] & 0xff) << 16) |
+ (desc[1] & 0xff000000));
+
+ /* 16-bit code segment? */
+ if (!((desc[1] >> 22) & 1))
+ addr &= 0xffff;
+ addr += base;
+ }
up(&child->mm->context.sem);
}
+
return addr;
}
diff --git a/drivers/Makefile b/drivers/Makefile
index 503d825..6d9d7fa 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,8 @@
obj-$(CONFIG_PNP) += pnp/
obj-$(CONFIG_ARM_AMBA) += amba/
+obj-$(CONFIG_XEN) += xen/
+
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y += char/
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 88a6fc7..58f1338 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -40,6 +40,7 @@
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -59,7 +60,6 @@
#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -419,26 +419,6 @@
return 0;
}
-static int acpi_thermal_call_usermode(char *path)
-{
- char *argv[2] = { NULL, NULL };
- char *envp[3] = { NULL, NULL, NULL };
-
-
- if (!path)
- return -EINVAL;
-
- argv[0] = path;
-
- /* minimal command environment */
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- call_usermodehelper(argv[0], argv, envp, 0);
-
- return 0;
-}
-
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
if (!tz || !tz->trips.critical.flags.valid)
@@ -456,7 +436,7 @@
acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
- acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+ orderly_poweroff(true);
return 0;
}
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index bb4ae628..bed9f58 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -172,7 +172,7 @@
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
- depends on PCI && !64BIT
+ depends on PCI && !64BIT && VIRT_TO_BUS
help
The NICStAR chipset family is used in a large number of ATM NICs for
25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 77637e7..41b2204 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1738,7 +1738,8 @@
printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
"magic - expected 0x%x, got 0x%x\n",dev->number,
ENI155_MAGIC,(unsigned) readl(&eprom->magic));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
}
eni_dev->phy = base+PHY_BASE;
@@ -1765,17 +1766,27 @@
printk(")\n");
printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
- if (error) return error;
+ if (error)
+ goto unmap;
for (i = 0; i < ESI_LEN; i++)
printk("%s%02X",i ? "-" : "",dev->esi[i]);
printk(")\n");
printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
- return suni_init(dev);
+
+ error = suni_init(dev);
+ if (error)
+ goto unmap;
+out:
+ return error;
+unmap:
+ iounmap(base);
+ goto out;
}
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38b688f..737cea4 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1710,7 +1710,7 @@
/* This bit is documented as "RESERVED" */
if (isr & ISR_INIT_ERR) {
printk (KERN_ERR "Error initializing the FS... \n");
- return 1;
+ goto unmap;
}
if (isr & ISR_INIT) {
fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@
if (!to) {
printk (KERN_ERR "timeout initializing the FS... \n");
- return 1;
+ goto unmap;
}
/* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@
if (!dev->atm_vccs) {
printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@
if (!dev->tx_inuse) {
printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
/* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@
if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
/* XXX undo all previous stuff... */
- return 1;
+ goto unmap;
}
fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
@@ -1890,6 +1890,9 @@
func_exit ();
return 0;
+unmap:
+ iounmap(dev->base);
+ return 1;
}
static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@
for (i=0;i < FS_NR_RX_QUEUES;i++)
free_queue (dev, &dev->rx_rq[i]);
+ iounmap(dev->base);
fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
nxtdev = dev->next;
kfree (dev);
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 8f995ce..f8b1700 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -65,7 +65,7 @@
static unsigned int vpibits = 1;
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
/*
@@ -3404,7 +3404,7 @@
conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */
SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */
SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
SAR_CFG_NO_IDLE | /* Do not send idle cells */
#endif
0;
@@ -3541,7 +3541,7 @@
printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
card->name, linkrate, card->link_pcr);
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
card->utopia_pcr = card->link_pcr;
#else
card->utopia_pcr = (160000000 / 8 / 54);
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 0e2c1ae..55fd1b4 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -552,8 +552,8 @@
writel(val, sram_addr(lanai, offset));
}
-static int __init sram_test_word(
- const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+ int offset, u32 pattern)
{
u32 readback;
sram_write(lanai, pattern, offset);
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 480947f..842e26c 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -134,7 +134,7 @@
/* Send read instruction */
val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
- for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+ for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
{
NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
(val | rdsrtab[i]) );
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 8f65b88..a4a3119 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -427,4 +427,13 @@
help
Include support for the Xilinx SystemACE CompactFlash interface
+config XEN_BLKDEV_FRONTEND
+ tristate "Xen virtual block device support"
+ depends on XEN
+ default y
+ help
+ This driver implements the front-end of the Xen virtual
+ block device driver. It communicates with a back-end driver
+ in another domain which drives the actual block device.
+
endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9ee08ab..3e31532 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -29,3 +29,4 @@
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 0f5e3ca..2288b55 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -45,8 +45,6 @@
struct vdc_port {
struct vio_driver_state vio;
- struct vdc *vp;
-
struct gendisk *disk;
struct vdc_completion *cmp;
@@ -72,8 +70,6 @@
struct vio_disk_geom geom;
struct vio_disk_vtoc label;
-
- struct list_head list;
};
static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +77,6 @@
return container_of(vio, struct vdc_port, vio);
}
-struct vdc {
- /* Protects prot_list. */
- spinlock_t lock;
-
- struct vio_dev *dev;
-
- struct list_head port_list;
-};
-
/* Ordered from largest major to lowest */
static struct vio_version vdc_versions[] = {
{ .major = 1, .minor = 0 },
@@ -747,21 +734,23 @@
.handshake_complete = vdc_handshake_complete,
};
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
static int __devinit vdc_port_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
struct mdesc_handle *hp;
struct vdc_port *port;
- unsigned long flags;
- struct vdc *vp;
const u64 *port_id;
int err;
- vp = dev_get_drvdata(vdev->dev.parent);
- if (!vp) {
- printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
- return -ENODEV;
- }
+ print_version();
hp = mdesc_grab();
@@ -783,7 +772,6 @@
goto err_out_release_mdesc;
}
- port->vp = vp;
port->dev_no = *port_id;
if (port->dev_no >= 26)
@@ -818,12 +806,6 @@
if (err)
goto err_out_free_tx_ring;
- INIT_LIST_HEAD(&port->list);
-
- spin_lock_irqsave(&vp->lock, flags);
- list_add(&port->list, &vp->port_list);
- spin_unlock_irqrestore(&vp->lock, flags);
-
dev_set_drvdata(&vdev->dev, port);
mdesc_release(hp);
@@ -879,58 +861,6 @@
}
};
-static int __devinit vdc_probe(struct vio_dev *vdev,
- const struct vio_device_id *id)
-{
- static int vdc_version_printed;
- struct vdc *vp;
-
- if (vdc_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
- if (!vp)
- return -ENOMEM;
-
- spin_lock_init(&vp->lock);
- vp->dev = vdev;
- INIT_LIST_HEAD(&vp->port_list);
-
- dev_set_drvdata(&vdev->dev, vp);
-
- return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
- struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
- if (vp) {
- kfree(vp);
- dev_set_drvdata(&vdev->dev, NULL);
- }
- return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
- {
- .type = "block",
- },
- {},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
- .id_table = vdc_match,
- .probe = vdc_probe,
- .remove = vdc_remove,
- .driver = {
- .name = "vdc",
- .owner = THIS_MODULE,
- }
-};
-
static int __init vdc_init(void)
{
int err;
@@ -940,19 +870,13 @@
goto out_err;
vdc_major = err;
- err = vio_register_driver(&vdc_driver);
- if (err)
- goto out_unregister_blkdev;
err = vio_register_driver(&vdc_port_driver);
if (err)
- goto out_unregister_vdc;
+ goto out_unregister_blkdev;
return 0;
-out_unregister_vdc:
- vio_unregister_driver(&vdc_driver);
-
out_unregister_blkdev:
unregister_blkdev(vdc_major, VDCBLK_NAME);
vdc_major = 0;
@@ -964,7 +888,6 @@
static void __exit vdc_exit(void)
{
vio_unregister_driver(&vdc_port_driver);
- vio_unregister_driver(&vdc_driver);
unregister_blkdev(vdc_major, VDCBLK_NAME);
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644
index 0000000..6746c29
--- /dev/null
+++ b/drivers/block/xen-blkfront.c
@@ -0,0 +1,988 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+ BLKIF_STATE_DISCONNECTED,
+ BLKIF_STATE_CONNECTED,
+ BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+ struct blkif_request req;
+ unsigned long request;
+ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'. They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+ struct xenbus_device *xbdev;
+ dev_t dev;
+ struct gendisk *gd;
+ int vdevice;
+ blkif_vdev_t handle;
+ enum blkif_state connected;
+ int ring_ref;
+ struct blkif_front_ring ring;
+ unsigned int evtchn, irq;
+ struct request_queue *rq;
+ struct work_struct work;
+ struct gnttab_free_callback callback;
+ struct blk_shadow shadow[BLK_RING_SIZE];
+ unsigned long shadow_free;
+ int feature_barrier;
+
+ /**
+ * The number of people holding this device open. We won't allow a
+ * hot-unplug unless this is 0.
+ */
+ int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF 0
+
+#define PARTS_PER_DISK 16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME "xvd" /* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+ unsigned long free = info->shadow_free;
+ BUG_ON(free > BLK_RING_SIZE);
+ info->shadow_free = info->shadow[free].req.id;
+ info->shadow[free].req.id = 0x0fffffee; /* debug */
+ return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+ unsigned long id)
+{
+ info->shadow[id].req.id = info->shadow_free;
+ info->shadow[id].request = 0;
+ info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+ struct blkfront_info *info = (struct blkfront_info *)arg;
+ schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+ struct blkfront_info *info = req->rq_disk->private_data;
+ unsigned long buffer_mfn;
+ struct blkif_request *ring_req;
+ struct bio *bio;
+ struct bio_vec *bvec;
+ int idx;
+ unsigned long id;
+ unsigned int fsect, lsect;
+ int ref;
+ grant_ref_t gref_head;
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+ return 1;
+
+ if (gnttab_alloc_grant_references(
+ BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+ gnttab_request_free_callback(
+ &info->callback,
+ blkif_restart_queue_callback,
+ info,
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ return 1;
+ }
+
+ /* Fill out a communications ring structure. */
+ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ id = get_id_from_freelist(info);
+ info->shadow[id].request = (unsigned long)req;
+
+ ring_req->id = id;
+ ring_req->sector_number = (blkif_sector_t)req->sector;
+ ring_req->handle = info->handle;
+
+ ring_req->operation = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ if (blk_barrier_rq(req))
+ ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+ ring_req->nr_segments = 0;
+ rq_for_each_bio (bio, req) {
+ bio_for_each_segment (bvec, bio, idx) {
+ BUG_ON(ring_req->nr_segments
+ == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+ fsect = bvec->bv_offset >> 9;
+ lsect = fsect + (bvec->bv_len >> 9) - 1;
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ info->xbdev->otherend_id,
+ buffer_mfn,
+ rq_data_dir(req) );
+
+ info->shadow[id].frame[ring_req->nr_segments] =
+ mfn_to_pfn(buffer_mfn);
+
+ ring_req->seg[ring_req->nr_segments] =
+ (struct blkif_request_segment) {
+ .gref = ref,
+ .first_sect = fsect,
+ .last_sect = lsect };
+
+ ring_req->nr_segments++;
+ }
+ }
+
+ info->ring.req_prod_pvt++;
+
+ /* Keep a private copy so we can reissue requests when recovering. */
+ info->shadow[id].req = *ring_req;
+
+ gnttab_free_grant_references(gref_head);
+
+ return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+ int notify;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+ if (notify)
+ notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ * read a block; request is in a request queue
+ */
+static void do_blkif_request(request_queue_t *rq)
+{
+ struct blkfront_info *info = NULL;
+ struct request *req;
+ int queued;
+
+ pr_debug("Entered do_blkif_request\n");
+
+ queued = 0;
+
+ while ((req = elv_next_request(rq)) != NULL) {
+ info = req->rq_disk->private_data;
+ if (!blk_fs_request(req)) {
+ end_request(req, 0);
+ continue;
+ }
+
+ if (RING_FULL(&info->ring))
+ goto wait;
+
+ pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+ "(%u/%li) buffer:%p [%s]\n",
+ req, req->cmd, (unsigned long)req->sector,
+ req->current_nr_sectors,
+ req->nr_sectors, req->buffer,
+ rq_data_dir(req) ? "write" : "read");
+
+
+ blkdev_dequeue_request(req);
+ if (blkif_queue_request(req)) {
+ blk_requeue_request(rq, req);
+wait:
+ /* Avoid pointless unplugs. */
+ blk_stop_queue(rq);
+ break;
+ }
+
+ queued++;
+ }
+
+ if (queued != 0)
+ flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+ request_queue_t *rq;
+
+ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (rq == NULL)
+ return -1;
+
+ elevator_init(rq, "noop");
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(rq, sector_size);
+ blk_queue_max_sectors(rq, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(rq, 511);
+
+ gd->queue = rq;
+
+ return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+ int err;
+
+ err = blk_queue_ordered(info->rq,
+ info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+ NULL);
+
+ if (err)
+ return err;
+
+ printk(KERN_INFO "blkfront: %s: barriers %s\n",
+ info->gd->disk_name,
+ info->feature_barrier ? "enabled" : "disabled");
+ return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+ int vdevice, u16 vdisk_info, u16 sector_size,
+ struct blkfront_info *info)
+{
+ struct gendisk *gd;
+ int nr_minors = 1;
+ int err = -ENODEV;
+
+ BUG_ON(info->gd != NULL);
+ BUG_ON(info->rq != NULL);
+
+ if ((minor % PARTS_PER_DISK) == 0)
+ nr_minors = PARTS_PER_DISK;
+
+ gd = alloc_disk(nr_minors);
+ if (gd == NULL)
+ goto out;
+
+ if (nr_minors > 1)
+ sprintf(gd->disk_name, "%s%c", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK);
+ else
+ sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK,
+ minor % PARTS_PER_DISK);
+
+ gd->major = XENVBD_MAJOR;
+ gd->first_minor = minor;
+ gd->fops = &xlvbd_block_fops;
+ gd->private_data = info;
+ gd->driverfs_dev = &(info->xbdev->dev);
+ set_capacity(gd, capacity);
+
+ if (xlvbd_init_blk_queue(gd, sector_size)) {
+ del_gendisk(gd);
+ goto out;
+ }
+
+ info->rq = gd->queue;
+ info->gd = gd;
+
+ if (info->feature_barrier)
+ xlvbd_barrier(info);
+
+ if (vdisk_info & VDISK_READONLY)
+ set_disk_ro(gd, 1);
+
+ if (vdisk_info & VDISK_REMOVABLE)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ if (vdisk_info & VDISK_CDROM)
+ gd->flags |= GENHD_FL_CD;
+
+ return 0;
+
+ out:
+ return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+ if (!RING_FULL(&info->ring)) {
+ /* Re-enable calldowns. */
+ blk_start_queue(info->rq);
+ /* Kick things off immediately. */
+ do_blkif_request(info->rq);
+ }
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+ struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+ spin_lock_irq(&blkif_io_lock);
+ if (info->connected == BLKIF_STATE_CONNECTED)
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+ /* Prevent new requests being issued until we fix things up. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = suspend ?
+ BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+ /* No more blkif_request(). */
+ if (info->rq)
+ blk_stop_queue(info->rq);
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irq(&blkif_io_lock);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ /* Free resources associated with old device channel. */
+ if (info->ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ring_ref, 0,
+ (unsigned long)info->ring.sring);
+ info->ring_ref = GRANT_INVALID_REF;
+ info->ring.sring = NULL;
+ }
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+ int i;
+ for (i = 0; i < s->req.nr_segments; i++)
+ gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+ struct request *req;
+ struct blkif_response *bret;
+ RING_IDX i, rp;
+ unsigned long flags;
+ struct blkfront_info *info = (struct blkfront_info *)dev_id;
+ int uptodate;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ again:
+ rp = info->ring.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for (i = info->ring.rsp_cons; i != rp; i++) {
+ unsigned long id;
+ int ret;
+
+ bret = RING_GET_RESPONSE(&info->ring, i);
+ id = bret->id;
+ req = (struct request *)info->shadow[id].request;
+
+ blkif_completion(&info->shadow[id]);
+
+ add_id_to_freelist(info, id);
+
+ uptodate = (bret->status == BLKIF_RSP_OKAY);
+ switch (bret->operation) {
+ case BLKIF_OP_WRITE_BARRIER:
+ if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+ printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+ info->gd->disk_name);
+ uptodate = -EOPNOTSUPP;
+ info->feature_barrier = 0;
+ xlvbd_barrier(info);
+ }
+ /* fall through */
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ if (unlikely(bret->status != BLKIF_RSP_OKAY))
+ dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+ "request: %x\n", bret->status);
+
+ ret = end_that_request_first(req, uptodate,
+ req->hard_nr_sectors);
+ BUG_ON(ret);
+ end_that_request_last(req, uptodate);
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ info->ring.rsp_cons = i;
+
+ if (i != info->ring.req_prod_pvt) {
+ int more_to_do;
+ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+ if (more_to_do)
+ goto again;
+ } else
+ info->ring.sring->rsp_event = i + 1;
+
+ kick_pending_request_queues(info);
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ struct blkif_sring *sring;
+ int err;
+
+ info->ring_ref = GRANT_INVALID_REF;
+
+ sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+ if (!sring) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+ return -ENOMEM;
+ }
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+ if (err < 0) {
+ free_page((unsigned long)sring);
+ info->ring.sring = NULL;
+ goto fail;
+ }
+ info->ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn,
+ blkif_interrupt,
+ IRQF_SAMPLE_RANDOM, "blkif", info);
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err,
+ "bind_evtchn_to_irqhandler failed");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ blkif_free(info, 0);
+ return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ const char *message = NULL;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_blkring(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_blkring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename,
+ "ring-ref", "%u", info->ring_ref);
+ if (err) {
+ message = "writing ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_blkring;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ if (message)
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+ blkif_free(info, 0);
+ out:
+ return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those. Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err, vdevice, i;
+ struct blkfront_info *info;
+
+ /* FIXME: Use dynamic device id if this is not set. */
+ err = xenbus_scanf(XBT_NIL, dev->nodename,
+ "virtual-device", "%i", &vdevice);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading virtual-device");
+ return err;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+ return -ENOMEM;
+ }
+
+ info->xbdev = dev;
+ info->vdevice = vdevice;
+ info->connected = BLKIF_STATE_DISCONNECTED;
+ INIT_WORK(&info->work, blkif_restart_queue);
+
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Front end dir is a number, which is used as the id. */
+ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+ dev->dev.driver_data = info;
+
+ err = talk_to_backend(dev, info);
+ if (err) {
+ kfree(info);
+ dev->dev.driver_data = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+ int i;
+ struct blkif_request *req;
+ struct blk_shadow *copy;
+ int j;
+
+ /* Stage 1: Make a safe copy of the shadow state. */
+ copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, info->shadow, sizeof(info->shadow));
+
+ /* Stage 2: Set up free list. */
+ memset(&info->shadow, 0, sizeof(info->shadow));
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow_free = info->ring.req_prod_pvt;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Stage 3: Find pending requests and requeue them. */
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ /* Not in use? */
+ if (copy[i].request == 0)
+ continue;
+
+ /* Grab a request slot and copy shadow state into it. */
+ req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ *req = copy[i].req;
+
+ /* We get a new request id, and must reset the shadow state. */
+ req->id = get_id_from_freelist(info);
+ memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i]));
+
+ /* Rewrite any grant references invalidated by susp/resume. */
+ for (j = 0; j < req->nr_segments; j++)
+ gnttab_grant_foreign_access_ref(
+ req->seg[j].gref,
+ info->xbdev->otherend_id,
+ pfn_to_mfn(info->shadow[req->id].frame[j]),
+ rq_data_dir(
+ (struct request *)
+ info->shadow[req->id].request));
+ info->shadow[req->id].req = *req;
+
+ info->ring.req_prod_pvt++;
+ }
+
+ kfree(copy);
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ spin_lock_irq(&blkif_io_lock);
+
+ /* Now safe for us to use the shared ring */
+ info->connected = BLKIF_STATE_CONNECTED;
+
+ /* Send off requeued requests */
+ flush_requests(info);
+
+ /* Kick any other new requests queued since we resumed */
+ kick_pending_request_queues(info);
+
+ spin_unlock_irq(&blkif_io_lock);
+
+ return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ int err;
+
+ dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+ blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+ err = talk_to_backend(dev, info);
+ if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+ err = blkif_recover(info);
+
+ return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+ unsigned long long sectors;
+ unsigned long sector_size;
+ unsigned int binfo;
+ int err;
+
+ if ((info->connected == BLKIF_STATE_CONNECTED) ||
+ (info->connected == BLKIF_STATE_SUSPENDED) )
+ return;
+
+ dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+ __func__, info->xbdev->otherend);
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "sectors", "%llu", §ors,
+ "info", "%u", &binfo,
+ "sector-size", "%lu", §or_size,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err,
+ "reading backend fields at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-barrier", "%lu", &info->feature_barrier,
+ NULL);
+ if (err)
+ info->feature_barrier = 0;
+
+ err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+ sectors, info->vdevice,
+ binfo, sector_size, info);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ /* Kick pending requests. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = BLKIF_STATE_CONNECTED;
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+
+ add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing. We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend. Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ unsigned long flags;
+
+ dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+ if (info->rq == NULL)
+ goto out;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ del_gendisk(info->gd);
+
+ /* No more blkif_request(). */
+ blk_stop_queue(info->rq);
+
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ blk_cleanup_queue(info->rq);
+ info->rq = NULL;
+
+ out:
+ xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ struct block_device *bd;
+
+ dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateConnected:
+ blkfront_connect(info);
+ break;
+
+ case XenbusStateClosing:
+ bd = bdget(info->dev);
+ if (bd == NULL)
+ xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+ mutex_lock(&bd->bd_mutex);
+ if (info->users > 0)
+ xenbus_dev_error(dev, -EBUSY,
+ "Device in use; refusing to close");
+ else
+ blkfront_closing(dev);
+ mutex_unlock(&bd->bd_mutex);
+ bdput(bd);
+ break;
+ }
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+ blkif_free(info, 0);
+
+ kfree(info);
+
+ return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users++;
+ return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users--;
+ if (info->users == 0) {
+ /* Check whether we have been instructed to close. We will
+ have ignored this request initially, as the device was
+ still mounted. */
+ struct xenbus_device *dev = info->xbdev;
+ enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+ if (state == XenbusStateClosing)
+ blkfront_closing(dev);
+ }
+ return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+ .owner = THIS_MODULE,
+ .open = blkif_open,
+ .release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+ { "vbd" },
+ { "" }
+};
+
+static struct xenbus_driver blkfront = {
+ .name = "vbd",
+ .owner = THIS_MODULE,
+ .ids = blkfront_ids,
+ .probe = blkfront_probe,
+ .remove = blkfront_remove,
+ .resume = blkfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+ printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+ XENVBD_MAJOR, DEV_NAME);
+ return -ENODEV;
+ }
+
+ return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+ return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 97bd71b..9e8f214 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -604,6 +604,14 @@
help
Toshiba's Cell Reference Set Beat Console device driver
+config HVC_XEN
+ bool "Xen Hypervisor Console support"
+ depends on XEN
+ select HVC_DRIVER
+ default y
+ help
+ Xen virtual console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f2996a9..8852b8d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -48,6 +48,7 @@
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644
index 0000000..dd68f85
--- /dev/null
+++ b/drivers/char/hvc_xen.c
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * 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 <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE 0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+ return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+ /* Use evtchn: this is called early, before irq is set up. */
+ notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int sent = 0;
+
+ cons = intf->out_cons;
+ prod = intf->out_prod;
+ mb(); /* update queue values before going on */
+ BUG_ON((prod - cons) > sizeof(intf->out));
+
+ while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+ intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+ wmb(); /* write ring before updating pointer */
+ intf->out_prod = prod;
+
+ notify_daemon();
+ return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int recv = 0;
+
+ cons = intf->in_cons;
+ prod = intf->in_prod;
+ mb(); /* get pointers before reading ring */
+ BUG_ON((prod - cons) > sizeof(intf->in));
+
+ while (cons != prod && recv < len)
+ buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+ mb(); /* read ring before consuming */
+ intf->in_cons = cons;
+
+ notify_daemon();
+ return recv;
+}
+
+static struct hv_ops hvc_ops = {
+ .get_chars = read_console,
+ .put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!is_running_on_xen())
+ return 0;
+
+ xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+ if (xencons_irq < 0)
+ xencons_irq = 0 /* NO_IRQ */;
+ hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+ hvc = hp;
+ return 0;
+}
+
+static void __exit xen_fini(void)
+{
+ if (hvc)
+ hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+ if (!is_running_on_xen())
+ return 0;
+
+ hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+ return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+ unsigned len)
+{
+ unsigned int linelen, off = 0;
+ const char *pos;
+
+ while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+ linelen = pos-string+off;
+ if (off + linelen > len)
+ break;
+ write_console(0, string+off, linelen);
+ write_console(0, "\r\n", 2);
+ off += linelen + 1;
+ }
+ if (off < len)
+ write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+ .name = "xenboot",
+ .write = xenboot_write_console,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+};
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index dbb22403..3d90fc0 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -1770,7 +1770,8 @@
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e18d265..516d943 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -80,7 +80,8 @@
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
EXPORT_SYMBOL_GPL(wf_critical_overtemp);
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 624b21c..d9d033e 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -80,8 +80,12 @@
config VIDEO_BTCX
tristate
+config VIDEO_IR_I2C
+ tristate
+
config VIDEO_IR
tristate
+ select VIDEO_IR_I2C if I2C
config VIDEO_TVEEPROM
tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fcb1941..fe447a0 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -107,21 +107,20 @@
}
/* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
u32 ir_extract_bits(u32 data, u32 mask)
{
- int mbit, vbit;
- u32 value;
+ u32 vbit = 1, value = 0;
- value = 0;
- vbit = 0;
- for (mbit = 0; mbit < 32; mbit++) {
- if (!(mask & ((u32)1 << mbit)))
- continue;
- if (data & ((u32)1 << mbit))
- value |= (1 << vbit);
- vbit++;
- }
+ do {
+ if (mask&1) {
+ if (data&1)
+ value |= vbit;
+ vbit<<=1;
+ }
+ data>>=1;
+ } while (mask>>=1);
+
return value;
}
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index ef3e54c..ba6701e 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -27,7 +27,7 @@
unsigned int saa7146_debug;
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
#if 0
@@ -130,10 +130,10 @@
/********************************************************************************/
/* common page table functions */
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
{
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
- char *mem = vmalloc_32(length);
+ void *mem = vmalloc_32(length);
int slen = 0;
if (NULL == mem)
@@ -168,7 +168,7 @@
return NULL;
}
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
{
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
saa7146_pgtable_free(pci, pt);
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e3d04a4..664280c 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -889,9 +889,9 @@
DEB_EE(("VIDIOC_QUERYCAP\n"));
- strcpy(cap->driver, "saa7146 v4l2");
- strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ strcpy((char *)cap->driver, "saa7146 v4l2");
+ strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+ sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = SAA7146_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +968,7 @@
}
memset(f,0,sizeof(*f));
f->index = index;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
+ strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
f->pixelformat = formats[index].pixelformat;
break;
}
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index a0dcd59..3197aeb 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,7 +1,7 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index bff00b5..e97ff60 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -12,4 +12,4 @@
b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index b02c2fd..0378fd6 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -500,13 +500,13 @@
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index cfd6fb7..ea66617 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,7 +7,7 @@
select DVB_CX24110 if !DVB_FE_CUSTOMISE
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d197ef..84cf705 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index e908e3c..b7a17e6 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1652,7 +1652,7 @@
static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 4f1c09b..67613eb 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -611,7 +611,7 @@
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
dvb_attach(dvb_pll_attach, card->fe, 0x61,
- card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+ card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
@@ -692,6 +692,9 @@
case BTTV_BOARD_PC_HDTV:
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+ if (card->fe != NULL)
+ dvb_attach(dvb_pll_attach, card->fe, 0x61,
+ card->i2c_adapter, DVB_PLL_FCV1236D);
break;
}
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
index c51aece..d762d8c 100644
--- a/drivers/media/dvb/cinergyT2/Makefile
+++ b/drivers/media/dvb/cinergyT2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index b40af48..5a1449f 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -829,7 +829,7 @@
input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
input_dev->id.version = 1;
- input_dev->cdev.dev = &cinergyt2->udev->dev;
+ input_dev->dev.parent = &cinergyt2->udev->dev;
err = input_register_device(input_dev);
if (err) {
@@ -1000,18 +1000,15 @@
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
return -ERESTARTSYS;
- if (1) {
- cinergyt2_suspend_rc(cinergyt2);
- cancel_rearming_delayed_work(&cinergyt2->query_work);
+ cinergyt2_suspend_rc(cinergyt2);
+ cancel_rearming_delayed_work(&cinergyt2->query_work);
- mutex_lock(&cinergyt2->sem);
- if (cinergyt2->streaming)
- cinergyt2_stop_stream_xfer(cinergyt2);
- cinergyt2_sleep(cinergyt2, 1);
- mutex_unlock(&cinergyt2->sem);
- }
+ mutex_lock(&cinergyt2->sem);
+ if (cinergyt2->streaming)
+ cinergyt2_stop_stream_xfer(cinergyt2);
+ cinergyt2_sleep(cinergyt2, 1);
+ mutex_unlock(&cinergyt2->sem);
- mutex_unlock(&cinergyt2->wq_sem);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 275df65..5394de2 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -97,7 +97,7 @@
if (avail > todo)
avail = todo;
- ret = dvb_ringbuffer_read(src, buf, avail, 1);
+ ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
if (ret < 0)
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 2a03bf5..4fadddb 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -175,7 +175,7 @@
* @param nlen Number of bytes in needle.
* @return Pointer into haystack needle was found at, or NULL if not found.
*/
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
{
int i;
@@ -482,7 +482,7 @@
}
/* check it contains the correct DVB string */
- dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
if (dvb_str == NULL)
return -EINVAL;
if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +513,8 @@
ca->slot_info[slot].config_option = tuple[0] & 0x3f;
/* OK, check it contains the correct strings */
- if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
- (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+ if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+ (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
break;
got_cftableentry = 1;
@@ -1300,7 +1300,7 @@
struct dvb_ca_private *ca = dvbdev->priv;
u8 slot, connection_id;
int status;
- char fragbuf[HOST_LINK_BUF_SIZE];
+ u8 fragbuf[HOST_LINK_BUF_SIZE];
int fragpos = 0;
int fraglen;
unsigned long timeout;
@@ -1486,7 +1486,7 @@
}
if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
- buf + pktlen, fraglen, 1)) < 0) {
+ (u8 *)buf + pktlen, fraglen, 1)) < 0) {
goto exit;
}
pktlen += fraglen;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d8d1c3d..cb6987f 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1068,7 +1068,7 @@
if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
- dvb_dmx_swfilter(dvbdemux, buf, count);
+ dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
mutex_unlock(&dvbdemux->mutex);
if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index f233d78..a770a87 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -103,7 +103,7 @@
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status);
/* get frontend tuning algorithm from the module */
int (*get_frontend_algo)(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4ebf33a5..acf0263 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -347,7 +347,8 @@
{
struct dvb_net_priv *priv = dev->priv;
unsigned long skipped = 0L;
- u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+ const u8 *ts, *ts_end, *from_where = NULL;
+ u8 ts_remain = 0, how_much = 0, new_ts = 1;
struct ethhdr *ethh = NULL;
#ifdef ULE_DEBUG
@@ -364,7 +365,7 @@
/* For all TS cells in current buffer.
* Appearently, we are called for every single TS cell.
*/
- for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+ for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
if (new_ts) {
/* We are about to process a new TS cell. */
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a9fa333..9ef0c00 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -208,7 +208,7 @@
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
- printk ("%s: could get find free device id...\n", __FUNCTION__);
+ printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
return -ENFILE;
}
@@ -252,7 +252,7 @@
return PTR_ERR(clsdev);
}
- dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
@@ -311,7 +311,7 @@
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
- printk ("DVB: registering new adapter (%s).\n", name);
+ printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
adap->num = num;
adap->name = name;
@@ -407,13 +407,13 @@
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable register character device\n");
goto error;
}
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 5448873..40e41f2 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -2,7 +2,6 @@
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C
select FW_LOADER
- select DVB_PLL
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@
depends on DVB_USB
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
config DVB_USB_DIBUSB_MB
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -89,7 +89,7 @@
config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -98,7 +98,7 @@
config DVB_USB_CXUSB
tristate "Conexant USB2.0 hybrid reference design support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_CX22702 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +142,7 @@
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
help
@@ -188,6 +188,7 @@
depends on DVB_USB
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
@@ -216,5 +217,23 @@
tristate "Opera1 DVB-S USB2.0 receiver"
depends on DVB_USB
select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+ tristate "Afatech AF9005 DVB-T USB1.1 support"
+ depends on DVB_USB && EXPERIMENTAL
+ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+ and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+ tristate "Afatech AF9005 default remote control support"
+ depends on DVB_USB_AF9005
+ help
+ Say Y here to support the default remote control decoding for the
+ Afatech AF9005 based receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 976f840..73ac0a9 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -55,4 +55,10 @@
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644
index 0000000..7195c94
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -0,0 +1,1503 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+ struct dvb_usb_device *d;
+ struct dvb_frontend *tuner;
+
+ fe_status_t stat;
+
+ /* retraining parameters */
+ u32 original_fcw;
+ u16 original_rf_top;
+ u16 original_if_top;
+ u16 original_if_min;
+ u16 original_aci0_if_top;
+ u16 original_aci1_if_top;
+ u16 original_aci0_if_min;
+ u8 original_if_unplug_th;
+ u8 original_rf_unplug_th;
+ u8 original_dtop_if_unplug_th;
+ u8 original_dtop_rf_unplug_th;
+
+ /* statistics */
+ u32 pre_vit_error_count;
+ u32 pre_vit_bit_count;
+ u32 ber;
+ u32 post_vit_error_count;
+ u32 post_vit_bit_count;
+ u32 unc;
+ u16 abort_count;
+
+ int opened;
+ int strong;
+ unsigned long next_status_check;
+ struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 value)
+{
+ int ret;
+ u8 temp;
+
+ if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+ return ret;
+ temp = (u8) ((value & 0x0300) >> 8);
+ return af9005_write_register_bits(d, reghi, pos, len,
+ (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 * value)
+{
+ int ret;
+ u8 temp0, temp1;
+
+ if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+ return ret;
+ if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+ return ret;
+ switch (pos) {
+ case 0:
+ *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+ break;
+ case 2:
+ *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+ break;
+ case 4:
+ *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+ break;
+ case 6:
+ *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+ break;
+ default:
+ err("invalid pos in read word agc");
+ return -EINVAL;
+ }
+ return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ *available = false;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, &temp);
+ if (ret)
+ return ret;
+ if (temp & 1) {
+ ret =
+ af9005_read_register_bits(state->d,
+ xd_p_reg_ofsm_read_rbc_en,
+ reg_ofsm_read_rbc_en_pos,
+ reg_ofsm_read_rbc_en_len, &temp);
+ if (ret)
+ return ret;
+ if ((temp & 1) == 0)
+ *available = true;
+
+ }
+ return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+ u32 * post_err_count,
+ u32 * post_cw_count,
+ u16 * abort_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u32 err_count;
+ u32 cw_count;
+ u8 temp, temp0, temp1, temp2;
+ u16 loc_abort_count;
+
+ *post_err_count = 0;
+ *post_cw_count = 0;
+
+ /* check if error bit count is ready */
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+ fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("rsd counter not ready\n");
+ return 100;
+ }
+ /* get abort count */
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+ /* get error count */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+ *post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+ /* get RSD packet number */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ cw_count = ((u32) temp1 << 8) + temp0;
+ if (cw_count == 0) {
+ err("wrong RSD packet count");
+ return -EIO;
+ }
+ deb_info("POST abort count %d err count %d rsd packets %d\n",
+ loc_abort_count, err_count, cw_count);
+ *post_cw_count = cw_count - (u32) loc_abort_count;
+ *abort_count = loc_abort_count;
+ return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+ u32 * post_err_count, u32 * post_cw_count,
+ u16 * abort_count)
+{
+ u32 loc_cw_count = 0, loc_err_count;
+ u16 loc_abort_count;
+ int ret;
+
+ ret =
+ af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+ &loc_abort_count);
+ if (ret)
+ return ret;
+ *post_err_count = loc_err_count;
+ *post_cw_count = loc_cw_count * 204 * 8;
+ *abort_count = loc_abort_count;
+
+ return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+ u32 * pre_err_count,
+ u32 * pre_bit_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp, temp0, temp1, temp2;
+ u32 super_frame_count, x, bits;
+ int ret;
+
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+ fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("viterbi counter not ready\n");
+ return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */
+ }
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ super_frame_count = ((u32) temp1 << 8) + temp0;
+ if (super_frame_count == 0) {
+ deb_info("super frame count 0\n");
+ return 102;
+ }
+
+ /* read fft mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp == 0) {
+ /* 2K */
+ x = 1512;
+ } else if (temp == 1) {
+ /* 8k */
+ x = 6048;
+ } else {
+ err("Invalid fft mode");
+ return -EINVAL;
+ }
+
+ /* read constellation mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ switch (temp) {
+ case 0: /* QPSK */
+ bits = 2;
+ break;
+ case 1: /* QAM_16 */
+ bits = 4;
+ break;
+ case 2: /* QAM_64 */
+ bits = 6;
+ break;
+ default:
+ err("invalid constellation mode");
+ return -EINVAL;
+ }
+ *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+ deb_info("PRE err count %d frame count %d bit count %d\n",
+ *pre_err_count, super_frame_count, *pre_bit_count);
+ return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set super frame count to 1 */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ 1 & 0xff);
+ if (ret)
+ return ret;
+ af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ 1 >> 8);
+ if (ret)
+ return ret;
+ /* reset pre viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+ fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set packet unit */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ 10000 & 0xff);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ 10000 >> 8);
+ if (ret)
+ return ret;
+ /* reset post viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+ fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret, fecavailable;
+ u64 numerator, denominator;
+
+ deb_info("GET STATISTIC\n");
+ ret = af9005_is_fecmon_available(fe, &fecavailable);
+ if (ret)
+ return ret;
+ if (!fecavailable) {
+ deb_info("fecmon not available\n");
+ return 0;
+ }
+
+ ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+ &state->pre_vit_bit_count);
+ if (ret == 0) {
+ af9005_reset_pre_viterbi(fe);
+ if (state->pre_vit_bit_count > 0) {
+ /* according to v 0.0.4 of the dvb api ber should be a multiple
+ of 10E-9 so we have to multiply the error count by
+ 10E9=1000000000 */
+ numerator =
+ (u64) state->pre_vit_error_count * (u64) 1000000000;
+ denominator = (u64) state->pre_vit_bit_count;
+ state->ber = do_div(numerator, denominator);
+ } else {
+ state->ber = 0xffffffff;
+ }
+ }
+
+ ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+ &state->post_vit_bit_count,
+ &state->abort_count);
+ if (ret == 0) {
+ ret = af9005_reset_post_viterbi(fe);
+ state->unc += state->abort_count;
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (time_after(jiffies, state->next_status_check)) {
+ deb_info("REFRESH STATE\n");
+
+ /* statistics */
+ if (af9005_get_statistic(fe))
+ err("get_statistic_failed");
+ state->next_status_check = jiffies + 250 * HZ / 1000;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp;
+ int ret;
+
+ if (state->tuner == NULL)
+ return -ENODEV;
+
+ *stat = 0;
+ ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+ agc_lock_pos, agc_lock_len, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SIGNAL;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+ fd_tpsd_lock_pos, fd_tpsd_lock_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_CARRIER;
+
+ ret = af9005_read_register_bits(state->d,
+ xd_r_mp2if_sync_byte_locked,
+ mp2if_sync_byte_locked_pos,
+ mp2if_sync_byte_locked_pos, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+ if (state->opened)
+ af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+ ret =
+ af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+ reg_strong_sginal_detected_pos,
+ reg_strong_sginal_detected_len, &temp);
+ if (ret)
+ return ret;
+ if (temp != state->strong) {
+ deb_info("adjust for strong signal %d\n", temp);
+ state->strong = temp;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (state->tuner == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *ber = state->ber;
+ return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (state->tuner == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *unc = state->unc;
+ return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+ u16 * strength)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 if_gain, rf_gain;
+
+ if (state->tuner == NULL)
+ return -ENODEV;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+ &rf_gain);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+ &if_gain);
+ if (ret)
+ return ret;
+ /* this value has no real meaning, but i don't have the tables that relate
+ the rf and if gain with the dbm, so I just scale the value */
+ *strength = (512 - rf_gain - if_gain) << 7;
+ return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ /* the snr can be derived from the ber and the constellation
+ but I don't think this kind of complex calculations belong
+ in the driver. I may be wrong.... */
+ return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp0, temp1, temp2, temp3, buf[4];
+ int ret;
+ u32 NS_coeff1_2048Nu;
+ u32 NS_coeff1_8191Nu;
+ u32 NS_coeff1_8192Nu;
+ u32 NS_coeff1_8193Nu;
+ u32 NS_coeff2_2k;
+ u32 NS_coeff2_8k;
+
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ NS_coeff1_2048Nu = 0x2ADB6DC;
+ NS_coeff1_8191Nu = 0xAB7313;
+ NS_coeff1_8192Nu = 0xAB6DB7;
+ NS_coeff1_8193Nu = 0xAB685C;
+ NS_coeff2_2k = 0x156DB6E;
+ NS_coeff2_8k = 0x55B6DC;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ NS_coeff1_2048Nu = 0x3200001;
+ NS_coeff1_8191Nu = 0xC80640;
+ NS_coeff1_8192Nu = 0xC80000;
+ NS_coeff1_8193Nu = 0xC7F9C0;
+ NS_coeff2_2k = 0x1900000;
+ NS_coeff2_8k = 0x640000;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ NS_coeff1_2048Nu = 0x3924926;
+ NS_coeff1_8191Nu = 0xE4996E;
+ NS_coeff1_8192Nu = 0xE49249;
+ NS_coeff1_8193Nu = 0xE48B25;
+ NS_coeff2_2k = 0x1C92493;
+ NS_coeff2_8k = 0x724925;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+
+ /*
+ * write NS_coeff1_2048Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+ temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ /* cfoe_NS_2k_coeff1_25_24 */
+ ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_23_16 */
+ ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_15_8 */
+ ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_7_0 */
+ ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_2k
+ */
+
+ temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8191Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8192Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8193Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_8k
+ */
+
+ temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+ return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp;
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ temp = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ temp = 1;
+ break;
+ case BANDWIDTH_8_MHZ:
+ temp = 2;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+ return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp = on;
+ int ret;
+ deb_info("power %s tuner\n", on ? "on" : "off");
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+ 0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+ 0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ int ret, i, scriptlen;
+ u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+ u8 buf[2];
+ u16 if1;
+
+ deb_info("in af9005_fe_init\n");
+
+ /* reset */
+ deb_info("reset\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+ 4, 1, 0x01)))
+ return ret;
+ if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+ return ret;
+ /* clear ofdm reset */
+ deb_info("clear ofdm reset\n");
+ for (i = 0; i < 150; i++) {
+ if ((ret =
+ af9005_read_ofdm_register(state->d,
+ xd_I2C_reg_ofdm_rst, &temp)))
+ return ret;
+ if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+ break;
+ msleep(10);
+ }
+ if (i == 150)
+ return -ETIMEDOUT;
+
+ /*FIXME in the dump
+ write B200 A9
+ write xd_g_reg_ofsm_clk 7
+ read eepr c6 (2)
+ read eepr c7 (2)
+ misc ctrl 3 -> 1
+ read eepr ca (6)
+ write xd_g_reg_ofsm_clk 0
+ write B200 a1
+ */
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+ if (ret)
+ return ret;
+ temp = 0x01;
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+ if (ret)
+ return ret;
+
+ temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+ return ret;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 0)))
+ return ret;
+
+ if (ret)
+ return ret;
+ /* don't know what register aefc is, but this is what the windows driver does */
+ ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+ if (ret)
+ return ret;
+
+ /* set stand alone chip */
+ deb_info("set stand alone chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+ reg_dca_stand_alone_pos,
+ reg_dca_stand_alone_len, 1)))
+ return ret;
+
+ /* set dca upper & lower chip */
+ deb_info("set dca upper & lower chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+ reg_dca_upper_chip_pos,
+ reg_dca_upper_chip_len, 0)))
+ return ret;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+ reg_dca_lower_chip_pos,
+ reg_dca_lower_chip_len, 0)))
+ return ret;
+
+ /* set 2wire master clock to 0x14 (for 60KHz) */
+ deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+ if ((ret =
+ af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+ return ret;
+
+ /* clear dca enable chip */
+ deb_info("clear dca enable chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+ reg_dca_en_pos, reg_dca_en_len, 0)))
+ return ret;
+ /* FIXME these are register bits, but I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+ if (ret)
+ return ret;
+
+ /* init other parameters: program cfoe and select bandwith */
+ deb_info("program cfoe\n");
+ if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+ return ret;
+ /* set read-update bit for constellation */
+ deb_info("set read-update bit for constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+ reg_feq_read_update_pos,
+ reg_feq_read_update_len, 1)))
+ return ret;
+
+ /* sample code has a set MPEG TS code here
+ but sniffing reveals that it doesn't do it */
+
+ /* set read-update bit to 1 for DCA constellation */
+ deb_info("set read-update bit 1 for DCA constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+ reg_dca_read_update_pos,
+ reg_dca_read_update_len, 1)))
+ return ret;
+
+ /* enable fec monitor */
+ deb_info("enable fec monitor\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, 1)))
+ return ret;
+
+ /* FIXME should be register bits, I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+ /* set api_retrain_never_freeze */
+ deb_info("set api_retrain_never_freeze\n");
+ if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+ return ret;
+
+ /* load init script */
+ deb_info("load init script\n");
+ scriptlen = sizeof(script) / sizeof(RegDesc);
+ for (i = 0; i < scriptlen; i++) {
+ if ((ret =
+ af9005_write_register_bits(state->d, script[i].reg,
+ script[i].pos,
+ script[i].len, script[i].val)))
+ return ret;
+ /* save 3 bytes of original fcw */
+ if (script[i].reg == 0xae18)
+ temp2 = script[i].val;
+ if (script[i].reg == 0xae19)
+ temp1 = script[i].val;
+ if (script[i].reg == 0xae1a)
+ temp0 = script[i].val;
+
+ /* save original unplug threshold */
+ if (script[i].reg == xd_p_reg_unplug_th)
+ state->original_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+ state->original_rf_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+ state->original_dtop_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+ state->original_dtop_rf_unplug_th = script[i].val;
+
+ }
+ state->original_fcw =
+ ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+ /* save original TOPs */
+ deb_info("save original TOPs\n");
+
+ /* RF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ &state->original_rf_top);
+ if (ret)
+ return ret;
+
+ /* IF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ &state->original_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 0 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ &state->original_aci0_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 1 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ &state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* attach tuner and init */
+ if (state->tuner == NULL) {
+ /* read tuner and board id from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+ switch (buf[0]) {
+ case 2: /* MT2060 */
+ /* read if1 from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ if1 = (u16) (buf[0] << 8) + buf[1];
+ state->tuner =
+ dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+ &af9005_mt2060_config, if1);
+ if (state->tuner == NULL) {
+ deb_info("MT2060 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ case 3: /* QT1010 */
+ case 9: /* QT1010B */
+ state->tuner =
+ dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+ &af9005_qt1010_config);
+ if (state->tuner == NULL) {
+ deb_info("QT1010 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ default:
+ err("Unsupported tuner type %d", buf[0]);
+ return -ENODEV;
+ }
+ ret = state->tuner->ops.tuner_ops.init(state->tuner);
+ if (ret)
+ return ret;
+ }
+
+ deb_info("profit!\n");
+ return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+ return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+
+ if (acquire) {
+ state->opened++;
+ } else {
+
+ state->opened--;
+ if (!state->opened)
+ af9005_led_control(state->d, 0);
+ }
+ return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp, temp0, temp1, temp2;
+
+ deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+ fep->u.ofdm.bandwidth);
+ if (state->tuner == NULL) {
+ err("Tuner not attached");
+ return -ENODEV;
+ }
+
+ deb_info("turn off led\n");
+ /* not in the log */
+ ret = af9005_led_control(state->d, 0);
+ if (ret)
+ return ret;
+ /* not sure about the bits */
+ ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+ if (ret)
+ return ret;
+
+ /* set FCW to default value */
+ deb_info("set FCW to default value\n");
+ temp0 = (u8) (state->original_fcw & 0x000000ff);
+ temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+ temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+ ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+ if (ret)
+ return ret;
+
+ /* restore original TOPs */
+ deb_info("restore original TOPs\n");
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ state->original_rf_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ state->original_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ state->original_aci0_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* select bandwith */
+ deb_info("select bandwidth");
+ ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+ ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+
+ /* clear easy mode flag */
+ deb_info("clear easy mode flag\n");
+ ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+ if (ret)
+ return ret;
+
+ /* set unplug threshold to original value */
+ deb_info("set unplug threshold to original value\n");
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+ state->original_if_unplug_th);
+ if (ret)
+ return ret;
+ /* set tuner */
+ deb_info("set tuner\n");
+ ret = state->tuner->ops.tuner_ops.set_params(state->tuner, fep);
+ if (ret)
+ return ret;
+
+ /* trigger ofsm */
+ deb_info("trigger ofsm\n");
+ temp = 0;
+ ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+ if (ret)
+ return ret;
+
+ /* clear retrain and freeze flag */
+ deb_info("clear retrain and freeze flag\n");
+ ret =
+ af9005_write_register_bits(state->d,
+ xd_p_reg_api_retrain_request,
+ reg_api_retrain_request_pos, 2, 0);
+ if (ret)
+ return ret;
+
+ /* reset pre viterbi and post viterbi registers and statistics */
+ af9005_reset_pre_viterbi(fe);
+ af9005_reset_post_viterbi(fe);
+ state->pre_vit_error_count = 0;
+ state->pre_vit_bit_count = 0;
+ state->ber = 0;
+ state->post_vit_error_count = 0;
+ /* state->unc = 0; commented out since it should be ever increasing */
+ state->abort_count = 0;
+
+ state->next_status_check = jiffies;
+ state->strong = -1;
+
+ return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ /* mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("===== fe_get_frontend ==============\n");
+ deb_info("CONSTELLATION ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.constellation = QPSK;
+ deb_info("QPSK\n");
+ break;
+ case 1:
+ fep->u.ofdm.constellation = QAM_16;
+ deb_info("QAM_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.constellation = QAM_64;
+ deb_info("QAM_64\n");
+ break;
+ }
+
+ /* tps hierarchy and alpha value */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+ reg_tpsd_hier_pos, reg_tpsd_hier_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("HIERARCHY ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ deb_info("NONE\n");
+ break;
+ case 1:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+ deb_info("1\n");
+ break;
+ case 2:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+ deb_info("2\n");
+ break;
+ case 3:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+ deb_info("4\n");
+ break;
+ }
+
+ /* high/low priority */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+ reg_dec_pri_pos, reg_dec_pri_len, &temp);
+ if (ret)
+ return ret;
+ /* if temp is set = high priority */
+ deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+ /* high coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+ reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE HP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_HP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_HP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_HP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_HP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_HP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* low coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+ reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE LP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_LP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_LP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_LP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_LP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_LP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* guard interval */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+ reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+ if (ret)
+ return ret;
+ deb_info("GUARD INTERVAL ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ deb_info("1_32\n");
+ break;
+ case 1:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ deb_info("1_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ deb_info("1_8\n");
+ break;
+ case 3:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ deb_info("1_4\n");
+ break;
+ }
+
+ /* fft */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("TRANSMISSION MODE ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ deb_info("2K\n");
+ break;
+ case 1:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ deb_info("8K\n");
+ break;
+ }
+
+ /* bandwidth */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, &temp);
+ deb_info("BANDWIDTH ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ deb_info("6\n");
+ break;
+ case 1:
+ fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ deb_info("7\n");
+ break;
+ case 2:
+ fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ deb_info("8\n");
+ break;
+ }
+ return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state =
+ (struct af9005_fe_state *)fe->demodulator_priv;
+ if (state->tuner != NULL && state->tuner->ops.tuner_ops.release != NULL) {
+ state->tuner->ops.tuner_ops.release(state->tuner);
+#ifdef CONFIG_DVB_CORE_ATTACH
+ symbol_put_addr(state->tuner->ops.tuner_ops.release);
+#endif
+ }
+ kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+ struct af9005_fe_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ deb_info("attaching frontend af9005\n");
+
+ state->d = d;
+ state->tuner = NULL;
+ state->opened = 0;
+
+ memcpy(&state->frontend.ops, &af9005_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+ error:
+ return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+ .info = {
+ .name = "AF9005 USB DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ 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_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = af9005_fe_release,
+
+ .init = af9005_fe_init,
+ .sleep = af9005_fe_sleep,
+ .ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+ .set_frontend = af9005_fe_set_frontend,
+ .get_frontend = af9005_fe_get_frontend,
+
+ .read_status = af9005_fe_read_status,
+ .read_ber = af9005_fe_read_ber,
+ .read_signal_strength = af9005_fe_read_signal_strength,
+ .read_snr = af9005_fe_read_snr,
+ .read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644
index 0000000..ff00c0e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "enable (1) or disable (0) debug messages."
+ DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+ {0x01, 0xb7, KEY_POWER},
+ {0x01, 0xa7, KEY_VOLUMEUP},
+ {0x01, 0x87, KEY_CHANNELUP},
+ {0x01, 0x7f, KEY_MUTE},
+ {0x01, 0xbf, KEY_VOLUMEDOWN},
+ {0x01, 0x3f, KEY_CHANNELDOWN},
+ {0x01, 0xdf, KEY_1},
+ {0x01, 0x5f, KEY_2},
+ {0x01, 0x9f, KEY_3},
+ {0x01, 0x1f, KEY_4},
+ {0x01, 0xef, KEY_5},
+ {0x01, 0x6f, KEY_6},
+ {0x01, 0xaf, KEY_7},
+ {0x01, 0x27, KEY_8},
+ {0x01, 0x07, KEY_9},
+ {0x01, 0xcf, KEY_ZOOM},
+ {0x01, 0x4f, KEY_0},
+ {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+
+ {0x00, 0xbd, KEY_POWER},
+ {0x00, 0x7d, KEY_VOLUMEUP},
+ {0x00, 0xfd, KEY_CHANNELUP},
+ {0x00, 0x9d, KEY_MUTE},
+ {0x00, 0x5d, KEY_VOLUMEDOWN},
+ {0x00, 0xdd, KEY_CHANNELDOWN},
+ {0x00, 0xad, KEY_1},
+ {0x00, 0x6d, KEY_2},
+ {0x00, 0xed, KEY_3},
+ {0x00, 0x8d, KEY_4},
+ {0x00, 0x4d, KEY_5},
+ {0x00, 0xcd, KEY_6},
+ {0x00, 0xb5, KEY_7},
+ {0x00, 0x75, KEY_8},
+ {0x00, 0xf5, KEY_9},
+ {0x00, 0x95, KEY_ZOOM},
+ {0x00, 0x55, KEY_0},
+ {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+ KEY_CHANNELUP,
+ KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+ int *state)
+{
+ u16 mark, space;
+ u32 result;
+ u8 cust, dat, invdat;
+ int i;
+
+ if (len >= 6) {
+ mark = (u16) (data[0] << 8) + data[1];
+ space = (u16) (data[2] << 8) + data[3];
+ if (space * 3 < mark) {
+ for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+ if (d->last_event == repeatable_keys[i]) {
+ *state = REMOTE_KEY_REPEAT;
+ *event = d->last_event;
+ deb_decode("repeat key, event %x\n",
+ *event);
+ return 0;
+ }
+ }
+ deb_decode("repeated key ignored (non repeatable)\n");
+ return 0;
+ } else if (len >= 33 * 4) { /*32 bits + start code */
+ result = 0;
+ for (i = 4; i < 4 + 32 * 4; i += 4) {
+ result <<= 1;
+ mark = (u16) (data[i] << 8) + data[i + 1];
+ mark >>= 1;
+ space = (u16) (data[i + 2] << 8) + data[i + 3];
+ space >>= 1;
+ if (mark * 2 > space)
+ result += 1;
+ }
+ deb_decode("key pressed, raw value %x\n", result);
+ if ((result & 0xff000000) != 0xfe000000) {
+ deb_decode
+ ("doesn't start with 0xfe, ignored\n");
+ return 0;
+ }
+ cust = (result >> 16) & 0xff;
+ dat = (result >> 8) & 0xff;
+ invdat = (~result) & 0xff;
+ if (dat != invdat) {
+ deb_decode("code != inverted code\n");
+ return 0;
+ }
+ for (i = 0; i < af9005_rc_keys_size; i++) {
+ if (af9005_rc_keys[i].custom == cust
+ && af9005_rc_keys[i].data == dat) {
+ *event = af9005_rc_keys[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ deb_decode
+ ("key pressed, event %x\n", *event);
+ return 0;
+ }
+ }
+ deb_decode("not found in table\n");
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+ ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644
index 0000000..6eeaae5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-script.h
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+ u16 reg;
+ u8 pos;
+ u8 len;
+ u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+ {0xa180, 0x0, 0x8, 0xa},
+ {0xa181, 0x0, 0x8, 0xd7},
+ {0xa182, 0x0, 0x8, 0xa3},
+ {0xa0a0, 0x0, 0x8, 0x0},
+ {0xa0a1, 0x0, 0x5, 0x0},
+ {0xa0a1, 0x5, 0x1, 0x1},
+ {0xa0c0, 0x0, 0x4, 0x1},
+ {0xa20e, 0x4, 0x4, 0xa},
+ {0xa20f, 0x0, 0x8, 0x40},
+ {0xa210, 0x0, 0x8, 0x8},
+ {0xa32a, 0x0, 0x4, 0xa},
+ {0xa32c, 0x0, 0x8, 0x20},
+ {0xa32b, 0x0, 0x8, 0x15},
+ {0xa1a0, 0x1, 0x1, 0x1},
+ {0xa000, 0x0, 0x1, 0x1},
+ {0xa000, 0x1, 0x1, 0x0},
+ {0xa001, 0x1, 0x1, 0x1},
+ {0xa001, 0x0, 0x1, 0x0},
+ {0xa001, 0x5, 0x1, 0x0},
+ {0xa00e, 0x0, 0x5, 0x10},
+ {0xa00f, 0x0, 0x3, 0x4},
+ {0xa00f, 0x3, 0x3, 0x5},
+ {0xa010, 0x0, 0x3, 0x4},
+ {0xa010, 0x3, 0x3, 0x5},
+ {0xa016, 0x4, 0x4, 0x3},
+ {0xa01f, 0x0, 0x6, 0xa},
+ {0xa020, 0x0, 0x6, 0xa},
+ {0xa2bc, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x5, 0x1, 0x1},
+ {0xa015, 0x0, 0x8, 0x50},
+ {0xa016, 0x0, 0x1, 0x0},
+ {0xa02a, 0x0, 0x8, 0x50},
+ {0xa029, 0x0, 0x8, 0x4b},
+ {0xa614, 0x0, 0x8, 0x46},
+ {0xa002, 0x0, 0x5, 0x19},
+ {0xa003, 0x0, 0x5, 0x1a},
+ {0xa004, 0x0, 0x5, 0x19},
+ {0xa005, 0x0, 0x5, 0x1a},
+ {0xa008, 0x0, 0x8, 0x69},
+ {0xa009, 0x0, 0x2, 0x2},
+ {0xae1b, 0x0, 0x8, 0x69},
+ {0xae1c, 0x0, 0x8, 0x2},
+ {0xae1d, 0x0, 0x8, 0x2a},
+ {0xa022, 0x0, 0x8, 0xaa},
+ {0xa006, 0x0, 0x8, 0xc8},
+ {0xa007, 0x0, 0x2, 0x0},
+ {0xa00c, 0x0, 0x8, 0xba},
+ {0xa00d, 0x0, 0x2, 0x2},
+ {0xa608, 0x0, 0x8, 0xba},
+ {0xa60e, 0x0, 0x2, 0x2},
+ {0xa609, 0x0, 0x8, 0x80},
+ {0xa60e, 0x2, 0x2, 0x3},
+ {0xa00a, 0x0, 0x8, 0xb6},
+ {0xa00b, 0x0, 0x2, 0x0},
+ {0xa011, 0x0, 0x8, 0xb9},
+ {0xa012, 0x0, 0x2, 0x0},
+ {0xa013, 0x0, 0x8, 0xbd},
+ {0xa014, 0x0, 0x2, 0x2},
+ {0xa366, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x3, 0x1, 0x0},
+ {0xa2bd, 0x0, 0x8, 0xa},
+ {0xa2be, 0x0, 0x8, 0x14},
+ {0xa2bf, 0x0, 0x8, 0x8},
+ {0xa60a, 0x0, 0x8, 0xbd},
+ {0xa60e, 0x4, 0x2, 0x2},
+ {0xa60b, 0x0, 0x8, 0x86},
+ {0xa60e, 0x6, 0x2, 0x3},
+ {0xa001, 0x2, 0x2, 0x1},
+ {0xa1c7, 0x0, 0x8, 0xf5},
+ {0xa03d, 0x0, 0x8, 0xb1},
+ {0xa616, 0x0, 0x8, 0xff},
+ {0xa617, 0x0, 0x8, 0xad},
+ {0xa618, 0x0, 0x8, 0xad},
+ {0xa61e, 0x3, 0x1, 0x1},
+ {0xae1a, 0x0, 0x8, 0x0},
+ {0xae19, 0x0, 0x8, 0xc8},
+ {0xae18, 0x0, 0x8, 0x61},
+ {0xa140, 0x0, 0x8, 0x0},
+ {0xa141, 0x0, 0x8, 0xc8},
+ {0xa142, 0x0, 0x7, 0x61},
+ {0xa023, 0x0, 0x8, 0xff},
+ {0xa021, 0x0, 0x8, 0xad},
+ {0xa026, 0x0, 0x1, 0x0},
+ {0xa024, 0x0, 0x8, 0xff},
+ {0xa025, 0x0, 0x8, 0xff},
+ {0xa1c8, 0x0, 0x8, 0xf},
+ {0xa2bc, 0x1, 0x1, 0x0},
+ {0xa60c, 0x0, 0x4, 0x5},
+ {0xa60c, 0x4, 0x4, 0x6},
+ {0xa60d, 0x0, 0x8, 0xa},
+ {0xa371, 0x0, 0x1, 0x1},
+ {0xa366, 0x1, 0x3, 0x7},
+ {0xa338, 0x0, 0x8, 0x10},
+ {0xa339, 0x0, 0x6, 0x7},
+ {0xa33a, 0x0, 0x6, 0x1f},
+ {0xa33b, 0x0, 0x8, 0xf6},
+ {0xa33c, 0x3, 0x5, 0x4},
+ {0xa33d, 0x4, 0x4, 0x0},
+ {0xa33d, 0x1, 0x1, 0x1},
+ {0xa33d, 0x2, 0x1, 0x1},
+ {0xa33d, 0x3, 0x1, 0x1},
+ {0xa16d, 0x0, 0x4, 0xf},
+ {0xa161, 0x0, 0x5, 0x5},
+ {0xa162, 0x0, 0x4, 0x5},
+ {0xa165, 0x0, 0x8, 0xff},
+ {0xa166, 0x0, 0x8, 0x9c},
+ {0xa2c3, 0x0, 0x4, 0x5},
+ {0xa61a, 0x0, 0x6, 0xf},
+ {0xb200, 0x0, 0x8, 0xa1},
+ {0xb201, 0x0, 0x8, 0x7},
+ {0xa093, 0x0, 0x1, 0x0},
+ {0xa093, 0x1, 0x5, 0xf},
+ {0xa094, 0x0, 0x8, 0xff},
+ {0xa095, 0x0, 0x8, 0xf},
+ {0xa080, 0x2, 0x5, 0x3},
+ {0xa081, 0x0, 0x4, 0x0},
+ {0xa081, 0x4, 0x4, 0x9},
+ {0xa082, 0x0, 0x5, 0x1f},
+ {0xa08d, 0x0, 0x8, 0x1},
+ {0xa083, 0x0, 0x8, 0x32},
+ {0xa084, 0x0, 0x1, 0x0},
+ {0xa08e, 0x0, 0x8, 0x3},
+ {0xa085, 0x0, 0x8, 0x32},
+ {0xa086, 0x0, 0x3, 0x0},
+ {0xa087, 0x0, 0x8, 0x6e},
+ {0xa088, 0x0, 0x5, 0x15},
+ {0xa089, 0x0, 0x8, 0x0},
+ {0xa08a, 0x0, 0x5, 0x19},
+ {0xa08b, 0x0, 0x8, 0x92},
+ {0xa08c, 0x0, 0x5, 0x1c},
+ {0xa120, 0x0, 0x8, 0x0},
+ {0xa121, 0x0, 0x5, 0x10},
+ {0xa122, 0x0, 0x8, 0x0},
+ {0xa123, 0x0, 0x7, 0x40},
+ {0xa123, 0x7, 0x1, 0x0},
+ {0xa124, 0x0, 0x8, 0x13},
+ {0xa125, 0x0, 0x7, 0x10},
+ {0xa1c0, 0x0, 0x8, 0x0},
+ {0xa1c1, 0x0, 0x5, 0x4},
+ {0xa1c2, 0x0, 0x8, 0x0},
+ {0xa1c3, 0x0, 0x5, 0x10},
+ {0xa1c3, 0x5, 0x3, 0x0},
+ {0xa1c4, 0x0, 0x6, 0x0},
+ {0xa1c5, 0x0, 0x7, 0x10},
+ {0xa100, 0x0, 0x8, 0x0},
+ {0xa101, 0x0, 0x5, 0x10},
+ {0xa102, 0x0, 0x8, 0x0},
+ {0xa103, 0x0, 0x7, 0x40},
+ {0xa103, 0x7, 0x1, 0x0},
+ {0xa104, 0x0, 0x8, 0x18},
+ {0xa105, 0x0, 0x7, 0xa},
+ {0xa106, 0x0, 0x8, 0x20},
+ {0xa107, 0x0, 0x8, 0x40},
+ {0xa108, 0x0, 0x4, 0x0},
+ {0xa38c, 0x0, 0x8, 0xfc},
+ {0xa38d, 0x0, 0x8, 0x0},
+ {0xa38e, 0x0, 0x8, 0x7e},
+ {0xa38f, 0x0, 0x8, 0x0},
+ {0xa390, 0x0, 0x8, 0x2f},
+ {0xa60f, 0x5, 0x1, 0x1},
+ {0xa170, 0x0, 0x8, 0xdc},
+ {0xa171, 0x0, 0x2, 0x0},
+ {0xa2ae, 0x0, 0x1, 0x1},
+ {0xa2ae, 0x1, 0x1, 0x1},
+ {0xa392, 0x0, 0x1, 0x1},
+ {0xa391, 0x2, 0x1, 0x0},
+ {0xabc1, 0x0, 0x8, 0xff},
+ {0xabc2, 0x0, 0x8, 0x0},
+ {0xabc8, 0x0, 0x8, 0x8},
+ {0xabca, 0x0, 0x8, 0x10},
+ {0xabcb, 0x0, 0x1, 0x0},
+ {0xabc3, 0x5, 0x3, 0x7},
+ {0xabc0, 0x6, 0x1, 0x0},
+ {0xabc0, 0x4, 0x2, 0x0},
+ {0xa344, 0x4, 0x4, 0x1},
+ {0xabc0, 0x7, 0x1, 0x1},
+ {0xabc0, 0x2, 0x1, 0x1},
+ {0xa345, 0x0, 0x8, 0x66},
+ {0xa346, 0x0, 0x8, 0x66},
+ {0xa347, 0x0, 0x4, 0x0},
+ {0xa343, 0x0, 0x4, 0xa},
+ {0xa347, 0x4, 0x4, 0x2},
+ {0xa348, 0x0, 0x4, 0xc},
+ {0xa348, 0x4, 0x4, 0x7},
+ {0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644
index 0000000..7db6eee
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+ DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+ int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+ u8 sequence;
+ int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+ u8 * rbuf, u16 rlen, int delay_ms)
+{
+ int actlen, ret = -ENOMEM;
+
+ if (wbuf == NULL || wlen == 0)
+ return -EINVAL;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ deb_xfer(">>> ");
+ debug_dump(wbuf, wlen, deb_xfer);
+
+ ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+ 2), wbuf, wlen,
+ &actlen, 2000);
+
+ if (ret)
+ err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+ else
+ ret = actlen != wlen ? -1 : 0;
+
+ /* an answer is expected, and no error before */
+ if (!ret && rbuf && rlen) {
+ if (delay_ms)
+ msleep(delay_ms);
+
+ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+ 0x01), rbuf,
+ rlen, &actlen, 2000);
+
+ if (ret)
+ err("recv bulk message failed: %d", ret);
+ else {
+ deb_xfer("<<< ");
+ debug_dump(rbuf, actlen, deb_xfer);
+ }
+ }
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+ return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+ int readwrite, int type, u8 * values, int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16] = { 0 };
+ u8 ibuf[17] = { 0 };
+ u8 command;
+ int i;
+ int ret;
+
+ if (len < 1) {
+ err("generic read/write, less than 1 byte. Makes no sense.");
+ return -EINVAL;
+ }
+ if (len > 8) {
+ err("generic read/write, more than 8 bytes. Not supported.");
+ return -EINVAL;
+ }
+
+ obuf[0] = 14; /* rest of buffer length low */
+ obuf[1] = 0; /* rest of buffer length high */
+
+ obuf[2] = AF9005_REGISTER_RW; /* register operation */
+ obuf[3] = 12; /* rest of buffer length */
+
+ obuf[4] = st->sequence++; /* sequence number */
+
+ obuf[5] = (u8) (reg >> 8); /* register address */
+ obuf[6] = (u8) (reg & 0xff);
+
+ if (type == AF9005_OFDM_REG) {
+ command = AF9005_CMD_OFDM_REG;
+ } else {
+ command = AF9005_CMD_TUNER;
+ }
+
+ if (len > 1)
+ command |=
+ AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+ command |= readwrite;
+ if (readwrite == AF9005_CMD_WRITE)
+ for (i = 0; i < len; i++)
+ obuf[8 + i] = values[i];
+ else if (type == AF9005_TUNER_REG)
+ /* read command for tuner, the first byte contains the i2c address */
+ obuf[8] = values[0];
+ obuf[7] = command;
+
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+ if (ret)
+ return ret;
+
+ /* sanity check */
+ if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+ err("generic read/write, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[3] != 0x0d) {
+ err("generic read/write, wrong length in reply.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("generic read/write, wrong sequence in reply.");
+ return -EIO;
+ }
+ /*
+ Windows driver doesn't check these fields, in fact sometimes
+ the register in the reply is different that what has been sent
+
+ if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+ err("generic read/write, wrong register in reply.");
+ return -EIO;
+ }
+ if (ibuf[7] != command) {
+ err("generic read/write wrong command in reply.");
+ return -EIO;
+ }
+ */
+ if (ibuf[16] != 0x01) {
+ err("generic read/write wrong status code in reply.");
+ return -EIO;
+ }
+ if (readwrite == AF9005_CMD_READ)
+ for (i = 0; i < len; i++)
+ values[i] = ibuf[8 + i];
+
+ return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+ int ret;
+ deb_reg("read register %x ", reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ value, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("value %x\n", *value);
+ return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("read %d registers %x ", len, reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ debug_dump(values, len, deb_reg);
+ return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+ int ret;
+ u8 temp = value;
+ deb_reg("write register %x value %x ", reg, value);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ &temp, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("write %d registers %x values ", len, reg);
+ debug_dump(values, len, deb_reg);
+
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 * value)
+{
+ u8 temp;
+ int ret;
+ deb_reg("read bits %x %x %x", reg, pos, len);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret) {
+ deb_reg(" failed\n");
+ return ret;
+ }
+ *value = (temp >> pos) & regmask[len - 1];
+ deb_reg(" value %x\n", *value);
+ return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 value)
+{
+ u8 temp, mask;
+ int ret;
+ deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+ if (pos == 0 && len == 8)
+ return af9005_write_ofdm_register(d, reg, value);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret)
+ return ret;
+ mask = regmask[len - 1] << pos;
+ temp = (temp & ~mask) | ((value << pos) & mask);
+ return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_TUNER_REG,
+ values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE,
+ AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i, done = 0, fail = 0;
+ u8 temp;
+ ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+ if (ret)
+ return ret;
+ if (reg != 0xffff) {
+ /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+ for (i = 0; i < 200; i++) {
+ ret =
+ af9005_read_ofdm_register(d,
+ xd_I2C_i2c_m_status_wdat_done,
+ &temp);
+ if (ret)
+ return ret;
+ done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+ << i2c_m_status_wdat_done_pos);
+ if (done)
+ break;
+ fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+ << i2c_m_status_wdat_fail_pos);
+ if (fail)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+ if (fail) {
+ /* clear write fail bit */
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_fail_pos,
+ i2c_m_status_wdat_fail_len,
+ 1);
+ return -EIO;
+ }
+ /* clear write done bit */
+ ret =
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_done_pos,
+ i2c_m_status_wdat_done_len, 1);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i;
+ u8 temp, buf[2];
+
+ buf[0] = addr; /* tuner i2c address */
+ buf[1] = values[0]; /* tuner register */
+
+ values[0] = addr + 0x01; /* i2c read address */
+
+ if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+ /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+ ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+ if (ret)
+ return ret;
+ }
+
+ /* send read command to ofsm */
+ ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+ if (ret)
+ return ret;
+
+ /* check if read done */
+ for (i = 0; i < 200; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+ if (ret)
+ return ret;
+ if (temp & 0x01)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+
+ /* clear read done bit (by writing 1) */
+ ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+ if (ret)
+ return ret;
+
+ /* get read data (available from 0xa400) */
+ for (i = 0; i < len; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+ if (ret)
+ return ret;
+ values[i] = temp;
+ }
+ return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 buf[3];
+ deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+ reg, len);
+ debug_dump(data, len, deb_i2c);
+
+ for (i = 0; i < len; i++) {
+ buf[0] = i2caddr;
+ buf[1] = reg + (u8) i;
+ buf[2] = data[i];
+ ret =
+ af9005_write_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ buf, 3);
+ if (ret) {
+ deb_i2c("i2c_write failed\n");
+ return ret;
+ }
+ }
+ deb_i2c("i2c_write ok\n");
+ return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 temp;
+ deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+ for (i = 0; i < len; i++) {
+ temp = reg + i;
+ ret =
+ af9005_read_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ i2caddr, &temp, 1);
+ if (ret) {
+ deb_i2c("i2c_read failed\n");
+ return ret;
+ }
+ data[i] = temp;
+ }
+ deb_i2c("i2c data read: ");
+ debug_dump(data, len, deb_i2c);
+ return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ /* only implements what the mt2060 module does, don't know how
+ to make it really generic */
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
+ u8 reg, addr;
+ u8 *value;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ if (num == 2) {
+ /* reads a single register */
+ reg = *msg[0].buf;
+ addr = msg[0].addr;
+ value = msg[1].buf;
+ ret = af9005_i2c_read(d, addr, reg, value, 1);
+ if (ret == 0)
+ ret = 2;
+ } else {
+ /* write one or more registers */
+ reg = msg[0].buf[0];
+ addr = msg[0].addr;
+ value = &msg[0].buf[1];
+ ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+ if (ret == 0)
+ ret = 1;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+ .master_xfer = af9005_i2c_xfer,
+ .functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+ int wlen, u8 * rbuf, int rlen)
+{
+ struct af9005_device_state *st = d->priv;
+
+ int ret, i, packet_len;
+ u8 buf[64];
+ u8 ibuf[64];
+
+ if (wlen < 0) {
+ err("send command, wlen less than 0 bytes. Makes no sense.");
+ return -EINVAL;
+ }
+ if (wlen > 54) {
+ err("send command, wlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ if (rlen > 54) {
+ err("send command, rlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ packet_len = wlen + 5;
+ buf[0] = (u8) (packet_len & 0xff);
+ buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+ buf[2] = 0x26; /* packet type */
+ buf[3] = wlen + 3;
+ buf[4] = st->sequence++;
+ buf[5] = command;
+ buf[6] = wlen;
+ for (i = 0; i < wlen; i++)
+ buf[7 + i] = wbuf[i];
+ ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x27) {
+ err("send command, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[4] != buf[4]) {
+ err("send command, wrong sequence in reply.");
+ return -EIO;
+ }
+ if (ibuf[5] != 0x01) {
+ err("send command, wrong status code in reply.");
+ return -EIO;
+ }
+ if (ibuf[6] != rlen) {
+ err("send command, invalid data length in reply.");
+ return -EIO;
+ }
+ for (i = 0; i < rlen; i++)
+ rbuf[i] = ibuf[i + 7];
+ return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+ int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16], ibuf[14];
+ int ret, i;
+
+ memset(obuf, 0, sizeof(obuf));
+ memset(ibuf, 0, sizeof(ibuf));
+
+ obuf[0] = 14; /* length of rest of packet low */
+ obuf[1] = 0; /* length of rest of packer high */
+
+ obuf[2] = 0x2a; /* read/write eeprom */
+
+ obuf[3] = 12; /* size */
+
+ obuf[4] = st->sequence++;
+
+ obuf[5] = 0; /* read */
+
+ obuf[6] = len;
+ obuf[7] = address;
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x2b) {
+ err("Read eeprom, invalid reply code");
+ return -EIO;
+ }
+ if (ibuf[3] != 10) {
+ err("Read eeprom, invalid reply length");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("Read eeprom, wrong sequence in reply ");
+ return -EIO;
+ }
+ if (ibuf[5] != 1) {
+ err("Read eeprom, wrong status in reply ");
+ return -EIO;
+ }
+ for (i = 0; i < len; i++) {
+ values[i] = ibuf[6 + i];
+ }
+ return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u16 checksum;
+ int act_len, i, ret;
+ memset(buf, 0, sizeof(buf));
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ switch (type) {
+ case FW_CONFIG:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x03;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_CONFIRM:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x01;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_BOOT:
+ buf[2] = 0x10;
+ buf[3] = 0x08;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x97;
+ buf[6] = 0xaa;
+ buf[7] = 0x55;
+ buf[8] = 0xa5;
+ buf[9] = 0x5a;
+ checksum = 0;
+ for (i = 4; i <= 9; i++)
+ checksum += buf[i];
+ buf[10] = (u8) ((checksum >> 8) & 0xff);
+ buf[11] = (u8) (checksum & 0xff);
+ break;
+ default:
+ err("boot packet invalid boot packet type");
+ return -EINVAL;
+ }
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+ if (ret)
+ err("boot packet bulk message failed: %d (%d/%d)", ret,
+ FW_BULKOUT_SIZE + 2, act_len);
+ else
+ ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+ if (ret)
+ return ret;
+ memset(buf, 0, 9);
+ ret = usb_bulk_msg(udev,
+ usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+ if (ret) {
+ err("boot packet recv bulk message failed: %d", ret);
+ return ret;
+ }
+ deb_fw("<<< ");
+ debug_dump(buf, act_len, deb_fw);
+ checksum = 0;
+ switch (type) {
+ case FW_CONFIG:
+ if (buf[2] != 0x11) {
+ err("boot bad config header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad config size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad config sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x04) {
+ err("boot bad config subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad config checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_CONFIRM:
+ if (buf[2] != 0x11) {
+ err("boot bad confirm header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad confirm size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad confirm sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x02) {
+ err("boot bad confirm subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad confirm checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_BOOT:
+ if (buf[2] != 0x10) {
+ err("boot bad boot header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad boot size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad boot sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x01) {
+ err("boot bad boot pattern 01.");
+ return -EIO;
+ }
+ if (buf[6] != 0x10) {
+ err("boot bad boot pattern 10.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad boot checksum.");
+ return -EIO;
+ }
+ break;
+
+ }
+
+ return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+ int i, packets, ret, act_len;
+
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u8 reply;
+
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x01) {
+ err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+ return -EIO;
+ }
+ packets = fw->size / FW_BULKOUT_SIZE;
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ for (i = 0; i < packets; i++) {
+ memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+ FW_BULKOUT_SIZE);
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+ if (ret) {
+ err("firmware download failed at packet %d with code %d", i, ret);
+ return ret;
+ }
+ }
+ ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+ if (ret)
+ return ret;
+ if (reply != (u8) (packets & 0xff)) {
+ err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+ return -EIO;
+ }
+ ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+ if (ret)
+ return ret;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x02) {
+ err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+ return -EIO;
+ }
+
+ return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+ struct af9005_device_state *st = d->priv;
+ int temp, ret;
+
+ if (onoff && dvb_usb_af9005_led)
+ temp = 1;
+ else
+ temp = 0;
+ if (st->led_state != temp) {
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_locken1,
+ reg_top_locken1_pos,
+ reg_top_locken1_len, temp);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_lock1,
+ reg_top_lock1_pos,
+ reg_top_lock1_len, temp);
+ if (ret)
+ return ret;
+ st->led_state = temp;
+ }
+ return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ u8 buf[8];
+ int i;
+
+ /* without these calls the first commands after downloading
+ the firmware fail. I put these calls here to simulate
+ what it is done in dvb-usb-init.c.
+ */
+ struct usb_device *udev = adap->dev->udev;
+ usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+ if (dvb_usb_af9005_dump_eeprom) {
+ printk("EEPROM DUMP\n");
+ for (i = 0; i < 255; i += 8) {
+ af9005_read_eeprom(adap->dev, i, buf, 8);
+ printk("ADDR %x ", i);
+ debug_dump(buf, 8, printk);
+ }
+ }
+ adap->fe = af9005_fe_attach(adap->dev);
+ return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+ struct af9005_device_state *st = d->priv;
+ int ret, len;
+
+ u8 obuf[5];
+ u8 ibuf[256];
+
+ *state = REMOTE_NO_KEY_PRESSED;
+ if (rc_decode == NULL) {
+ /* it shouldn't never come here */
+ return 0;
+ }
+ /* deb_info("rc_query\n"); */
+ obuf[0] = 3; /* rest of packet length low */
+ obuf[1] = 0; /* rest of packet lentgh high */
+ obuf[2] = 0x40; /* read remote */
+ obuf[3] = 1; /* rest of packet length */
+ obuf[4] = st->sequence++; /* sequence number */
+ ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+ if (ret) {
+ err("rc query failed");
+ return ret;
+ }
+ if (ibuf[2] != 0x41) {
+ err("rc query bad header.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("rc query bad sequence.");
+ return -EIO;
+ }
+ len = ibuf[5];
+ if (len > 246) {
+ err("rc query invalid length");
+ return -EIO;
+ }
+ if (len > 0) {
+ deb_rc("rc data (%d) ", len);
+ debug_dump((ibuf + 6), len, deb_rc);
+ ret = rc_decode(d, &ibuf[6], len, event, state);
+ if (ret) {
+ err("rc_decode failed");
+ return ret;
+ } else {
+ deb_rc("rc_decode state %x event %x\n", *state, *event);
+ if (*state == REMOTE_KEY_REPEAT)
+ *event = d->last_event;
+ }
+ }
+ return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+ return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ deb_info("pid filter control onoff %d\n", onoff);
+ if (onoff) {
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(adap->dev,
+ XD_MP2IF_DMX_CTRL, 1, 1, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ } else
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+ if (ret)
+ return ret;
+ deb_info("pid filter control ok\n");
+ return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+ u16 pid, int onoff)
+{
+ u8 cmd = index & 0x1f;
+ int ret;
+ deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+ pid, onoff);
+ if (onoff) {
+ /* cannot use it as pid_filter_ctrl since it has to be done
+ before setting the first pid */
+ if (adap->feedcount == 1) {
+ deb_info("first pid set, enable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_L,
+ (u8) (pid & 0xff));
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_H,
+ (u8) (pid >> 8));
+ if (ret)
+ return ret;
+ cmd |= 0x20 | 0x40;
+ } else {
+ if (adap->feedcount == 0) {
+ deb_info("last pid unset, disable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ }
+ ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+ if (ret)
+ return ret;
+ deb_info("set pid ok\n");
+ return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ int ret;
+ u8 reply;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ deb_info("result of FW_CONFIG in identify state %d\n", reply);
+ if (reply == 0x01)
+ *cold = 1;
+ else if (reply == 0x02)
+ *cold = 0;
+ else
+ return -EIO;
+ deb_info("Identify state cold = %d\n", *cold);
+ return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+ {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "af9005.fw",
+ .download_firmware = af9005_download_firmware,
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct af9005_device_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps =
+ DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = af9005_pid_filter,
+ /* .pid_filter_ctrl = af9005_pid_filter_control, */
+ .frontend_attach = af9005_frontend_attach,
+ /* .tuner_attach = af9005_tuner_attach, */
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 4096, /* actual size seen is 3948 */
+ }
+ }
+ },
+ }
+ },
+ .power_ctrl = af9005_power_ctrl,
+ .identify_state = af9005_identify_state,
+
+ .i2c_algo = &af9005_i2c_algo,
+
+ .rc_interval = 200,
+ .rc_key_map = NULL,
+ .rc_key_map_size = 0,
+ .rc_query = af9005_rc_query,
+
+ .num_device_descs = 2,
+ .devices = {
+ {.name = "Afatech DVB-T USB1.1 stick",
+ .cold_ids = {&af9005_usb_table[0], NULL},
+ .warm_ids = {NULL},
+ },
+ {.name = "TerraTec Cinergy T USB XE",
+ .cold_ids = {&af9005_usb_table[1], NULL},
+ .warm_ids = {NULL},
+ },
+ {NULL},
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+ .name = "dvb_usb_af9005",
+ .probe = af9005_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&af9005_usb_driver))) {
+ err("usb_register failed. (%d)", result);
+ return result;
+ }
+ rc_decode = symbol_request(af9005_rc_decode);
+ rc_keys = symbol_request(af9005_rc_keys);
+ rc_keys_size = symbol_request(af9005_rc_keys_size);
+ if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+ err("af9005_rc_decode function not found, disabling remote");
+ af9005_properties.rc_query = NULL;
+ } else {
+ af9005_properties.rc_key_map = rc_keys;
+ af9005_properties.rc_key_map_size = *rc_keys_size;
+ }
+
+ return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+ /* release rc decode symbols */
+ if (rc_decode != NULL)
+ symbol_put(af9005_rc_decode);
+ if (rc_keys != NULL)
+ symbol_put(af9005_rc_keys);
+ if (rc_keys_size != NULL)
+ symbol_put(af9005_rc_keys_size);
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644
index 0000000..0bc48a0
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+ FW_CONFIG,
+ FW_CONFIRM,
+ FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG 0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW 0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER 0x80
+#define AF9005_CMD_BURST 0x02
+#define AF9005_CMD_AUTOINC 0x04
+#define AF9005_CMD_READ 0x00
+#define AF9005_CMD_WRITE 0x01
+
+/* af9005 registers */
+#define APO_REG_RESET 0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER 0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER 0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */
+#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */
+
+/***********************************************************************
+ * Apollo Registers from VLSI *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc 0xA000
+#define reg_aagc_inverted_agc_pos 0
+#define reg_aagc_inverted_agc_len 1
+#define reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only 0xA000
+#define reg_aagc_sign_only_pos 1
+#define reg_aagc_sign_only_len 1
+#define reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en 0xA000
+#define reg_aagc_slow_adc_en_pos 2
+#define reg_aagc_slow_adc_en_len 1
+#define reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale 0xA000
+#define reg_aagc_slow_adc_scale_pos 3
+#define reg_aagc_slow_adc_scale_len 5
+#define reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock 0xA001
+#define reg_aagc_check_slow_adc_lock_pos 0
+#define reg_aagc_check_slow_adc_lock_len 1
+#define reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control 0xA001
+#define reg_aagc_init_control_pos 1
+#define reg_aagc_init_control_len 1
+#define reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel 0xA001
+#define reg_aagc_total_gain_sel_pos 2
+#define reg_aagc_total_gain_sel_len 2
+#define reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv 0xA001
+#define reg_aagc_out_inv_pos 5
+#define reg_aagc_out_inv_len 1
+#define reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en 0xA001
+#define reg_aagc_int_en_pos 6
+#define reg_aagc_int_en_len 1
+#define reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag 0xA001
+#define reg_aagc_lock_change_flag_pos 7
+#define reg_aagc_lock_change_flag_len 1
+#define reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002
+#define reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003
+#define reg_aagc_rf_loop_bw_scale_track_pos 0
+#define reg_aagc_rf_loop_bw_scale_track_len 5
+#define reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004
+#define reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define reg_aagc_if_loop_bw_scale_acquire_len 5
+#define reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005
+#define reg_aagc_if_loop_bw_scale_track_pos 0
+#define reg_aagc_if_loop_bw_scale_track_len 5
+#define reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006
+#define reg_aagc_max_rf_agc_7_0_pos 0
+#define reg_aagc_max_rf_agc_7_0_len 8
+#define reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007
+#define reg_aagc_max_rf_agc_9_8_pos 0
+#define reg_aagc_max_rf_agc_9_8_len 2
+#define reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008
+#define reg_aagc_min_rf_agc_7_0_pos 0
+#define reg_aagc_min_rf_agc_7_0_len 8
+#define reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009
+#define reg_aagc_min_rf_agc_9_8_pos 0
+#define reg_aagc_min_rf_agc_9_8_len 2
+#define reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A
+#define reg_aagc_max_if_agc_7_0_pos 0
+#define reg_aagc_max_if_agc_7_0_len 8
+#define reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B
+#define reg_aagc_max_if_agc_9_8_pos 0
+#define reg_aagc_max_if_agc_9_8_len 2
+#define reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C
+#define reg_aagc_min_if_agc_7_0_pos 0
+#define reg_aagc_min_if_agc_7_0_len 8
+#define reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D
+#define reg_aagc_min_if_agc_9_8_pos 0
+#define reg_aagc_min_if_agc_9_8_len 2
+#define reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale 0xA00E
+#define reg_aagc_lock_sample_scale_pos 0
+#define reg_aagc_lock_sample_scale_len 5
+#define reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F
+#define reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F
+#define reg_aagc_rf_agc_lock_scale_track_pos 3
+#define reg_aagc_rf_agc_lock_scale_track_len 3
+#define reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010
+#define reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define reg_aagc_if_agc_lock_scale_acquire_len 3
+#define reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010
+#define reg_aagc_if_agc_lock_scale_track_pos 3
+#define reg_aagc_if_agc_lock_scale_track_len 3
+#define reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011
+#define reg_aagc_rf_top_numerator_7_0_pos 0
+#define reg_aagc_rf_top_numerator_7_0_len 8
+#define reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012
+#define reg_aagc_rf_top_numerator_9_8_pos 0
+#define reg_aagc_rf_top_numerator_9_8_len 2
+#define reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013
+#define reg_aagc_if_top_numerator_7_0_pos 0
+#define reg_aagc_if_top_numerator_7_0_len 8
+#define reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014
+#define reg_aagc_if_top_numerator_9_8_pos 0
+#define reg_aagc_if_top_numerator_9_8_len 2
+#define reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015
+#define reg_aagc_adc_out_desired_7_0_pos 0
+#define reg_aagc_adc_out_desired_7_0_len 8
+#define reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8 0xA016
+#define reg_aagc_adc_out_desired_8_pos 0
+#define reg_aagc_adc_out_desired_8_len 1
+#define reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain 0xA016
+#define reg_aagc_fixed_gain_pos 3
+#define reg_aagc_fixed_gain_len 1
+#define reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th 0xA016
+#define reg_aagc_lock_count_th_pos 4
+#define reg_aagc_lock_count_th_len 4
+#define reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017
+#define reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018
+#define reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019
+#define reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A
+#define reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B
+#define reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define reg_aagc_fixed_if_agc_control_7_0_len 8
+#define reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C
+#define reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define reg_aagc_fixed_if_agc_control_15_8_len 8
+#define reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D
+#define reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define reg_aagc_fixed_if_agc_control_23_16_len 8
+#define reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E
+#define reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define reg_aagc_fixed_if_agc_control_30_24_len 7
+#define reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F
+#define reg_aagc_rf_agc_unlock_numerator_pos 0
+#define reg_aagc_rf_agc_unlock_numerator_len 6
+#define reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020
+#define reg_aagc_if_agc_unlock_numerator_pos 0
+#define reg_aagc_if_agc_unlock_numerator_len 6
+#define reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th 0xA021
+#define reg_unplug_th_pos 0
+#define reg_unplug_th_len 8
+#define reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define reg_weak_signal_rfagc_thr_pos 0
+#define reg_weak_signal_rfagc_thr_len 8
+#define reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define reg_unplug_rf_gain_th_pos 0
+#define reg_unplug_rf_gain_th_len 8
+#define reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define reg_unplug_dtop_rf_gain_th_pos 0
+#define reg_unplug_dtop_rf_gain_th_len 8
+#define reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define reg_unplug_dtop_if_gain_th_pos 0
+#define reg_unplug_dtop_if_gain_th_len 8
+#define reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define reg_top_recover_at_unplug_en_pos 0
+#define reg_top_recover_at_unplug_en_len 1
+#define reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6 0xA027
+#define reg_aagc_rf_x6_pos 0
+#define reg_aagc_rf_x6_len 8
+#define reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7 0xA028
+#define reg_aagc_rf_x7_pos 0
+#define reg_aagc_rf_x7_len 8
+#define reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8 0xA029
+#define reg_aagc_rf_x8_pos 0
+#define reg_aagc_rf_x8_len 8
+#define reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9 0xA02A
+#define reg_aagc_rf_x9_pos 0
+#define reg_aagc_rf_x9_len 8
+#define reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10 0xA02B
+#define reg_aagc_rf_x10_pos 0
+#define reg_aagc_rf_x10_len 8
+#define reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11 0xA02C
+#define reg_aagc_rf_x11_pos 0
+#define reg_aagc_rf_x11_len 8
+#define reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12 0xA02D
+#define reg_aagc_rf_x12_pos 0
+#define reg_aagc_rf_x12_len 8
+#define reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13 0xA02E
+#define reg_aagc_rf_x13_pos 0
+#define reg_aagc_rf_x13_len 8
+#define reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0 0xA02F
+#define reg_aagc_if_x0_pos 0
+#define reg_aagc_if_x0_len 8
+#define reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1 0xA030
+#define reg_aagc_if_x1_pos 0
+#define reg_aagc_if_x1_len 8
+#define reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2 0xA031
+#define reg_aagc_if_x2_pos 0
+#define reg_aagc_if_x2_len 8
+#define reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3 0xA032
+#define reg_aagc_if_x3_pos 0
+#define reg_aagc_if_x3_len 8
+#define reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4 0xA033
+#define reg_aagc_if_x4_pos 0
+#define reg_aagc_if_x4_len 8
+#define reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5 0xA034
+#define reg_aagc_if_x5_pos 0
+#define reg_aagc_if_x5_len 8
+#define reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6 0xA035
+#define reg_aagc_if_x6_pos 0
+#define reg_aagc_if_x6_len 8
+#define reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7 0xA036
+#define reg_aagc_if_x7_pos 0
+#define reg_aagc_if_x7_len 8
+#define reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8 0xA037
+#define reg_aagc_if_x8_pos 0
+#define reg_aagc_if_x8_len 8
+#define reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9 0xA038
+#define reg_aagc_if_x9_pos 0
+#define reg_aagc_if_x9_len 8
+#define reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10 0xA039
+#define reg_aagc_if_x10_pos 0
+#define reg_aagc_if_x10_len 8
+#define reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11 0xA03A
+#define reg_aagc_if_x11_pos 0
+#define reg_aagc_if_x11_len 8
+#define reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12 0xA03B
+#define reg_aagc_if_x12_pos 0
+#define reg_aagc_if_x12_len 8
+#define reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13 0xA03C
+#define reg_aagc_if_x13_pos 0
+#define reg_aagc_if_x13_len 8
+#define reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D
+#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E
+#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0 0xA070
+#define reg_aagc_total_gain_7_0_pos 0
+#define reg_aagc_total_gain_7_0_len 8
+#define reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8 0xA071
+#define reg_aagc_total_gain_15_8_pos 0
+#define reg_aagc_total_gain_15_8_len 8
+#define reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074
+#define reg_aagc_in_sat_cnt_7_0_pos 0
+#define reg_aagc_in_sat_cnt_7_0_len 8
+#define reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075
+#define reg_aagc_in_sat_cnt_15_8_pos 0
+#define reg_aagc_in_sat_cnt_15_8_len 8
+#define reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076
+#define reg_aagc_in_sat_cnt_23_16_pos 0
+#define reg_aagc_in_sat_cnt_23_16_len 8
+#define reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077
+#define reg_aagc_in_sat_cnt_31_24_pos 0
+#define reg_aagc_in_sat_cnt_31_24_len 8
+#define reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078
+#define reg_aagc_digital_rf_volt_7_0_pos 0
+#define reg_aagc_digital_rf_volt_7_0_len 8
+#define reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079
+#define reg_aagc_digital_rf_volt_9_8_pos 0
+#define reg_aagc_digital_rf_volt_9_8_len 2
+#define reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A
+#define reg_aagc_digital_if_volt_7_0_pos 0
+#define reg_aagc_digital_if_volt_7_0_len 8
+#define reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B
+#define reg_aagc_digital_if_volt_9_8_pos 0
+#define reg_aagc_digital_if_volt_9_8_len 2
+#define reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain 0xA07C
+#define reg_aagc_rf_gain_pos 0
+#define reg_aagc_rf_gain_len 8
+#define reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain 0xA07D
+#define reg_aagc_if_gain_pos 0
+#define reg_aagc_if_gain_len 8
+#define reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator 0xA080
+#define tinr_imp_indicator_pos 0
+#define tinr_imp_indicator_len 2
+#define tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size 0xA080
+#define reg_tinr_fifo_size_pos 2
+#define reg_tinr_fifo_size_len 5
+#define reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th 0xA081
+#define reg_tinr_saturation_cnt_th_pos 0
+#define reg_tinr_saturation_cnt_th_len 4
+#define reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0 0xA081
+#define reg_tinr_saturation_th_3_0_pos 4
+#define reg_tinr_saturation_th_3_0_len 4
+#define reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4 0xA082
+#define reg_tinr_saturation_th_8_4_pos 0
+#define reg_tinr_saturation_th_8_4_len 5
+#define reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083
+#define reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define reg_tinr_imp_duration_th_2k_7_0_len 8
+#define reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084
+#define reg_tinr_imp_duration_th_2k_8_pos 0
+#define reg_tinr_imp_duration_th_2k_8_len 1
+#define reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085
+#define reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define reg_tinr_imp_duration_th_8k_7_0_len 8
+#define reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086
+#define reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define reg_tinr_imp_duration_th_8k_10_8_len 3
+#define reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087
+#define reg_tinr_freq_ratio_6m_7_0_pos 0
+#define reg_tinr_freq_ratio_6m_7_0_len 8
+#define reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088
+#define reg_tinr_freq_ratio_6m_12_8_pos 0
+#define reg_tinr_freq_ratio_6m_12_8_len 5
+#define reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089
+#define reg_tinr_freq_ratio_7m_7_0_pos 0
+#define reg_tinr_freq_ratio_7m_7_0_len 8
+#define reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A
+#define reg_tinr_freq_ratio_7m_12_8_pos 0
+#define reg_tinr_freq_ratio_7m_12_8_len 5
+#define reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B
+#define reg_tinr_freq_ratio_8m_7_0_pos 0
+#define reg_tinr_freq_ratio_8m_7_0_len 8
+#define reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C
+#define reg_tinr_freq_ratio_8m_12_8_pos 0
+#define reg_tinr_freq_ratio_8m_12_8_len 5
+#define reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D
+#define reg_tinr_imp_duration_th_low_2k_pos 0
+#define reg_tinr_imp_duration_th_low_2k_len 8
+#define reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E
+#define reg_tinr_imp_duration_th_low_8k_pos 0
+#define reg_tinr_imp_duration_th_low_8k_len 8
+#define reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0 0xA090
+#define reg_tinr_counter_7_0_pos 0
+#define reg_tinr_counter_7_0_len 8
+#define reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8 0xA091
+#define reg_tinr_counter_15_8_pos 0
+#define reg_tinr_counter_15_8_len 8
+#define reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en 0xA093
+#define reg_tinr_adative_tinr_en_pos 0
+#define reg_tinr_adative_tinr_en_len 1
+#define reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size 0xA093
+#define reg_tinr_peak_fifo_size_pos 1
+#define reg_tinr_peak_fifo_size_len 5
+#define reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst 0xA093
+#define reg_tinr_counter_rst_pos 6
+#define reg_tinr_counter_rst_len 1
+#define reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0 0xA094
+#define reg_tinr_search_period_7_0_pos 0
+#define reg_tinr_search_period_7_0_len 8
+#define reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8 0xA095
+#define reg_tinr_search_period_15_8_pos 0
+#define reg_tinr_search_period_15_8_len 8
+#define reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0 0xA0A0
+#define reg_ccifs_fcw_7_0_pos 0
+#define reg_ccifs_fcw_7_0_len 8
+#define reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8 0xA0A1
+#define reg_ccifs_fcw_12_8_pos 0
+#define reg_ccifs_fcw_12_8_len 5
+#define reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv 0xA0A1
+#define reg_ccifs_spec_inv_pos 5
+#define reg_ccifs_spec_inv_len 1
+#define reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger 0xA0A2
+#define reg_gp_trigger_pos 0
+#define reg_gp_trigger_len 1
+#define reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel 0xA0A2
+#define reg_trigger_sel_pos 1
+#define reg_trigger_sel_len 2
+#define reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm 0xA0A2
+#define reg_debug_ofdm_pos 3
+#define reg_debug_ofdm_len 2
+#define reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel 0xA0A3
+#define reg_trigger_module_sel_pos 0
+#define reg_trigger_module_sel_len 6
+#define reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel 0xA0A4
+#define reg_trigger_set_sel_pos 0
+#define reg_trigger_set_sel_len 6
+#define reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n 0xA0A4
+#define reg_fw_int_mask_n_pos 6
+#define reg_fw_int_mask_n_len 1
+#define reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group 0xA0A5
+#define reg_debug_group_pos 0
+#define reg_debug_group_len 4
+#define reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel 0xA0A5
+#define reg_odbg_clk_sel_pos 4
+#define reg_odbg_clk_sel_len 2
+#define reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc 0xA0C0
+#define reg_ccif_sc_pos 0
+#define reg_ccif_sc_len 4
+#define reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate 0xA0C1
+#define reg_ccif_saturate_pos 0
+#define reg_ccif_saturate_len 2
+#define reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate 0xA0C1
+#define reg_antif_saturate_pos 2
+#define reg_antif_saturate_len 4
+#define reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate 0xA0C2
+#define reg_acif_saturate_pos 0
+#define reg_acif_saturate_len 8
+#define reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8
+#define reg_tmr_timer0_threshold_7_0_pos 0
+#define reg_tmr_timer0_threshold_7_0_len 8
+#define reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9
+#define reg_tmr_timer0_threshold_15_8_pos 0
+#define reg_tmr_timer0_threshold_15_8_len 8
+#define reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable 0xA0CA
+#define reg_tmr_timer0_enable_pos 0
+#define reg_tmr_timer0_enable_len 1
+#define reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA
+#define reg_tmr_timer0_clk_sel_pos 1
+#define reg_tmr_timer0_clk_sel_len 1
+#define reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int 0xA0CA
+#define reg_tmr_timer0_int_pos 2
+#define reg_tmr_timer0_int_len 1
+#define reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst 0xA0CA
+#define reg_tmr_timer0_rst_pos 3
+#define reg_tmr_timer0_rst_len 1
+#define reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB
+#define reg_tmr_timer0_count_7_0_pos 0
+#define reg_tmr_timer0_count_7_0_len 8
+#define reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC
+#define reg_tmr_timer0_count_15_8_pos 0
+#define reg_tmr_timer0_count_15_8_len 8
+#define reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend 0xA0CD
+#define reg_suspend_pos 0
+#define reg_suspend_len 1
+#define reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy 0xA0CD
+#define reg_suspend_rdy_pos 1
+#define reg_suspend_rdy_len 1
+#define reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume 0xA0CD
+#define reg_resume_pos 2
+#define reg_resume_len 1
+#define reg_resume_lsb 0
+#define xd_p_reg_resume_rdy 0xA0CD
+#define reg_resume_rdy_pos 3
+#define reg_resume_rdy_len 1
+#define reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf 0xA0CE
+#define reg_fmf_pos 0
+#define reg_fmf_len 8
+#define reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0 0xA100
+#define ccid_accumulate_num_2k_7_0_pos 0
+#define ccid_accumulate_num_2k_7_0_len 8
+#define ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8 0xA101
+#define ccid_accumulate_num_2k_12_8_pos 0
+#define ccid_accumulate_num_2k_12_8_len 5
+#define ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0 0xA102
+#define ccid_accumulate_num_8k_7_0_pos 0
+#define ccid_accumulate_num_8k_7_0_len 8
+#define ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8 0xA103
+#define ccid_accumulate_num_8k_14_8_pos 0
+#define ccid_accumulate_num_8k_14_8_len 7
+#define ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0 0xA103
+#define ccid_desired_level_0_pos 7
+#define ccid_desired_level_0_len 1
+#define ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1 0xA104
+#define ccid_desired_level_8_1_pos 0
+#define ccid_desired_level_8_1_len 8
+#define ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay 0xA105
+#define ccid_apply_delay_pos 0
+#define ccid_apply_delay_len 7
+#define ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1 0xA106
+#define ccid_CCID_Threshold1_pos 0
+#define ccid_CCID_Threshold1_len 8
+#define ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2 0xA107
+#define ccid_CCID_Threshold2_pos 0
+#define ccid_CCID_Threshold2_len 8
+#define ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale 0xA108
+#define reg_ccid_gain_scale_pos 0
+#define reg_ccid_gain_scale_len 4
+#define reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set 0xA108
+#define reg_ccid2_passband_gain_set_pos 4
+#define reg_ccid2_passband_gain_set_len 4
+#define reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0 0xA109
+#define ccid_multiplier_7_0_pos 0
+#define ccid_multiplier_7_0_len 8
+#define ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8 0xA10A
+#define ccid_multiplier_15_8_pos 0
+#define ccid_multiplier_15_8_len 8
+#define ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits 0xA10B
+#define ccid_right_shift_bits_pos 0
+#define ccid_right_shift_bits_len 4
+#define ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0 0xA10C
+#define reg_ccid_sx_7_0_pos 0
+#define reg_ccid_sx_7_0_len 8
+#define reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8 0xA10D
+#define reg_ccid_sx_15_8_pos 0
+#define reg_ccid_sx_15_8_len 8
+#define reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16 0xA10E
+#define reg_ccid_sx_21_16_pos 0
+#define reg_ccid_sx_21_16_len 6
+#define reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0 0xA110
+#define reg_ccid_sy_7_0_pos 0
+#define reg_ccid_sy_7_0_len 8
+#define reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8 0xA111
+#define reg_ccid_sy_15_8_pos 0
+#define reg_ccid_sy_15_8_len 8
+#define reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16 0xA112
+#define reg_ccid_sy_23_16_pos 0
+#define reg_ccid_sy_23_16_len 8
+#define reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0 0xA114
+#define reg_ccid2_sz_7_0_pos 0
+#define reg_ccid2_sz_7_0_len 8
+#define reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8 0xA115
+#define reg_ccid2_sz_15_8_pos 0
+#define reg_ccid2_sz_15_8_len 8
+#define reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16 0xA116
+#define reg_ccid2_sz_23_16_pos 0
+#define reg_ccid2_sz_23_16_len 8
+#define reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24 0xA117
+#define reg_ccid2_sz_25_24_pos 0
+#define reg_ccid2_sz_25_24_len 2
+#define reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0 0xA118
+#define reg_ccid2_sy_7_0_pos 0
+#define reg_ccid2_sy_7_0_len 8
+#define reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8 0xA119
+#define reg_ccid2_sy_15_8_pos 0
+#define reg_ccid2_sy_15_8_len 8
+#define reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16 0xA11A
+#define reg_ccid2_sy_23_16_pos 0
+#define reg_ccid2_sy_23_16_len 8
+#define reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24 0xA11B
+#define reg_ccid2_sy_25_24_pos 0
+#define reg_ccid2_sy_25_24_len 2
+#define reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120
+#define dagc1_accumulate_num_2k_7_0_pos 0
+#define dagc1_accumulate_num_2k_7_0_len 8
+#define dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121
+#define dagc1_accumulate_num_2k_12_8_pos 0
+#define dagc1_accumulate_num_2k_12_8_len 5
+#define dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122
+#define dagc1_accumulate_num_8k_7_0_pos 0
+#define dagc1_accumulate_num_8k_7_0_len 8
+#define dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123
+#define dagc1_accumulate_num_8k_14_8_pos 0
+#define dagc1_accumulate_num_8k_14_8_len 7
+#define dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0 0xA123
+#define dagc1_desired_level_0_pos 7
+#define dagc1_desired_level_0_len 1
+#define dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1 0xA124
+#define dagc1_desired_level_8_1_pos 0
+#define dagc1_desired_level_8_1_len 8
+#define dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay 0xA125
+#define dagc1_apply_delay_pos 0
+#define dagc1_apply_delay_len 7
+#define dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl 0xA126
+#define dagc1_bypass_scale_ctl_pos 0
+#define dagc1_bypass_scale_ctl_len 2
+#define dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127
+#define reg_dagc1_in_sat_cnt_7_0_pos 0
+#define reg_dagc1_in_sat_cnt_7_0_len 8
+#define reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128
+#define reg_dagc1_in_sat_cnt_15_8_pos 0
+#define reg_dagc1_in_sat_cnt_15_8_len 8
+#define reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129
+#define reg_dagc1_in_sat_cnt_23_16_pos 0
+#define reg_dagc1_in_sat_cnt_23_16_len 8
+#define reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A
+#define reg_dagc1_in_sat_cnt_31_24_pos 0
+#define reg_dagc1_in_sat_cnt_31_24_len 8
+#define reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B
+#define reg_dagc1_out_sat_cnt_7_0_pos 0
+#define reg_dagc1_out_sat_cnt_7_0_len 8
+#define reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C
+#define reg_dagc1_out_sat_cnt_15_8_pos 0
+#define reg_dagc1_out_sat_cnt_15_8_len 8
+#define reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D
+#define reg_dagc1_out_sat_cnt_23_16_pos 0
+#define reg_dagc1_out_sat_cnt_23_16_len 8
+#define reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E
+#define reg_dagc1_out_sat_cnt_31_24_pos 0
+#define reg_dagc1_out_sat_cnt_31_24_len 8
+#define reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0 0xA136
+#define dagc1_multiplier_7_0_pos 0
+#define dagc1_multiplier_7_0_len 8
+#define dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8 0xA137
+#define dagc1_multiplier_15_8_pos 0
+#define dagc1_multiplier_15_8_len 8
+#define dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits 0xA138
+#define dagc1_right_shift_bits_pos 0
+#define dagc1_right_shift_bits_len 4
+#define dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0 0xA140
+#define reg_bfs_fcw_7_0_pos 0
+#define reg_bfs_fcw_7_0_len 8
+#define reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8 0xA141
+#define reg_bfs_fcw_15_8_pos 0
+#define reg_bfs_fcw_15_8_len 8
+#define reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16 0xA142
+#define reg_bfs_fcw_22_16_pos 0
+#define reg_bfs_fcw_22_16_len 7
+#define reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0 0xA144
+#define reg_antif_sf_7_0_pos 0
+#define reg_antif_sf_7_0_len 8
+#define reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8 0xA145
+#define reg_antif_sf_11_8_pos 0
+#define reg_antif_sf_11_8_len 4
+#define reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0 0xA150
+#define bfs_fcw_q_7_0_pos 0
+#define bfs_fcw_q_7_0_len 8
+#define bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8 0xA151
+#define bfs_fcw_q_15_8_pos 0
+#define bfs_fcw_q_15_8_len 8
+#define bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16 0xA152
+#define bfs_fcw_q_22_16_pos 0
+#define bfs_fcw_q_22_16_len 7
+#define bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu 0xA160
+#define reg_dca_enu_pos 0
+#define reg_dca_enu_len 1
+#define reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl 0xA160
+#define reg_dca_enl_pos 1
+#define reg_dca_enl_len 1
+#define reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip 0xA160
+#define reg_dca_lower_chip_pos 2
+#define reg_dca_lower_chip_len 1
+#define reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip 0xA160
+#define reg_dca_upper_chip_pos 3
+#define reg_dca_upper_chip_len 1
+#define reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch 0xA160
+#define reg_dca_platch_pos 4
+#define reg_dca_platch_len 1
+#define reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th 0xA161
+#define reg_dca_th_pos 0
+#define reg_dca_th_len 5
+#define reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale 0xA162
+#define reg_dca_scale_pos 0
+#define reg_dca_scale_len 4
+#define reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0 0xA163
+#define reg_dca_tone_7_0_pos 0
+#define reg_dca_tone_7_0_len 8
+#define reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8 0xA164
+#define reg_dca_tone_12_8_pos 0
+#define reg_dca_tone_12_8_len 5
+#define reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0 0xA165
+#define reg_dca_time_7_0_pos 0
+#define reg_dca_time_7_0_len 8
+#define reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8 0xA166
+#define reg_dca_time_15_8_pos 0
+#define reg_dca_time_15_8_len 8
+#define reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm 0xA167
+#define dcasm_pos 0
+#define dcasm_len 3
+#define dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0 0xA168
+#define reg_qnt_valuew_7_0_pos 0
+#define reg_qnt_valuew_7_0_len 8
+#define reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8 0xA169
+#define reg_qnt_valuew_10_8_pos 0
+#define reg_qnt_valuew_10_8_len 3
+#define reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0 0xA16A
+#define dca_sbx_gain_diff_7_0_pos 0
+#define dca_sbx_gain_diff_7_0_len 8
+#define dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8 0xA16B
+#define dca_sbx_gain_diff_9_8_pos 0
+#define dca_sbx_gain_diff_9_8_len 2
+#define dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone 0xA16C
+#define reg_dca_stand_alone_pos 0
+#define reg_dca_stand_alone_len 1
+#define reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en 0xA16C
+#define reg_dca_upper_out_en_pos 1
+#define reg_dca_upper_out_en_len 1
+#define reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en 0xA16C
+#define reg_dca_rc_en_pos 2
+#define reg_dca_rc_en_len 1
+#define reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send 0xA16C
+#define reg_dca_retrain_send_pos 3
+#define reg_dca_retrain_send_len 1
+#define reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec 0xA16C
+#define reg_dca_retrain_rec_pos 4
+#define reg_dca_retrain_rec_len 1
+#define reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy 0xA16C
+#define reg_dca_api_tpsrdy_pos 5
+#define reg_dca_api_tpsrdy_len 1
+#define reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap 0xA16D
+#define reg_dca_symbol_gap_pos 0
+#define reg_dca_symbol_gap_len 4
+#define reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E
+#define reg_qnt_nfvaluew_7_0_pos 0
+#define reg_qnt_nfvaluew_7_0_len 8
+#define reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F
+#define reg_qnt_nfvaluew_10_8_pos 0
+#define reg_qnt_nfvaluew_10_8_len 3
+#define reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0 0xA170
+#define reg_qnt_flatness_thr_7_0_pos 0
+#define reg_qnt_flatness_thr_7_0_len 8
+#define reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8 0xA171
+#define reg_qnt_flatness_thr_9_8_pos 0
+#define reg_qnt_flatness_thr_9_8_len 2
+#define reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0 0xA171
+#define reg_dca_tone_idx_5_0_pos 2
+#define reg_dca_tone_idx_5_0_len 6
+#define reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6 0xA172
+#define reg_dca_tone_idx_12_6_pos 0
+#define reg_dca_tone_idx_12_6_len 7
+#define reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld 0xA173
+#define reg_dca_data_vld_pos 0
+#define reg_dca_data_vld_len 1
+#define reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update 0xA173
+#define reg_dca_read_update_pos 1
+#define reg_dca_read_update_len 1
+#define reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0 0xA173
+#define reg_dca_data_re_5_0_pos 2
+#define reg_dca_data_re_5_0_len 6
+#define reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6 0xA174
+#define reg_dca_data_re_10_6_pos 0
+#define reg_dca_data_re_10_6_len 5
+#define reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0 0xA175
+#define reg_dca_data_im_7_0_pos 0
+#define reg_dca_data_im_7_0_len 8
+#define reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8 0xA176
+#define reg_dca_data_im_10_8_pos 0
+#define reg_dca_data_im_10_8_len 3
+#define reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0 0xA178
+#define reg_dca_data_h2_7_0_pos 0
+#define reg_dca_data_h2_7_0_len 8
+#define reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8 0xA179
+#define reg_dca_data_h2_9_8_pos 0
+#define reg_dca_data_h2_9_8_len 2
+#define reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0 0xA180
+#define reg_f_adc_7_0_pos 0
+#define reg_f_adc_7_0_len 8
+#define reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8 0xA181
+#define reg_f_adc_15_8_pos 0
+#define reg_f_adc_15_8_len 8
+#define reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16 0xA182
+#define reg_f_adc_23_16_pos 0
+#define reg_f_adc_23_16_len 8
+#define reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0 0xA190
+#define intp_mu_7_0_pos 0
+#define intp_mu_7_0_len 8
+#define intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8 0xA191
+#define intp_mu_15_8_pos 0
+#define intp_mu_15_8_len 8
+#define intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16 0xA192
+#define intp_mu_19_16_pos 0
+#define intp_mu_19_16_len 4
+#define intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst 0xA1A0
+#define reg_agc_rst_pos 0
+#define reg_agc_rst_len 1
+#define reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en 0xA1A0
+#define rf_agc_en_pos 1
+#define rf_agc_en_len 1
+#define rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis 0xA1A0
+#define rf_agc_dis_pos 2
+#define rf_agc_dis_len 1
+#define rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst 0xA1A0
+#define if_agc_rst_pos 3
+#define if_agc_rst_len 1
+#define if_agc_rst_lsb 0
+#define xd_p_if_agc_en 0xA1A0
+#define if_agc_en_pos 4
+#define if_agc_en_len 1
+#define if_agc_en_lsb 0
+#define xd_p_if_agc_dis 0xA1A0
+#define if_agc_dis_pos 5
+#define if_agc_dis_len 1
+#define if_agc_dis_lsb 0
+#define xd_p_agc_lock 0xA1A0
+#define agc_lock_pos 6
+#define agc_lock_len 1
+#define agc_lock_lsb 0
+#define xd_p_reg_tinr_rst 0xA1A1
+#define reg_tinr_rst_pos 0
+#define reg_tinr_rst_len 1
+#define reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en 0xA1A1
+#define reg_tinr_en_pos 1
+#define reg_tinr_en_len 1
+#define reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en 0xA1A2
+#define reg_ccifs_en_pos 0
+#define reg_ccifs_en_len 1
+#define reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis 0xA1A2
+#define reg_ccifs_dis_pos 1
+#define reg_ccifs_dis_len 1
+#define reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst 0xA1A2
+#define reg_ccifs_rst_pos 2
+#define reg_ccifs_rst_len 1
+#define reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp 0xA1A2
+#define reg_ccifs_byp_pos 3
+#define reg_ccifs_byp_len 1
+#define reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en 0xA1A3
+#define reg_ccif_en_pos 0
+#define reg_ccif_en_len 1
+#define reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis 0xA1A3
+#define reg_ccif_dis_pos 1
+#define reg_ccif_dis_len 1
+#define reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst 0xA1A3
+#define reg_ccif_rst_pos 2
+#define reg_ccif_rst_len 1
+#define reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp 0xA1A3
+#define reg_ccif_byp_pos 3
+#define reg_ccif_byp_len 1
+#define reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst 0xA1A4
+#define dagc1_rst_pos 0
+#define dagc1_rst_len 1
+#define dagc1_rst_lsb 0
+#define xd_p_dagc1_en 0xA1A4
+#define dagc1_en_pos 1
+#define dagc1_en_len 1
+#define dagc1_en_lsb 0
+#define xd_p_dagc1_mode 0xA1A4
+#define dagc1_mode_pos 2
+#define dagc1_mode_len 2
+#define dagc1_mode_lsb 0
+#define xd_p_dagc1_done 0xA1A4
+#define dagc1_done_pos 4
+#define dagc1_done_len 1
+#define dagc1_done_lsb 0
+#define xd_p_ccid_rst 0xA1A5
+#define ccid_rst_pos 0
+#define ccid_rst_len 1
+#define ccid_rst_lsb 0
+#define xd_p_ccid_en 0xA1A5
+#define ccid_en_pos 1
+#define ccid_en_len 1
+#define ccid_en_lsb 0
+#define xd_p_ccid_mode 0xA1A5
+#define ccid_mode_pos 2
+#define ccid_mode_len 2
+#define ccid_mode_lsb 0
+#define xd_p_ccid_done 0xA1A5
+#define ccid_done_pos 4
+#define ccid_done_len 1
+#define ccid_done_lsb 0
+#define xd_r_ccid_deted 0xA1A5
+#define ccid_deted_pos 5
+#define ccid_deted_len 1
+#define ccid_deted_lsb 0
+#define xd_p_ccid2_en 0xA1A5
+#define ccid2_en_pos 6
+#define ccid2_en_len 1
+#define ccid2_en_lsb 0
+#define xd_p_ccid2_done 0xA1A5
+#define ccid2_done_pos 7
+#define ccid2_done_len 1
+#define ccid2_done_lsb 0
+#define xd_p_reg_bfs_en 0xA1A6
+#define reg_bfs_en_pos 0
+#define reg_bfs_en_len 1
+#define reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis 0xA1A6
+#define reg_bfs_dis_pos 1
+#define reg_bfs_dis_len 1
+#define reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst 0xA1A6
+#define reg_bfs_rst_pos 2
+#define reg_bfs_rst_len 1
+#define reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp 0xA1A6
+#define reg_bfs_byp_pos 3
+#define reg_bfs_byp_len 1
+#define reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en 0xA1A7
+#define reg_antif_en_pos 0
+#define reg_antif_en_len 1
+#define reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis 0xA1A7
+#define reg_antif_dis_pos 1
+#define reg_antif_dis_len 1
+#define reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst 0xA1A7
+#define reg_antif_rst_pos 2
+#define reg_antif_rst_len 1
+#define reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp 0xA1A7
+#define reg_antif_byp_pos 3
+#define reg_antif_byp_len 1
+#define reg_antif_byp_lsb 0
+#define xd_p_intp_en 0xA1A8
+#define intp_en_pos 0
+#define intp_en_len 1
+#define intp_en_lsb 0
+#define xd_p_intp_dis 0xA1A8
+#define intp_dis_pos 1
+#define intp_dis_len 1
+#define intp_dis_lsb 0
+#define xd_p_intp_rst 0xA1A8
+#define intp_rst_pos 2
+#define intp_rst_len 1
+#define intp_rst_lsb 0
+#define xd_p_intp_byp 0xA1A8
+#define intp_byp_pos 3
+#define intp_byp_len 1
+#define intp_byp_lsb 0
+#define xd_p_reg_acif_en 0xA1A9
+#define reg_acif_en_pos 0
+#define reg_acif_en_len 1
+#define reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis 0xA1A9
+#define reg_acif_dis_pos 1
+#define reg_acif_dis_len 1
+#define reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst 0xA1A9
+#define reg_acif_rst_pos 2
+#define reg_acif_rst_len 1
+#define reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp 0xA1A9
+#define reg_acif_byp_pos 3
+#define reg_acif_byp_len 1
+#define reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode 0xA1A9
+#define reg_acif_sync_mode_pos 4
+#define reg_acif_sync_mode_len 1
+#define reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst 0xA1AA
+#define dagc2_rst_pos 0
+#define dagc2_rst_len 1
+#define dagc2_rst_lsb 0
+#define xd_p_dagc2_en 0xA1AA
+#define dagc2_en_pos 1
+#define dagc2_en_len 1
+#define dagc2_en_lsb 0
+#define xd_p_dagc2_mode 0xA1AA
+#define dagc2_mode_pos 2
+#define dagc2_mode_len 2
+#define dagc2_mode_lsb 0
+#define xd_p_dagc2_done 0xA1AA
+#define dagc2_done_pos 4
+#define dagc2_done_len 1
+#define dagc2_done_lsb 0
+#define xd_p_reg_dca_en 0xA1AB
+#define reg_dca_en_pos 0
+#define reg_dca_en_len 1
+#define reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0
+#define dagc2_accumulate_num_2k_7_0_pos 0
+#define dagc2_accumulate_num_2k_7_0_len 8
+#define dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1
+#define dagc2_accumulate_num_2k_12_8_pos 0
+#define dagc2_accumulate_num_2k_12_8_len 5
+#define dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2
+#define dagc2_accumulate_num_8k_7_0_pos 0
+#define dagc2_accumulate_num_8k_7_0_len 8
+#define dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3
+#define dagc2_accumulate_num_8k_12_8_pos 0
+#define dagc2_accumulate_num_8k_12_8_len 5
+#define dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0 0xA1C3
+#define dagc2_desired_level_2_0_pos 5
+#define dagc2_desired_level_2_0_len 3
+#define dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3 0xA1C4
+#define dagc2_desired_level_8_3_pos 0
+#define dagc2_desired_level_8_3_len 6
+#define dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay 0xA1C5
+#define dagc2_apply_delay_pos 0
+#define dagc2_apply_delay_len 7
+#define dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl 0xA1C6
+#define dagc2_bypass_scale_ctl_pos 0
+#define dagc2_bypass_scale_ctl_len 3
+#define dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1 0xA1C7
+#define dagc2_programmable_shift1_pos 0
+#define dagc2_programmable_shift1_len 8
+#define dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2 0xA1C8
+#define dagc2_programmable_shift2_pos 0
+#define dagc2_programmable_shift2_len 8
+#define dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9
+#define reg_dagc2_in_sat_cnt_7_0_pos 0
+#define reg_dagc2_in_sat_cnt_7_0_len 8
+#define reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA
+#define reg_dagc2_in_sat_cnt_15_8_pos 0
+#define reg_dagc2_in_sat_cnt_15_8_len 8
+#define reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB
+#define reg_dagc2_in_sat_cnt_23_16_pos 0
+#define reg_dagc2_in_sat_cnt_23_16_len 8
+#define reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC
+#define reg_dagc2_in_sat_cnt_31_24_pos 0
+#define reg_dagc2_in_sat_cnt_31_24_len 8
+#define reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD
+#define reg_dagc2_out_sat_cnt_7_0_pos 0
+#define reg_dagc2_out_sat_cnt_7_0_len 8
+#define reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE
+#define reg_dagc2_out_sat_cnt_15_8_pos 0
+#define reg_dagc2_out_sat_cnt_15_8_len 8
+#define reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF
+#define reg_dagc2_out_sat_cnt_23_16_pos 0
+#define reg_dagc2_out_sat_cnt_23_16_len 8
+#define reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0
+#define reg_dagc2_out_sat_cnt_31_24_pos 0
+#define reg_dagc2_out_sat_cnt_31_24_len 8
+#define reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0 0xA1D6
+#define dagc2_multiplier_7_0_pos 0
+#define dagc2_multiplier_7_0_len 8
+#define dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8 0xA1D7
+#define dagc2_multiplier_15_8_pos 0
+#define dagc2_multiplier_15_8_len 8
+#define dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits 0xA1D8
+#define dagc2_right_shift_bits_pos 0
+#define dagc2_right_shift_bits_len 4
+#define dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0 0xA200
+#define cfoe_NS_coeff1_7_0_pos 0
+#define cfoe_NS_coeff1_7_0_len 8
+#define cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8 0xA201
+#define cfoe_NS_coeff1_15_8_pos 0
+#define cfoe_NS_coeff1_15_8_len 8
+#define cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16 0xA202
+#define cfoe_NS_coeff1_23_16_pos 0
+#define cfoe_NS_coeff1_23_16_len 8
+#define cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24 0xA203
+#define cfoe_NS_coeff1_25_24_pos 0
+#define cfoe_NS_coeff1_25_24_len 2
+#define cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0 0xA203
+#define cfoe_NS_coeff2_5_0_pos 2
+#define cfoe_NS_coeff2_5_0_len 6
+#define cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6 0xA204
+#define cfoe_NS_coeff2_13_6_pos 0
+#define cfoe_NS_coeff2_13_6_len 8
+#define cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14 0xA205
+#define cfoe_NS_coeff2_21_14_pos 0
+#define cfoe_NS_coeff2_21_14_len 8
+#define cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22 0xA206
+#define cfoe_NS_coeff2_24_22_pos 0
+#define cfoe_NS_coeff2_24_22_len 3
+#define cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0 0xA206
+#define cfoe_lf_c1_4_0_pos 3
+#define cfoe_lf_c1_4_0_len 5
+#define cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5 0xA207
+#define cfoe_lf_c1_12_5_pos 0
+#define cfoe_lf_c1_12_5_len 8
+#define cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13 0xA208
+#define cfoe_lf_c1_20_13_pos 0
+#define cfoe_lf_c1_20_13_len 8
+#define cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21 0xA209
+#define cfoe_lf_c1_25_21_pos 0
+#define cfoe_lf_c1_25_21_len 5
+#define cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0 0xA209
+#define cfoe_lf_c2_2_0_pos 5
+#define cfoe_lf_c2_2_0_len 3
+#define cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3 0xA20A
+#define cfoe_lf_c2_10_3_pos 0
+#define cfoe_lf_c2_10_3_len 8
+#define cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11 0xA20B
+#define cfoe_lf_c2_18_11_pos 0
+#define cfoe_lf_c2_18_11_len 8
+#define cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19 0xA20C
+#define cfoe_lf_c2_25_19_pos 0
+#define cfoe_lf_c2_25_19_len 7
+#define cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0 0xA20D
+#define cfoe_ifod_7_0_pos 0
+#define cfoe_ifod_7_0_len 8
+#define cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8 0xA20E
+#define cfoe_ifod_10_8_pos 0
+#define cfoe_ifod_10_8_len 3
+#define cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th 0xA20E
+#define cfoe_Divg_ctr_th_pos 4
+#define cfoe_Divg_ctr_th_len 4
+#define cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th 0xA20F
+#define cfoe_FOT_divg_th_pos 0
+#define cfoe_FOT_divg_th_len 8
+#define cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th 0xA210
+#define cfoe_FOT_cnvg_th_pos 0
+#define cfoe_FOT_cnvg_th_len 8
+#define cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0 0xA211
+#define reg_cfoe_offset_7_0_pos 0
+#define reg_cfoe_offset_7_0_len 8
+#define reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8 0xA212
+#define reg_cfoe_offset_9_8_pos 0
+#define reg_cfoe_offset_9_8_len 2
+#define reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212
+#define reg_cfoe_ifoe_sign_corr_pos 2
+#define reg_cfoe_ifoe_sign_corr_len 1
+#define reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0 0xA218
+#define cfoe_fot_LF_output_7_0_pos 0
+#define cfoe_fot_LF_output_7_0_len 8
+#define cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8 0xA219
+#define cfoe_fot_LF_output_15_8_pos 0
+#define cfoe_fot_LF_output_15_8_len 8
+#define cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0 0xA21A
+#define cfoe_ifo_metric_7_0_pos 0
+#define cfoe_ifo_metric_7_0_len 8
+#define cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8 0xA21B
+#define cfoe_ifo_metric_15_8_pos 0
+#define cfoe_ifo_metric_15_8_len 8
+#define cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16 0xA21C
+#define cfoe_ifo_metric_23_16_pos 0
+#define cfoe_ifo_metric_23_16_len 8
+#define cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu 0xA220
+#define ste_Nu_pos 0
+#define ste_Nu_len 2
+#define ste_Nu_lsb 0
+#define xd_p_ste_GI 0xA220
+#define ste_GI_pos 2
+#define ste_GI_len 3
+#define ste_GI_lsb 0
+#define xd_p_ste_symbol_num 0xA221
+#define ste_symbol_num_pos 0
+#define ste_symbol_num_len 2
+#define ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num 0xA221
+#define ste_sample_num_pos 2
+#define ste_sample_num_len 2
+#define ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en 0xA221
+#define reg_ste_buf_en_pos 7
+#define reg_ste_buf_en_len 1
+#define reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0 0xA222
+#define ste_FFT_offset_7_0_pos 0
+#define ste_FFT_offset_7_0_len 8
+#define ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8 0xA223
+#define ste_FFT_offset_11_8_pos 0
+#define ste_FFT_offset_11_8_len 4
+#define ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod 0xA223
+#define reg_ste_tstmod_pos 5
+#define reg_ste_tstmod_len 1
+#define reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0 0xA224
+#define ste_adv_start_7_0_pos 0
+#define ste_adv_start_7_0_len 8
+#define ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8 0xA225
+#define ste_adv_start_10_8_pos 0
+#define ste_adv_start_10_8_len 3
+#define ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop 0xA226
+#define ste_adv_stop_pos 0
+#define ste_adv_stop_len 8
+#define ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0 0xA228
+#define ste_P_value_7_0_pos 0
+#define ste_P_value_7_0_len 8
+#define ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8 0xA229
+#define ste_P_value_10_8_pos 0
+#define ste_P_value_10_8_len 3
+#define ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0 0xA22A
+#define ste_M_value_7_0_pos 0
+#define ste_M_value_7_0_len 8
+#define ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8 0xA22B
+#define ste_M_value_10_8_pos 0
+#define ste_M_value_10_8_len 3
+#define ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1 0xA22C
+#define ste_H1_pos 0
+#define ste_H1_len 7
+#define ste_H1_lsb 0
+#define xd_r_ste_H2 0xA22D
+#define ste_H2_pos 0
+#define ste_H2_len 7
+#define ste_H2_lsb 0
+#define xd_r_ste_H3 0xA22E
+#define ste_H3_pos 0
+#define ste_H3_len 7
+#define ste_H3_lsb 0
+#define xd_r_ste_H4 0xA22F
+#define ste_H4_pos 0
+#define ste_H4_len 7
+#define ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0 0xA230
+#define ste_Corr_value_I_7_0_pos 0
+#define ste_Corr_value_I_7_0_len 8
+#define ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8 0xA231
+#define ste_Corr_value_I_15_8_pos 0
+#define ste_Corr_value_I_15_8_len 8
+#define ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16 0xA232
+#define ste_Corr_value_I_23_16_pos 0
+#define ste_Corr_value_I_23_16_len 8
+#define ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24 0xA233
+#define ste_Corr_value_I_27_24_pos 0
+#define ste_Corr_value_I_27_24_len 4
+#define ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0 0xA234
+#define ste_Corr_value_Q_7_0_pos 0
+#define ste_Corr_value_Q_7_0_len 8
+#define ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8 0xA235
+#define ste_Corr_value_Q_15_8_pos 0
+#define ste_Corr_value_Q_15_8_len 8
+#define ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16 0xA236
+#define ste_Corr_value_Q_23_16_pos 0
+#define ste_Corr_value_Q_23_16_len 8
+#define ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24 0xA237
+#define ste_Corr_value_Q_27_24_pos 0
+#define ste_Corr_value_Q_27_24_len 4
+#define ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0 0xA238
+#define ste_J_num_7_0_pos 0
+#define ste_J_num_7_0_len 8
+#define ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8 0xA239
+#define ste_J_num_15_8_pos 0
+#define ste_J_num_15_8_len 8
+#define ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16 0xA23A
+#define ste_J_num_23_16_pos 0
+#define ste_J_num_23_16_len 8
+#define ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24 0xA23B
+#define ste_J_num_31_24_pos 0
+#define ste_J_num_31_24_len 8
+#define ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0 0xA23C
+#define ste_J_den_7_0_pos 0
+#define ste_J_den_7_0_len 8
+#define ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8 0xA23D
+#define ste_J_den_15_8_pos 0
+#define ste_J_den_15_8_len 8
+#define ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16 0xA23E
+#define ste_J_den_18_16_pos 0
+#define ste_J_den_18_16_len 3
+#define ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator 0xA23E
+#define ste_Beacon_Indicator_pos 4
+#define ste_Beacon_Indicator_len 1
+#define ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num 0xA250
+#define tpsd_Frame_Num_pos 0
+#define tpsd_Frame_Num_len 2
+#define tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel 0xA250
+#define tpsd_Constel_pos 2
+#define tpsd_Constel_len 2
+#define tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI 0xA250
+#define tpsd_GI_pos 4
+#define tpsd_GI_len 2
+#define tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode 0xA250
+#define tpsd_Mode_pos 6
+#define tpsd_Mode_len 2
+#define tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP 0xA251
+#define tpsd_CR_HP_pos 0
+#define tpsd_CR_HP_len 3
+#define tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP 0xA251
+#define tpsd_CR_LP_pos 3
+#define tpsd_CR_LP_len 3
+#define tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie 0xA252
+#define tpsd_Hie_pos 0
+#define tpsd_Hie_len 3
+#define tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits 0xA252
+#define tpsd_Res_Bits_pos 3
+#define tpsd_Res_Bits_len 5
+#define tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0 0xA253
+#define tpsd_Res_Bits_0_pos 0
+#define tpsd_Res_Bits_0_len 1
+#define tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd 0xA253
+#define tpsd_LengthInd_pos 1
+#define tpsd_LengthInd_len 6
+#define tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0 0xA254
+#define tpsd_Cell_Id_7_0_pos 0
+#define tpsd_Cell_Id_7_0_len 8
+#define tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8 0xA255
+#define tpsd_Cell_Id_15_8_pos 0
+#define tpsd_Cell_Id_15_8_len 8
+#define tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0 0xA260
+#define reg_fft_mask_tone0_7_0_pos 0
+#define reg_fft_mask_tone0_7_0_len 8
+#define reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8 0xA261
+#define reg_fft_mask_tone0_12_8_pos 0
+#define reg_fft_mask_tone0_12_8_len 5
+#define reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0 0xA262
+#define reg_fft_mask_tone1_7_0_pos 0
+#define reg_fft_mask_tone1_7_0_len 8
+#define reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8 0xA263
+#define reg_fft_mask_tone1_12_8_pos 0
+#define reg_fft_mask_tone1_12_8_len 5
+#define reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0 0xA264
+#define reg_fft_mask_tone2_7_0_pos 0
+#define reg_fft_mask_tone2_7_0_len 8
+#define reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8 0xA265
+#define reg_fft_mask_tone2_12_8_pos 0
+#define reg_fft_mask_tone2_12_8_len 5
+#define reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0 0xA266
+#define reg_fft_mask_tone3_7_0_pos 0
+#define reg_fft_mask_tone3_7_0_len 8
+#define reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8 0xA267
+#define reg_fft_mask_tone3_12_8_pos 0
+#define reg_fft_mask_tone3_12_8_len 5
+#define reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0 0xA268
+#define reg_fft_mask_from0_7_0_pos 0
+#define reg_fft_mask_from0_7_0_len 8
+#define reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8 0xA269
+#define reg_fft_mask_from0_12_8_pos 0
+#define reg_fft_mask_from0_12_8_len 5
+#define reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0 0xA26A
+#define reg_fft_mask_to0_7_0_pos 0
+#define reg_fft_mask_to0_7_0_len 8
+#define reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8 0xA26B
+#define reg_fft_mask_to0_12_8_pos 0
+#define reg_fft_mask_to0_12_8_len 5
+#define reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0 0xA26C
+#define reg_fft_mask_from1_7_0_pos 0
+#define reg_fft_mask_from1_7_0_len 8
+#define reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8 0xA26D
+#define reg_fft_mask_from1_12_8_pos 0
+#define reg_fft_mask_from1_12_8_len 5
+#define reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0 0xA26E
+#define reg_fft_mask_to1_7_0_pos 0
+#define reg_fft_mask_to1_7_0_len 8
+#define reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8 0xA26F
+#define reg_fft_mask_to1_12_8_pos 0
+#define reg_fft_mask_to1_12_8_len 5
+#define reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0 0xA280
+#define reg_cge_idx0_7_0_pos 0
+#define reg_cge_idx0_7_0_len 8
+#define reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8 0xA281
+#define reg_cge_idx0_12_8_pos 0
+#define reg_cge_idx0_12_8_len 5
+#define reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0 0xA282
+#define reg_cge_idx1_7_0_pos 0
+#define reg_cge_idx1_7_0_len 8
+#define reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8 0xA283
+#define reg_cge_idx1_12_8_pos 0
+#define reg_cge_idx1_12_8_len 5
+#define reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0 0xA284
+#define reg_cge_idx2_7_0_pos 0
+#define reg_cge_idx2_7_0_len 8
+#define reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8 0xA285
+#define reg_cge_idx2_12_8_pos 0
+#define reg_cge_idx2_12_8_len 5
+#define reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0 0xA286
+#define reg_cge_idx3_7_0_pos 0
+#define reg_cge_idx3_7_0_len 8
+#define reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8 0xA287
+#define reg_cge_idx3_12_8_pos 0
+#define reg_cge_idx3_12_8_len 5
+#define reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0 0xA288
+#define reg_cge_idx4_7_0_pos 0
+#define reg_cge_idx4_7_0_len 8
+#define reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8 0xA289
+#define reg_cge_idx4_12_8_pos 0
+#define reg_cge_idx4_12_8_len 5
+#define reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0 0xA28A
+#define reg_cge_idx5_7_0_pos 0
+#define reg_cge_idx5_7_0_len 8
+#define reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8 0xA28B
+#define reg_cge_idx5_12_8_pos 0
+#define reg_cge_idx5_12_8_len 5
+#define reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0 0xA28C
+#define reg_cge_idx6_7_0_pos 0
+#define reg_cge_idx6_7_0_len 8
+#define reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8 0xA28D
+#define reg_cge_idx6_12_8_pos 0
+#define reg_cge_idx6_12_8_len 5
+#define reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0 0xA28E
+#define reg_cge_idx7_7_0_pos 0
+#define reg_cge_idx7_7_0_len 8
+#define reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8 0xA28F
+#define reg_cge_idx7_12_8_pos 0
+#define reg_cge_idx7_12_8_len 5
+#define reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0 0xA290
+#define reg_cge_idx8_7_0_pos 0
+#define reg_cge_idx8_7_0_len 8
+#define reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8 0xA291
+#define reg_cge_idx8_12_8_pos 0
+#define reg_cge_idx8_12_8_len 5
+#define reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0 0xA292
+#define reg_cge_idx9_7_0_pos 0
+#define reg_cge_idx9_7_0_len 8
+#define reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8 0xA293
+#define reg_cge_idx9_12_8_pos 0
+#define reg_cge_idx9_12_8_len 5
+#define reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0 0xA294
+#define reg_cge_idx10_7_0_pos 0
+#define reg_cge_idx10_7_0_len 8
+#define reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8 0xA295
+#define reg_cge_idx10_12_8_pos 0
+#define reg_cge_idx10_12_8_len 5
+#define reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0 0xA296
+#define reg_cge_idx11_7_0_pos 0
+#define reg_cge_idx11_7_0_len 8
+#define reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8 0xA297
+#define reg_cge_idx11_12_8_pos 0
+#define reg_cge_idx11_12_8_len 5
+#define reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0 0xA298
+#define reg_cge_idx12_7_0_pos 0
+#define reg_cge_idx12_7_0_len 8
+#define reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8 0xA299
+#define reg_cge_idx12_12_8_pos 0
+#define reg_cge_idx12_12_8_len 5
+#define reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0 0xA29A
+#define reg_cge_idx13_7_0_pos 0
+#define reg_cge_idx13_7_0_len 8
+#define reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8 0xA29B
+#define reg_cge_idx13_12_8_pos 0
+#define reg_cge_idx13_12_8_len 5
+#define reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0 0xA29C
+#define reg_cge_idx14_7_0_pos 0
+#define reg_cge_idx14_7_0_len 8
+#define reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8 0xA29D
+#define reg_cge_idx14_12_8_pos 0
+#define reg_cge_idx14_12_8_len 5
+#define reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0 0xA29E
+#define reg_cge_idx15_7_0_pos 0
+#define reg_cge_idx15_7_0_len 8
+#define reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8 0xA29F
+#define reg_cge_idx15_12_8_pos 0
+#define reg_cge_idx15_12_8_len 5
+#define reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc 0xA2A8
+#define reg_fft_crc_pos 0
+#define reg_fft_crc_len 8
+#define reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max 0xA2A9
+#define fd_fft_shift_max_pos 0
+#define fd_fft_shift_max_len 4
+#define fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift 0xA2A9
+#define fd_fft_shift_pos 4
+#define fd_fft_shift_len 4
+#define fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num 0xA2AA
+#define fd_fft_frame_num_pos 0
+#define fd_fft_frame_num_len 2
+#define fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count 0xA2AB
+#define fd_fft_symbol_count_pos 0
+#define fd_fft_symbol_count_len 7
+#define fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0 0xA2AC
+#define reg_fft_idx_max_7_0_pos 0
+#define reg_fft_idx_max_7_0_len 8
+#define reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8 0xA2AD
+#define reg_fft_idx_max_12_8_pos 0
+#define reg_fft_idx_max_12_8_len 5
+#define reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program 0xA2AE
+#define reg_cge_program_pos 0
+#define reg_cge_program_len 1
+#define reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed 0xA2AE
+#define reg_cge_fixed_pos 1
+#define reg_cge_fixed_len 1
+#define reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en 0xA2AE
+#define reg_fft_rotate_en_pos 2
+#define reg_fft_rotate_en_len 1
+#define reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0 0xA2AE
+#define reg_fft_rotate_base_4_0_pos 3
+#define reg_fft_rotate_base_4_0_len 5
+#define reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5 0xA2AF
+#define reg_fft_rotate_base_12_5_pos 0
+#define reg_fft_rotate_base_12_5_len 8
+#define reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd 0xA2B8
+#define reg_gp_trigger_fd_pos 0
+#define reg_gp_trigger_fd_len 1
+#define reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd 0xA2B8
+#define reg_trigger_sel_fd_pos 1
+#define reg_trigger_sel_fd_len 2
+#define reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd 0xA2B9
+#define reg_trigger_module_sel_fd_pos 0
+#define reg_trigger_module_sel_fd_len 6
+#define reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd 0xA2BA
+#define reg_trigger_set_sel_fd_pos 0
+#define reg_trigger_set_sel_fd_len 6
+#define reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0 0xA2BC
+#define reg_fd_noname_7_0_pos 0
+#define reg_fd_noname_7_0_len 8
+#define reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8 0xA2BD
+#define reg_fd_noname_15_8_pos 0
+#define reg_fd_noname_15_8_len 8
+#define reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16 0xA2BE
+#define reg_fd_noname_23_16_pos 0
+#define reg_fd_noname_23_16_len 8
+#define reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24 0xA2BF
+#define reg_fd_noname_31_24_pos 0
+#define reg_fd_noname_31_24_len 8
+#define reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0
+#define fd_fpcc_cp_corr_signn_pos 0
+#define fd_fpcc_cp_corr_signn_len 8
+#define fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1 0xA2C1
+#define reg_feq_s1_pos 0
+#define reg_feq_s1_len 5
+#define reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2
+#define fd_fpcc_cp_corr_tone_th_pos 0
+#define fd_fpcc_cp_corr_tone_th_len 6
+#define fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3
+#define fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define fd_fpcc_cp_corr_symbol_log_th_len 4
+#define fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int 0xA2C4
+#define fd_fpcc_cp_corr_int_pos 0
+#define fd_fpcc_cp_corr_int_len 1
+#define fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0 0xA320
+#define reg_sfoe_ns_7_0_pos 0
+#define reg_sfoe_ns_7_0_len 8
+#define reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8 0xA321
+#define reg_sfoe_ns_14_8_pos 0
+#define reg_sfoe_ns_14_8_len 7
+#define reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0 0xA322
+#define reg_sfoe_c1_7_0_pos 0
+#define reg_sfoe_c1_7_0_len 8
+#define reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8 0xA323
+#define reg_sfoe_c1_15_8_pos 0
+#define reg_sfoe_c1_15_8_len 8
+#define reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16 0xA324
+#define reg_sfoe_c1_17_16_pos 0
+#define reg_sfoe_c1_17_16_len 2
+#define reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0 0xA325
+#define reg_sfoe_c2_7_0_pos 0
+#define reg_sfoe_c2_7_0_len 8
+#define reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8 0xA326
+#define reg_sfoe_c2_15_8_pos 0
+#define reg_sfoe_c2_15_8_len 8
+#define reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16 0xA327
+#define reg_sfoe_c2_17_16_pos 0
+#define reg_sfoe_c2_17_16_len 2
+#define reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2 0xA328
+#define reg_sfoe_out_9_2_pos 0
+#define reg_sfoe_out_9_2_len 8
+#define reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0 0xA329
+#define reg_sfoe_out_1_0_pos 0
+#define reg_sfoe_out_1_0_len 2
+#define reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th 0xA32A
+#define reg_sfoe_lm_counter_th_pos 0
+#define reg_sfoe_lm_counter_th_len 4
+#define reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th 0xA32B
+#define reg_sfoe_convg_th_pos 0
+#define reg_sfoe_convg_th_len 8
+#define reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th 0xA32C
+#define reg_sfoe_divg_th_pos 0
+#define reg_sfoe_divg_th_len 8
+#define reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en 0xA330
+#define fd_tpsd_en_pos 0
+#define fd_tpsd_en_len 1
+#define fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis 0xA330
+#define fd_tpsd_dis_pos 1
+#define fd_tpsd_dis_len 1
+#define fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst 0xA330
+#define fd_tpsd_rst_pos 2
+#define fd_tpsd_rst_len 1
+#define fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock 0xA330
+#define fd_tpsd_lock_pos 3
+#define fd_tpsd_lock_len 1
+#define fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19 0xA330
+#define fd_tpsd_s19_pos 4
+#define fd_tpsd_s19_len 1
+#define fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17 0xA330
+#define fd_tpsd_s17_pos 5
+#define fd_tpsd_s17_len 1
+#define fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en 0xA331
+#define fd_sfr_ste_en_pos 0
+#define fd_sfr_ste_en_len 1
+#define fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis 0xA331
+#define fd_sfr_ste_dis_pos 1
+#define fd_sfr_ste_dis_len 1
+#define fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst 0xA331
+#define fd_sfr_ste_rst_pos 2
+#define fd_sfr_ste_rst_len 1
+#define fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode 0xA331
+#define fd_sfr_ste_mode_pos 3
+#define fd_sfr_ste_mode_len 1
+#define fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done 0xA331
+#define fd_sfr_ste_done_pos 4
+#define fd_sfr_ste_done_len 1
+#define fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en 0xA332
+#define reg_cfoe_ffoe_en_pos 0
+#define reg_cfoe_ffoe_en_len 1
+#define reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis 0xA332
+#define reg_cfoe_ffoe_dis_pos 1
+#define reg_cfoe_ffoe_dis_len 1
+#define reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst 0xA332
+#define reg_cfoe_ffoe_rst_pos 2
+#define reg_cfoe_ffoe_rst_len 1
+#define reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en 0xA332
+#define reg_cfoe_ifoe_en_pos 3
+#define reg_cfoe_ifoe_en_len 1
+#define reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis 0xA332
+#define reg_cfoe_ifoe_dis_pos 4
+#define reg_cfoe_ifoe_dis_len 1
+#define reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst 0xA332
+#define reg_cfoe_ifoe_rst_pos 5
+#define reg_cfoe_ifoe_rst_len 1
+#define reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en 0xA332
+#define reg_cfoe_fot_en_pos 6
+#define reg_cfoe_fot_en_len 1
+#define reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en 0xA332
+#define reg_cfoe_fot_lm_en_pos 7
+#define reg_cfoe_fot_lm_en_len 1
+#define reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst 0xA333
+#define reg_cfoe_fot_rst_pos 0
+#define reg_cfoe_fot_rst_len 1
+#define reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done 0xA333
+#define fd_cfoe_ffoe_done_pos 1
+#define fd_cfoe_ffoe_done_len 1
+#define fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld 0xA333
+#define fd_cfoe_metric_vld_pos 2
+#define fd_cfoe_metric_vld_len 1
+#define fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld 0xA333
+#define reg_cfoe_ifod_vld_pos 3
+#define reg_cfoe_ifod_vld_len 1
+#define reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done 0xA333
+#define fd_cfoe_ifoe_done_pos 4
+#define fd_cfoe_ifoe_done_len 1
+#define fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid 0xA333
+#define fd_cfoe_fot_valid_pos 5
+#define fd_cfoe_fot_valid_len 1
+#define fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int 0xA333
+#define reg_cfoe_divg_int_pos 6
+#define reg_cfoe_divg_int_len 1
+#define reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag 0xA333
+#define reg_cfoe_divg_flag_pos 7
+#define reg_cfoe_divg_flag_len 1
+#define reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en 0xA334
+#define reg_sfoe_en_pos 0
+#define reg_sfoe_en_len 1
+#define reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis 0xA334
+#define reg_sfoe_dis_pos 1
+#define reg_sfoe_dis_len 1
+#define reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst 0xA334
+#define reg_sfoe_rst_pos 2
+#define reg_sfoe_rst_len 1
+#define reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int 0xA334
+#define reg_sfoe_vld_int_pos 3
+#define reg_sfoe_vld_int_len 1
+#define reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en 0xA334
+#define reg_sfoe_lm_en_pos 4
+#define reg_sfoe_lm_en_len 1
+#define reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int 0xA334
+#define reg_sfoe_divg_int_pos 5
+#define reg_sfoe_divg_int_len 1
+#define reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag 0xA334
+#define reg_sfoe_divg_flag_pos 6
+#define reg_sfoe_divg_flag_len 1
+#define reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst 0xA335
+#define reg_fft_rst_pos 0
+#define reg_fft_rst_len 1
+#define reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon 0xA335
+#define reg_fft_fast_beacon_pos 1
+#define reg_fft_fast_beacon_len 1
+#define reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid 0xA335
+#define reg_fft_fast_valid_pos 2
+#define reg_fft_fast_valid_len 1
+#define reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en 0xA335
+#define reg_fft_mask_en_pos 3
+#define reg_fft_mask_en_len 1
+#define reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en 0xA335
+#define reg_fft_crc_en_pos 4
+#define reg_fft_crc_en_len 1
+#define reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en 0xA336
+#define reg_finr_en_pos 0
+#define reg_finr_en_len 1
+#define reg_finr_en_lsb 0
+#define xd_p_fd_fste_en 0xA337
+#define fd_fste_en_pos 1
+#define fd_fste_en_len 1
+#define fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift 0xA338
+#define fd_sqi_tps_level_shift_pos 0
+#define fd_sqi_tps_level_shift_len 8
+#define fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len 0xA339
+#define fd_pilot_ma_len_pos 0
+#define fd_pilot_ma_len_len 6
+#define fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len 0xA33A
+#define fd_tps_ma_len_pos 0
+#define fd_tps_ma_len_len 6
+#define fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3 0xA33B
+#define fd_sqi_s3_pos 0
+#define fd_sqi_s3_len 8
+#define fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0 0xA33C
+#define fd_sqi_dummy_reg_0_pos 0
+#define fd_sqi_dummy_reg_0_len 1
+#define fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel 0xA33C
+#define fd_sqi_debug_sel_pos 1
+#define fd_sqi_debug_sel_len 2
+#define fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2 0xA33C
+#define fd_sqi_s2_pos 3
+#define fd_sqi_s2_len 5
+#define fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1 0xA33D
+#define fd_sqi_dummy_reg_1_pos 0
+#define fd_sqi_dummy_reg_1_len 1
+#define fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore 0xA33D
+#define fd_inr_ignore_pos 1
+#define fd_inr_ignore_len 1
+#define fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore 0xA33D
+#define fd_pilot_ignore_pos 2
+#define fd_pilot_ignore_len 1
+#define fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore 0xA33D
+#define fd_etps_ignore_pos 3
+#define fd_etps_ignore_len 1
+#define fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1 0xA33D
+#define fd_sqi_s1_pos 4
+#define fd_sqi_s1_len 4
+#define fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0 0xA33E
+#define reg_fste_ehw_7_0_pos 0
+#define reg_fste_ehw_7_0_len 8
+#define reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8 0xA33F
+#define reg_fste_ehw_9_8_pos 0
+#define reg_fste_ehw_9_8_len 2
+#define reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld 0xA33F
+#define reg_fste_i_adj_vld_pos 2
+#define reg_fste_i_adj_vld_len 1
+#define reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0 0xA340
+#define reg_fste_phase_ini_7_0_pos 0
+#define reg_fste_phase_ini_7_0_len 8
+#define reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8 0xA341
+#define reg_fste_phase_ini_11_8_pos 0
+#define reg_fste_phase_ini_11_8_len 4
+#define reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0 0xA341
+#define reg_fste_phase_inc_3_0_pos 4
+#define reg_fste_phase_inc_3_0_len 4
+#define reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4 0xA342
+#define reg_fste_phase_inc_11_4_pos 0
+#define reg_fste_phase_inc_11_4_len 8
+#define reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max 0xA343
+#define reg_fste_acum_cost_cnt_max_pos 0
+#define reg_fste_acum_cost_cnt_max_len 4
+#define reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std 0xA343
+#define reg_fste_step_size_std_pos 4
+#define reg_fste_step_size_std_len 4
+#define reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max 0xA344
+#define reg_fste_step_size_max_pos 0
+#define reg_fste_step_size_max_len 4
+#define reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min 0xA344
+#define reg_fste_step_size_min_pos 4
+#define reg_fste_step_size_min_len 4
+#define reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0 0xA345
+#define reg_fste_frac_step_size_7_0_pos 0
+#define reg_fste_frac_step_size_7_0_len 8
+#define reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8 0xA346
+#define reg_fste_frac_step_size_15_8_pos 0
+#define reg_fste_frac_step_size_15_8_len 8
+#define reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16 0xA347
+#define reg_fste_frac_step_size_19_16_pos 0
+#define reg_fste_frac_step_size_19_16_len 4
+#define reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347
+#define reg_fste_rpd_dir_cnt_max_pos 4
+#define reg_fste_rpd_dir_cnt_max_len 4
+#define reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs 0xA348
+#define reg_fste_ehs_pos 0
+#define reg_fste_ehs_len 4
+#define reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348
+#define reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define reg_fste_frac_cost_cnt_max_3_0_len 4
+#define reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349
+#define reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define reg_fste_frac_cost_cnt_max_9_4_len 6
+#define reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0 0xA34A
+#define reg_fste_w0_7_0_pos 0
+#define reg_fste_w0_7_0_len 8
+#define reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8 0xA34B
+#define reg_fste_w0_11_8_pos 0
+#define reg_fste_w0_11_8_len 4
+#define reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0 0xA34B
+#define reg_fste_w1_3_0_pos 4
+#define reg_fste_w1_3_0_len 4
+#define reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4 0xA34C
+#define reg_fste_w1_11_4_pos 0
+#define reg_fste_w1_11_4_len 8
+#define reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0 0xA34D
+#define reg_fste_w2_7_0_pos 0
+#define reg_fste_w2_7_0_len 8
+#define reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8 0xA34E
+#define reg_fste_w2_11_8_pos 0
+#define reg_fste_w2_11_8_len 4
+#define reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0 0xA34E
+#define reg_fste_w3_3_0_pos 4
+#define reg_fste_w3_3_0_len 4
+#define reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4 0xA34F
+#define reg_fste_w3_11_4_pos 0
+#define reg_fste_w3_11_4_len 8
+#define reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0 0xA350
+#define reg_fste_w4_7_0_pos 0
+#define reg_fste_w4_7_0_len 8
+#define reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8 0xA351
+#define reg_fste_w4_11_8_pos 0
+#define reg_fste_w4_11_8_len 4
+#define reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0 0xA351
+#define reg_fste_w5_3_0_pos 4
+#define reg_fste_w5_3_0_len 4
+#define reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4 0xA352
+#define reg_fste_w5_11_4_pos 0
+#define reg_fste_w5_11_4_len 8
+#define reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0 0xA353
+#define reg_fste_w6_7_0_pos 0
+#define reg_fste_w6_7_0_len 8
+#define reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8 0xA354
+#define reg_fste_w6_11_8_pos 0
+#define reg_fste_w6_11_8_len 4
+#define reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0 0xA354
+#define reg_fste_w7_3_0_pos 4
+#define reg_fste_w7_3_0_len 4
+#define reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4 0xA355
+#define reg_fste_w7_11_4_pos 0
+#define reg_fste_w7_11_4_len 8
+#define reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0 0xA356
+#define reg_fste_w8_7_0_pos 0
+#define reg_fste_w8_7_0_len 8
+#define reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8 0xA357
+#define reg_fste_w8_11_8_pos 0
+#define reg_fste_w8_11_8_len 4
+#define reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0 0xA357
+#define reg_fste_w9_3_0_pos 4
+#define reg_fste_w9_3_0_len 4
+#define reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4 0xA358
+#define reg_fste_w9_11_4_pos 0
+#define reg_fste_w9_11_4_len 8
+#define reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0 0xA359
+#define reg_fste_wa_7_0_pos 0
+#define reg_fste_wa_7_0_len 8
+#define reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8 0xA35A
+#define reg_fste_wa_11_8_pos 0
+#define reg_fste_wa_11_8_len 4
+#define reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0 0xA35A
+#define reg_fste_wb_3_0_pos 4
+#define reg_fste_wb_3_0_len 4
+#define reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4 0xA35B
+#define reg_fste_wb_11_4_pos 0
+#define reg_fste_wb_11_4_len 8
+#define reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj 0xA35C
+#define fd_fste_i_adj_pos 0
+#define fd_fste_i_adj_len 5
+#define fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0 0xA35D
+#define fd_fste_f_adj_7_0_pos 0
+#define fd_fste_f_adj_7_0_len 8
+#define fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8 0xA35E
+#define fd_fste_f_adj_15_8_pos 0
+#define fd_fste_f_adj_15_8_len 8
+#define fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16 0xA35F
+#define fd_fste_f_adj_19_16_pos 0
+#define fd_fste_f_adj_19_16_len 4
+#define fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass 0xA366
+#define reg_feq_Leak_Bypass_pos 0
+#define reg_feq_Leak_Bypass_len 1
+#define reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1 0xA366
+#define reg_feq_Leak_Mneg1_pos 1
+#define reg_feq_Leak_Mneg1_len 3
+#define reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366
+#define reg_feq_Leak_B_ShiftQ_pos 4
+#define reg_feq_Leak_B_ShiftQ_len 4
+#define reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0 0xA367
+#define reg_feq_Leak_B_Float0_pos 0
+#define reg_feq_Leak_B_Float0_len 8
+#define reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1 0xA368
+#define reg_feq_Leak_B_Float1_pos 0
+#define reg_feq_Leak_B_Float1_len 8
+#define reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2 0xA369
+#define reg_feq_Leak_B_Float2_pos 0
+#define reg_feq_Leak_B_Float2_len 8
+#define reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3 0xA36A
+#define reg_feq_Leak_B_Float3_pos 0
+#define reg_feq_Leak_B_Float3_len 8
+#define reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4 0xA36B
+#define reg_feq_Leak_B_Float4_pos 0
+#define reg_feq_Leak_B_Float4_len 8
+#define reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5 0xA36C
+#define reg_feq_Leak_B_Float5_pos 0
+#define reg_feq_Leak_B_Float5_len 8
+#define reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6 0xA36D
+#define reg_feq_Leak_B_Float6_pos 0
+#define reg_feq_Leak_B_Float6_len 8
+#define reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7 0xA36E
+#define reg_feq_Leak_B_Float7_pos 0
+#define reg_feq_Leak_B_Float7_len 8
+#define reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0 0xA36F
+#define reg_feq_data_h2_7_0_pos 0
+#define reg_feq_data_h2_7_0_len 8
+#define reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8 0xA370
+#define reg_feq_data_h2_9_8_pos 0
+#define reg_feq_data_h2_9_8_len 2
+#define reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps 0xA371
+#define reg_feq_leak_use_slice_tps_pos 0
+#define reg_feq_leak_use_slice_tps_len 1
+#define reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update 0xA371
+#define reg_feq_read_update_pos 1
+#define reg_feq_read_update_len 1
+#define reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld 0xA371
+#define reg_feq_data_vld_pos 2
+#define reg_feq_data_vld_len 1
+#define reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0 0xA371
+#define reg_feq_tone_idx_4_0_pos 3
+#define reg_feq_tone_idx_4_0_len 5
+#define reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5 0xA372
+#define reg_feq_tone_idx_12_5_pos 0
+#define reg_feq_tone_idx_12_5_len 8
+#define reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0 0xA373
+#define reg_feq_data_re_7_0_pos 0
+#define reg_feq_data_re_7_0_len 8
+#define reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8 0xA374
+#define reg_feq_data_re_10_8_pos 0
+#define reg_feq_data_re_10_8_len 3
+#define reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0 0xA375
+#define reg_feq_data_im_7_0_pos 0
+#define reg_feq_data_im_7_0_len 8
+#define reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8 0xA376
+#define reg_feq_data_im_10_8_pos 0
+#define reg_feq_data_im_10_8_len 3
+#define reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re 0xA377
+#define reg_feq_y_re_pos 0
+#define reg_feq_y_re_len 8
+#define reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im 0xA378
+#define reg_feq_y_im_pos 0
+#define reg_feq_y_im_len 8
+#define reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0 0xA379
+#define reg_feq_h_re_7_0_pos 0
+#define reg_feq_h_re_7_0_len 8
+#define reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8 0xA37A
+#define reg_feq_h_re_8_pos 0
+#define reg_feq_h_re_8_len 1
+#define reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0 0xA37B
+#define reg_feq_h_im_7_0_pos 0
+#define reg_feq_h_im_7_0_len 8
+#define reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8 0xA37C
+#define reg_feq_h_im_8_pos 0
+#define reg_feq_h_im_8_len 1
+#define reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0 0xA380
+#define fec_super_frm_unit_7_0_pos 0
+#define fec_super_frm_unit_7_0_len 8
+#define fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8 0xA381
+#define fec_super_frm_unit_15_8_pos 0
+#define fec_super_frm_unit_15_8_len 8
+#define fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382
+#define fec_vtb_err_bit_cnt_7_0_pos 0
+#define fec_vtb_err_bit_cnt_7_0_len 8
+#define fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383
+#define fec_vtb_err_bit_cnt_15_8_pos 0
+#define fec_vtb_err_bit_cnt_15_8_len 8
+#define fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384
+#define fec_vtb_err_bit_cnt_23_16_pos 0
+#define fec_vtb_err_bit_cnt_23_16_len 8
+#define fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0 0xA385
+#define fec_rsd_packet_unit_7_0_pos 0
+#define fec_rsd_packet_unit_7_0_len 8
+#define fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8 0xA386
+#define fec_rsd_packet_unit_15_8_pos 0
+#define fec_rsd_packet_unit_15_8_len 8
+#define fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387
+#define fec_rsd_bit_err_cnt_7_0_pos 0
+#define fec_rsd_bit_err_cnt_7_0_len 8
+#define fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388
+#define fec_rsd_bit_err_cnt_15_8_pos 0
+#define fec_rsd_bit_err_cnt_15_8_len 8
+#define fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389
+#define fec_rsd_bit_err_cnt_23_16_pos 0
+#define fec_rsd_bit_err_cnt_23_16_len 8
+#define fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A
+#define fec_rsd_abort_packet_cnt_7_0_pos 0
+#define fec_rsd_abort_packet_cnt_7_0_len 8
+#define fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B
+#define fec_rsd_abort_packet_cnt_15_8_pos 0
+#define fec_rsd_abort_packet_cnt_15_8_len 8
+#define fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0 0xA38E
+#define fec_RS_TH_1_7_0_pos 0
+#define fec_RS_TH_1_7_0_len 8
+#define fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8 0xA38F
+#define fec_RS_TH_1_15_8_pos 0
+#define fec_RS_TH_1_15_8_len 8
+#define fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2 0xA390
+#define fec_RS_TH_2_pos 0
+#define fec_RS_TH_2_len 8
+#define fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en 0xA391
+#define fec_mon_en_pos 0
+#define fec_mon_en_len 1
+#define fec_mon_en_lsb 0
+#define xd_p_reg_b8to47 0xA391
+#define reg_b8to47_pos 1
+#define reg_b8to47_len 1
+#define reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep 0xA391
+#define reg_rsd_sync_rep_pos 2
+#define reg_rsd_sync_rep_len 1
+#define reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst 0xA391
+#define fec_rsd_retrain_rst_pos 3
+#define fec_rsd_retrain_rst_len 1
+#define fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy 0xA391
+#define fec_rsd_ber_rdy_pos 4
+#define fec_rsd_ber_rdy_len 1
+#define fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst 0xA391
+#define fec_rsd_ber_rst_pos 5
+#define fec_rsd_ber_rst_len 1
+#define fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy 0xA391
+#define fec_vtb_ber_rdy_pos 6
+#define fec_vtb_ber_rdy_len 1
+#define fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst 0xA391
+#define fec_vtb_ber_rst_pos 7
+#define fec_vtb_ber_rst_len 1
+#define fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en 0xA392
+#define reg_vtb_clk40en_pos 0
+#define reg_vtb_clk40en_len 1
+#define reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en 0xA392
+#define fec_vtb_rsd_mon_en_pos 1
+#define fec_vtb_rsd_mon_en_len 1
+#define fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en 0xA392
+#define reg_fec_data_en_pos 2
+#define reg_fec_data_en_len 1
+#define reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2 0xA392
+#define fec_dummy_reg_2_pos 3
+#define fec_dummy_reg_2_len 3
+#define fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk 0xA392
+#define reg_sync_chk_pos 6
+#define reg_sync_chk_len 1
+#define reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass 0xA392
+#define fec_rsd_bypass_pos 7
+#define fec_rsd_bypass_len 1
+#define fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst 0xA393
+#define fec_sw_rst_pos 0
+#define fec_sw_rst_len 1
+#define fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc 0xA394
+#define fec_vtb_pm_crc_pos 0
+#define fec_vtb_pm_crc_len 8
+#define fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc 0xA395
+#define fec_vtb_tb_7_crc_pos 0
+#define fec_vtb_tb_7_crc_len 8
+#define fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc 0xA396
+#define fec_vtb_tb_6_crc_pos 0
+#define fec_vtb_tb_6_crc_len 8
+#define fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc 0xA397
+#define fec_vtb_tb_5_crc_pos 0
+#define fec_vtb_tb_5_crc_len 8
+#define fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc 0xA398
+#define fec_vtb_tb_4_crc_pos 0
+#define fec_vtb_tb_4_crc_len 8
+#define fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc 0xA399
+#define fec_vtb_tb_3_crc_pos 0
+#define fec_vtb_tb_3_crc_len 8
+#define fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc 0xA39A
+#define fec_vtb_tb_2_crc_pos 0
+#define fec_vtb_tb_2_crc_len 8
+#define fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc 0xA39B
+#define fec_vtb_tb_1_crc_pos 0
+#define fec_vtb_tb_1_crc_len 8
+#define fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc 0xA39C
+#define fec_vtb_tb_0_crc_pos 0
+#define fec_vtb_tb_0_crc_len 8
+#define fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc 0xA39D
+#define fec_rsd_bank0_crc_pos 0
+#define fec_rsd_bank0_crc_len 8
+#define fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc 0xA39E
+#define fec_rsd_bank1_crc_pos 0
+#define fec_rsd_bank1_crc_len 8
+#define fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc 0xA39F
+#define fec_idi_vtb_crc_pos 0
+#define fec_idi_vtb_crc_len 8
+#define fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod 0xA3C0
+#define reg_tpsd_txmod_pos 0
+#define reg_tpsd_txmod_len 2
+#define reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi 0xA3C0
+#define reg_tpsd_gi_pos 2
+#define reg_tpsd_gi_len 2
+#define reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier 0xA3C0
+#define reg_tpsd_hier_pos 4
+#define reg_tpsd_hier_len 3
+#define reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw 0xA3C1
+#define reg_bw_pos 2
+#define reg_bw_len 2
+#define reg_bw_lsb 0
+#define xd_g_reg_dec_pri 0xA3C1
+#define reg_dec_pri_pos 4
+#define reg_dec_pri_len 1
+#define reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const 0xA3C1
+#define reg_tpsd_const_pos 6
+#define reg_tpsd_const_len 2
+#define reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr 0xA3C2
+#define reg_tpsd_hpcr_pos 0
+#define reg_tpsd_hpcr_len 3
+#define reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr 0xA3C2
+#define reg_tpsd_lpcr_pos 3
+#define reg_tpsd_lpcr_len 3
+#define reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk 0xA3D0
+#define reg_ofsm_clk_pos 0
+#define reg_ofsm_clk_len 3
+#define reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg 0xA3D1
+#define reg_fclk_cfg_pos 0
+#define reg_fclk_cfg_len 1
+#define reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi 0xA3D1
+#define reg_fclk_idi_pos 1
+#define reg_fclk_idi_len 1
+#define reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi 0xA3D1
+#define reg_fclk_odi_pos 2
+#define reg_fclk_odi_len 1
+#define reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd 0xA3D1
+#define reg_fclk_rsd_pos 3
+#define reg_fclk_rsd_len 1
+#define reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb 0xA3D1
+#define reg_fclk_vtb_pos 4
+#define reg_fclk_vtb_len 1
+#define reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste 0xA3D1
+#define reg_fclk_cste_pos 5
+#define reg_fclk_cste_len 1
+#define reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if 0xA3D1
+#define reg_fclk_mp2if_pos 6
+#define reg_fclk_mp2if_len 1
+#define reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr 0xA400
+#define i2c_m_slave_addr_pos 0
+#define i2c_m_slave_addr_len 8
+#define i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1 0xA401
+#define i2c_m_data1_pos 0
+#define i2c_m_data1_len 8
+#define i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2 0xA402
+#define i2c_m_data2_pos 0
+#define i2c_m_data2_len 8
+#define i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3 0xA403
+#define i2c_m_data3_pos 0
+#define i2c_m_data3_len 8
+#define i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4 0xA404
+#define i2c_m_data4_pos 0
+#define i2c_m_data4_len 8
+#define i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5 0xA405
+#define i2c_m_data5_pos 0
+#define i2c_m_data5_len 8
+#define i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6 0xA406
+#define i2c_m_data6_pos 0
+#define i2c_m_data6_len 8
+#define i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7 0xA407
+#define i2c_m_data7_pos 0
+#define i2c_m_data7_len 8
+#define i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8 0xA408
+#define i2c_m_data8_pos 0
+#define i2c_m_data8_len 8
+#define i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9 0xA409
+#define i2c_m_data9_pos 0
+#define i2c_m_data9_len 8
+#define i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10 0xA40A
+#define i2c_m_data10_pos 0
+#define i2c_m_data10_len 8
+#define i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11 0xA40B
+#define i2c_m_data11_pos 0
+#define i2c_m_data11_len 8
+#define i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw 0xA40C
+#define i2c_m_cmd_rw_pos 0
+#define i2c_m_cmd_rw_len 1
+#define i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen 0xA40C
+#define i2c_m_cmd_rwlen_pos 3
+#define i2c_m_cmd_rwlen_len 4
+#define i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe 0xA40D
+#define i2c_m_status_cmd_exe_pos 0
+#define i2c_m_status_cmd_exe_len 1
+#define i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done 0xA40D
+#define i2c_m_status_wdat_done_pos 1
+#define i2c_m_status_wdat_done_len 1
+#define i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail 0xA40D
+#define i2c_m_status_wdat_fail_pos 2
+#define i2c_m_status_wdat_fail_len 1
+#define i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period 0xA40E
+#define i2c_m_period_pos 0
+#define i2c_m_period_len 8
+#define i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F
+#define i2c_m_reg_msb_lsb_pos 0
+#define i2c_m_reg_msb_lsb_len 1
+#define i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst 0xA40F
+#define reg_ofdm_rst_pos 1
+#define reg_ofdm_rst_len 1
+#define reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner 0xA40F
+#define reg_sample_period_on_tuner_pos 2
+#define reg_sample_period_on_tuner_len 1
+#define reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c 0xA40F
+#define reg_rst_i2c_pos 3
+#define reg_rst_i2c_len 1
+#define reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en 0xA40F
+#define reg_ofdm_rst_en_pos 4
+#define reg_ofdm_rst_en_len 1
+#define reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on 0xA40F
+#define reg_tuner_sda_sync_on_pos 5
+#define reg_tuner_sda_sync_on_len 1
+#define reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm 0xA500
+#define mp2if_data_access_disable_ofsm_pos 0
+#define mp2if_data_access_disable_ofsm_len 1
+#define mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm 0xA500
+#define reg_mp2_sw_rst_ofsm_pos 1
+#define reg_mp2_sw_rst_ofsm_len 1
+#define reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm 0xA500
+#define reg_mp2if_clk_en_ofsm_pos 2
+#define reg_mp2if_clk_en_ofsm_len 1
+#define reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked 0xA500
+#define mp2if_sync_byte_locked_pos 3
+#define mp2if_sync_byte_locked_len 1
+#define mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188 0xA500
+#define mp2if_ts_not_188_pos 4
+#define mp2if_ts_not_188_len 1
+#define mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty 0xA500
+#define mp2if_psb_empty_pos 5
+#define mp2if_psb_empty_len 1
+#define mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow 0xA500
+#define mp2if_psb_overflow_pos 6
+#define mp2if_psb_overflow_len 1
+#define mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500
+#define mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define mp2if_keep_sf_sync_byte_ofsm_len 1
+#define mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501
+#define mp2if_psb_mp2if_num_pkt_pos 0
+#define mp2if_psb_mp2if_num_pkt_len 6
+#define mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm 0xA501
+#define reg_mpeg_full_speed_ofsm_pos 6
+#define reg_mpeg_full_speed_ofsm_len 1
+#define reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501
+#define mp2if_mpeg_ser_mode_ofsm_pos 7
+#define mp2if_mpeg_ser_mode_ofsm_len 1
+#define mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51 0xA600
+#define reg_sw_mon51_pos 0
+#define reg_sw_mon51_len 8
+#define reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel 0xA601
+#define reg_top_pcsel_pos 0
+#define reg_top_pcsel_len 1
+#define reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232 0xA601
+#define reg_top_rs232_pos 1
+#define reg_top_rs232_len 1
+#define reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout 0xA601
+#define reg_top_pcout_pos 2
+#define reg_top_pcout_len 1
+#define reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug 0xA601
+#define reg_top_debug_pos 3
+#define reg_top_debug_len 1
+#define reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly 0xA601
+#define reg_top_adcdly_pos 4
+#define reg_top_adcdly_len 2
+#define reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw 0xA601
+#define reg_top_pwrdw_pos 6
+#define reg_top_pwrdw_len 1
+#define reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv 0xA601
+#define reg_top_pwrdw_inv_pos 7
+#define reg_top_pwrdw_inv_len 1
+#define reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv 0xA602
+#define reg_top_int_inv_pos 0
+#define reg_top_int_inv_len 1
+#define reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel 0xA602
+#define reg_top_dio_sel_pos 1
+#define reg_top_dio_sel_len 1
+#define reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0 0xA603
+#define reg_top_gpioon0_pos 0
+#define reg_top_gpioon0_len 1
+#define reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1 0xA603
+#define reg_top_gpioon1_pos 1
+#define reg_top_gpioon1_len 1
+#define reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2 0xA603
+#define reg_top_gpioon2_pos 2
+#define reg_top_gpioon2_len 1
+#define reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3 0xA603
+#define reg_top_gpioon3_pos 3
+#define reg_top_gpioon3_len 1
+#define reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1 0xA603
+#define reg_top_lockon1_pos 4
+#define reg_top_lockon1_len 1
+#define reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2 0xA603
+#define reg_top_lockon2_pos 5
+#define reg_top_lockon2_len 1
+#define reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0 0xA604
+#define reg_top_gpioo0_pos 0
+#define reg_top_gpioo0_len 1
+#define reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1 0xA604
+#define reg_top_gpioo1_pos 1
+#define reg_top_gpioo1_len 1
+#define reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2 0xA604
+#define reg_top_gpioo2_pos 2
+#define reg_top_gpioo2_len 1
+#define reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3 0xA604
+#define reg_top_gpioo3_pos 3
+#define reg_top_gpioo3_len 1
+#define reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1 0xA604
+#define reg_top_lock1_pos 4
+#define reg_top_lock1_len 1
+#define reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2 0xA604
+#define reg_top_lock2_pos 5
+#define reg_top_lock2_len 1
+#define reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0 0xA605
+#define reg_top_gpioen0_pos 0
+#define reg_top_gpioen0_len 1
+#define reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1 0xA605
+#define reg_top_gpioen1_pos 1
+#define reg_top_gpioen1_len 1
+#define reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2 0xA605
+#define reg_top_gpioen2_pos 2
+#define reg_top_gpioen2_len 1
+#define reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3 0xA605
+#define reg_top_gpioen3_pos 3
+#define reg_top_gpioen3_len 1
+#define reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1 0xA605
+#define reg_top_locken1_pos 4
+#define reg_top_locken1_len 1
+#define reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2 0xA605
+#define reg_top_locken2_pos 5
+#define reg_top_locken2_len 1
+#define reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0 0xA606
+#define reg_top_gpioi0_pos 0
+#define reg_top_gpioi0_len 1
+#define reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1 0xA606
+#define reg_top_gpioi1_pos 1
+#define reg_top_gpioi1_len 1
+#define reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2 0xA606
+#define reg_top_gpioi2_pos 2
+#define reg_top_gpioi2_len 1
+#define reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3 0xA606
+#define reg_top_gpioi3_pos 3
+#define reg_top_gpioi3_len 1
+#define reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1 0xA606
+#define reg_top_locki1_pos 4
+#define reg_top_locki1_len 1
+#define reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2 0xA606
+#define reg_top_locki2_pos 5
+#define reg_top_locki2_len 1
+#define reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0 0xA608
+#define reg_dummy_7_0_pos 0
+#define reg_dummy_7_0_len 8
+#define reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8 0xA609
+#define reg_dummy_15_8_pos 0
+#define reg_dummy_15_8_len 8
+#define reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16 0xA60A
+#define reg_dummy_23_16_pos 0
+#define reg_dummy_23_16_len 8
+#define reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24 0xA60B
+#define reg_dummy_31_24_pos 0
+#define reg_dummy_31_24_len 8
+#define reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32 0xA60C
+#define reg_dummy_39_32_pos 0
+#define reg_dummy_39_32_len 8
+#define reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40 0xA60D
+#define reg_dummy_47_40_pos 0
+#define reg_dummy_47_40_len 8
+#define reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48 0xA60E
+#define reg_dummy_55_48_pos 0
+#define reg_dummy_55_48_len 8
+#define reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56 0xA60F
+#define reg_dummy_63_56_pos 0
+#define reg_dummy_63_56_len 8
+#define reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64 0xA610
+#define reg_dummy_71_64_pos 0
+#define reg_dummy_71_64_len 8
+#define reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72 0xA611
+#define reg_dummy_79_72_pos 0
+#define reg_dummy_79_72_len 8
+#define reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80 0xA612
+#define reg_dummy_87_80_pos 0
+#define reg_dummy_87_80_len 8
+#define reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88 0xA613
+#define reg_dummy_95_88_pos 0
+#define reg_dummy_95_88_len 8
+#define reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96 0xA614
+#define reg_dummy_103_96_pos 0
+#define reg_dummy_103_96_len 8
+#define reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag 0xA615
+#define reg_unplug_flag_pos 0
+#define reg_unplug_flag_len 1
+#define reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request 0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag 0xA615
+#define reg_back_to_dca_flag_pos 2
+#define reg_back_to_dca_flag_len 1
+#define reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request 0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag 0xA615
+#define reg_Dyn_Top_Try_flag_pos 3
+#define reg_Dyn_Top_Try_flag_len 1
+#define reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag 0xA615
+#define reg_API_retrain_freeze_flag_pos 4
+#define reg_API_retrain_freeze_flag_len 1
+#define reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104 0xA615
+#define reg_dummy_111_104_pos 0
+#define reg_dummy_111_104_len 8
+#define reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112 0xA616
+#define reg_dummy_119_112_pos 0
+#define reg_dummy_119_112_len 8
+#define reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120 0xA617
+#define reg_dummy_127_120_pos 0
+#define reg_dummy_127_120_len 8
+#define reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128 0xA618
+#define reg_dummy_135_128_pos 0
+#define reg_dummy_135_128_len 8
+#define reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136 0xA619
+#define reg_dummy_143_136_pos 0
+#define reg_dummy_143_136_len 8
+#define reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis 0xA619
+#define reg_CCIR_dis_pos 0
+#define reg_CCIR_dis_len 1
+#define reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144 0xA61A
+#define reg_dummy_151_144_pos 0
+#define reg_dummy_151_144_len 8
+#define reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152 0xA61B
+#define reg_dummy_159_152_pos 0
+#define reg_dummy_159_152_len 8
+#define reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160 0xA61C
+#define reg_dummy_167_160_pos 0
+#define reg_dummy_167_160_len 8
+#define reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168 0xA61D
+#define reg_dummy_175_168_pos 0
+#define reg_dummy_175_168_len 8
+#define reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176 0xA61E
+#define reg_dummy_183_176_pos 0
+#define reg_dummy_183_176_len 8
+#define reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en 0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis 0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0 0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8 0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16 0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184 0xA61F
+#define reg_dummy_191_184_pos 0
+#define reg_dummy_191_184_len 8
+#define reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192 0xA620
+#define reg_dummy_199_192_pos 0
+#define reg_dummy_199_192_len 8
+#define reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en 0xABC0
+#define reg_ce_en_pos 0
+#define reg_ce_en_len 1
+#define reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en 0xABC0
+#define reg_ce_fctrl_en_pos 1
+#define reg_ce_fctrl_en_len 1
+#define reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi 0xABC0
+#define reg_ce_fste_tdi_pos 2
+#define reg_ce_fste_tdi_len 1
+#define reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic 0xABC0
+#define reg_ce_dynamic_pos 3
+#define reg_ce_dynamic_len 1
+#define reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf 0xABC0
+#define reg_ce_conf_pos 4
+#define reg_ce_conf_len 2
+#define reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12 0xABC0
+#define reg_ce_dyn12_pos 6
+#define reg_ce_dyn12_len 1
+#define reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en 0xABC0
+#define reg_ce_derot_en_pos 7
+#define reg_ce_derot_en_len 1
+#define reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0 0xABC1
+#define reg_ce_dynamic_th_7_0_pos 0
+#define reg_ce_dynamic_th_7_0_len 8
+#define reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8 0xABC2
+#define reg_ce_dynamic_th_15_8_pos 0
+#define reg_ce_dynamic_th_15_8_len 8
+#define reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1 0xABC3
+#define reg_ce_s1_pos 0
+#define reg_ce_s1_len 5
+#define reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value 0xABC3
+#define reg_ce_var_forced_value_pos 5
+#define reg_ce_var_forced_value_len 3
+#define reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0 0xABC4
+#define reg_ce_data_im_7_0_pos 0
+#define reg_ce_data_im_7_0_len 8
+#define reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8 0xABC5
+#define reg_ce_data_im_8_pos 0
+#define reg_ce_data_im_8_len 1
+#define reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0 0xABC5
+#define reg_ce_data_re_6_0_pos 1
+#define reg_ce_data_re_6_0_len 7
+#define reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7 0xABC6
+#define reg_ce_data_re_8_7_pos 0
+#define reg_ce_data_re_8_7_len 2
+#define reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0 0xABC6
+#define reg_ce_tone_5_0_pos 2
+#define reg_ce_tone_5_0_len 6
+#define reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6 0xABC7
+#define reg_ce_tone_12_6_pos 0
+#define reg_ce_tone_12_6_len 7
+#define reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th 0xABC8
+#define reg_ce_centroid_drift_th_pos 0
+#define reg_ce_centroid_drift_th_len 8
+#define reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max 0xABC9
+#define reg_ce_centroid_count_max_pos 0
+#define reg_ce_centroid_count_max_len 4
+#define reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA
+#define reg_ce_centroid_bias_inc_7_0_pos 0
+#define reg_ce_centroid_bias_inc_7_0_len 8
+#define reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB
+#define reg_ce_centroid_bias_inc_8_pos 0
+#define reg_ce_centroid_bias_inc_8_len 1
+#define reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0 0xABCC
+#define reg_ce_var_th0_7_0_pos 0
+#define reg_ce_var_th0_7_0_len 8
+#define reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8 0xABCD
+#define reg_ce_var_th0_15_8_pos 0
+#define reg_ce_var_th0_15_8_len 8
+#define reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0 0xABCE
+#define reg_ce_var_th1_7_0_pos 0
+#define reg_ce_var_th1_7_0_len 8
+#define reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8 0xABCF
+#define reg_ce_var_th1_15_8_pos 0
+#define reg_ce_var_th1_15_8_len 8
+#define reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0 0xABD0
+#define reg_ce_var_th2_7_0_pos 0
+#define reg_ce_var_th2_7_0_len 8
+#define reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8 0xABD1
+#define reg_ce_var_th2_15_8_pos 0
+#define reg_ce_var_th2_15_8_len 8
+#define reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0 0xABD2
+#define reg_ce_var_th3_7_0_pos 0
+#define reg_ce_var_th3_7_0_len 8
+#define reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8 0xABD3
+#define reg_ce_var_th3_15_8_pos 0
+#define reg_ce_var_th3_15_8_len 8
+#define reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0 0xABD4
+#define reg_ce_var_th4_7_0_pos 0
+#define reg_ce_var_th4_7_0_len 8
+#define reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8 0xABD5
+#define reg_ce_var_th4_15_8_pos 0
+#define reg_ce_var_th4_15_8_len 8
+#define reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0 0xABD6
+#define reg_ce_var_th5_7_0_pos 0
+#define reg_ce_var_th5_7_0_len 8
+#define reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8 0xABD7
+#define reg_ce_var_th5_15_8_pos 0
+#define reg_ce_var_th5_15_8_len 8
+#define reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0 0xABD8
+#define reg_ce_var_th6_7_0_pos 0
+#define reg_ce_var_th6_7_0_len 8
+#define reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8 0xABD9
+#define reg_ce_var_th6_15_8_pos 0
+#define reg_ce_var_th6_15_8_len 8
+#define reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset 0xABDA
+#define reg_ce_fctrl_reset_pos 0
+#define reg_ce_fctrl_reset_len 1
+#define reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en 0xABDA
+#define reg_ce_cent_auto_clr_en_pos 1
+#define reg_ce_cent_auto_clr_en_len 1
+#define reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA
+#define reg_ce_fctrl_auto_reset_en_pos 2
+#define reg_ce_fctrl_auto_reset_en_len 1
+#define reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en 0xABDA
+#define reg_ce_var_forced_en_pos 3
+#define reg_ce_var_forced_en_len 1
+#define reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en 0xABDA
+#define reg_ce_cent_forced_en_pos 4
+#define reg_ce_cent_forced_en_len 1
+#define reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max 0xABDA
+#define reg_ce_var_max_pos 5
+#define reg_ce_var_max_len 3
+#define reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB
+#define reg_ce_cent_forced_value_7_0_pos 0
+#define reg_ce_cent_forced_value_7_0_len 8
+#define reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC
+#define reg_ce_cent_forced_value_11_8_pos 0
+#define reg_ce_cent_forced_value_11_8_len 4
+#define reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd 0xABDD
+#define reg_ce_fctrl_rd_pos 0
+#define reg_ce_fctrl_rd_len 1
+#define reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0 0xABDD
+#define reg_ce_centroid_max_6_0_pos 1
+#define reg_ce_centroid_max_6_0_len 7
+#define reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7 0xABDE
+#define reg_ce_centroid_max_11_7_pos 0
+#define reg_ce_centroid_max_11_7_len 5
+#define reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var 0xABDF
+#define reg_ce_var_pos 0
+#define reg_ce_var_len 3
+#define reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy 0xABDF
+#define reg_ce_fctrl_rdy_pos 3
+#define reg_ce_fctrl_rdy_len 1
+#define reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0 0xABDF
+#define reg_ce_centroid_out_3_0_pos 4
+#define reg_ce_centroid_out_3_0_len 4
+#define reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4 0xABE0
+#define reg_ce_centroid_out_11_4_pos 0
+#define reg_ce_centroid_out_11_4_len 8
+#define reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0 0xABE1
+#define reg_ce_bias_7_0_pos 0
+#define reg_ce_bias_7_0_len 8
+#define reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8 0xABE2
+#define reg_ce_bias_11_8_pos 0
+#define reg_ce_bias_11_8_len 4
+#define reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0 0xABE2
+#define reg_ce_m1_3_0_pos 4
+#define reg_ce_m1_3_0_len 4
+#define reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4 0xABE3
+#define reg_ce_m1_11_4_pos 0
+#define reg_ce_m1_11_4_len 8
+#define reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0 0xABE4
+#define reg_ce_rh0_7_0_pos 0
+#define reg_ce_rh0_7_0_len 8
+#define reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8 0xABE5
+#define reg_ce_rh0_15_8_pos 0
+#define reg_ce_rh0_15_8_len 8
+#define reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16 0xABE6
+#define reg_ce_rh0_23_16_pos 0
+#define reg_ce_rh0_23_16_len 8
+#define reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24 0xABE7
+#define reg_ce_rh0_31_24_pos 0
+#define reg_ce_rh0_31_24_len 8
+#define reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0 0xABE8
+#define reg_ce_rh3_real_7_0_pos 0
+#define reg_ce_rh3_real_7_0_len 8
+#define reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8 0xABE9
+#define reg_ce_rh3_real_15_8_pos 0
+#define reg_ce_rh3_real_15_8_len 8
+#define reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16 0xABEA
+#define reg_ce_rh3_real_23_16_pos 0
+#define reg_ce_rh3_real_23_16_len 8
+#define reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24 0xABEB
+#define reg_ce_rh3_real_31_24_pos 0
+#define reg_ce_rh3_real_31_24_len 8
+#define reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0 0xABEC
+#define reg_ce_rh3_imag_7_0_pos 0
+#define reg_ce_rh3_imag_7_0_len 8
+#define reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8 0xABED
+#define reg_ce_rh3_imag_15_8_pos 0
+#define reg_ce_rh3_imag_15_8_len 8
+#define reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16 0xABEE
+#define reg_ce_rh3_imag_23_16_pos 0
+#define reg_ce_rh3_imag_23_16_len 8
+#define reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24 0xABEF
+#define reg_ce_rh3_imag_31_24_pos 0
+#define reg_ce_rh3_imag_31_24_len 8
+#define reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0 0xABF0
+#define reg_feq_fix_eh2_7_0_pos 0
+#define reg_feq_fix_eh2_7_0_len 8
+#define reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8 0xABF1
+#define reg_feq_fix_eh2_15_8_pos 0
+#define reg_feq_fix_eh2_15_8_len 8
+#define reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16 0xABF2
+#define reg_feq_fix_eh2_23_16_pos 0
+#define reg_feq_fix_eh2_23_16_len 8
+#define reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24 0xABF3
+#define reg_feq_fix_eh2_31_24_pos 0
+#define reg_feq_fix_eh2_31_24_len 8
+#define reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0 0xABF4
+#define reg_ce_m2_central_7_0_pos 0
+#define reg_ce_m2_central_7_0_len 8
+#define reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8 0xABF5
+#define reg_ce_m2_central_15_8_pos 0
+#define reg_ce_m2_central_15_8_len 8
+#define reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift 0xABF6
+#define reg_ce_fftshift_pos 0
+#define reg_ce_fftshift_len 4
+#define reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1 0xABF6
+#define reg_ce_fftshift1_pos 4
+#define reg_ce_fftshift1_len 4
+#define reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2 0xABF7
+#define reg_ce_fftshift2_pos 0
+#define reg_ce_fftshift2_len 4
+#define reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile 0xABF7
+#define reg_ce_top_mobile_pos 4
+#define reg_ce_top_mobile_len 1
+#define reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE 0xB000
+#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+ u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+ u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+ u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index bac2ae3..04e31cf 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -354,41 +354,35 @@
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
- u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- adap->pll_addr = 0x61;
- memcpy(adap->pll_init, bpll, 4);
- adap->pll_desc = &dvb_pll_fmd1216me;
-
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_FMD1216ME);
return 0;
}
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
return 0;
}
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 5143e42..9a184da 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -295,7 +295,7 @@
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
/* not found - use panasonic pll parameters */
- if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+ if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
return -ENOMEM;
} else {
st->mt2060_present = 1;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 7a6ae8f..043cada 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,6 +14,14 @@
*/
#include "dibusb.h"
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dibusb_state *st = adap->priv;
+
+ return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@
demod_cfg.demod_address = 0x8;
- if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+ if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+ &adap->dev->i2c_adap, &st->ops)) == NULL)
return -ENODEV;
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
- adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+ adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
return 0;
}
static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6010xs;
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x61;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_TUA6010XS);
+ return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x60;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+ DVB_PLL_TDA665X);
return 0;
}
@@ -50,30 +71,28 @@
{ .flags = 0, .buf = b, .len = 2 },
{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
};
+ struct dibusb_state *st = adap->priv;
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
- msg[0].addr = msg[1].addr = 0x60;
+ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
if (b2[0] == 0xfe) {
info("This device has the Thomson Cable onboard. Which is default.");
- dibusb_thomson_tuner_attach(adap);
+ ret = dibusb_thomson_tuner_attach(adap);
} else {
- u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("This device has the Panasonic ENV77H11D5 onboard.");
- adap->pll_addr = 0x60;
- memcpy(adap->pll_init,bpll,4);
- adap->pll_desc = &dvb_pll_tda665x;
+ ret = dibusb_panasonic_tuner_attach(adap);
}
return ret;
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index b607810..8e847aa 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -99,6 +99,7 @@
struct dibusb_state {
struct dib_fe_xfer_ops ops;
int mt2060_present;
+ u8 tuner_addr;
};
struct dibusb_device_state {
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index b5acb11..bca1e09 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -118,7 +118,8 @@
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
- dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+ fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@
static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct digitv_state *st = adap->dev->priv;
+
if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ st->is_nxt6000 = 0;
return 0;
}
if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ st->is_nxt6000 = 1;
return 0;
}
return -EIO;
@@ -143,8 +146,14 @@
static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x60;
- adap->pll_desc = &dvb_pll_tded4;
+ struct digitv_state *st = adap->dev->priv;
+
+ if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+ return -ENODEV;
+
+ if (st->is_nxt6000)
+ adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
return 0;
}
@@ -273,6 +282,8 @@
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-digitv-02.fw",
+ .size_of_priv = sizeof(struct digitv_state),
+
.num_adapters = 1,
.adapter = {
{
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
index 477ee42..8b43e3d 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -4,6 +4,10 @@
#define DVB_USB_LOG_PREFIX "digitv"
#include "dvb-usb.h"
+struct digitv_state {
+ int is_nxt6000;
+};
+
extern int dvb_usb_digitv_debug;
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 088b6de..23428cd 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,82 +46,3 @@
d->state &= ~DVB_USB_STATE_I2C;
return 0;
}
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
- int ret = 0;
-
- /* if pll_desc is not used */
- if (adap->pll_desc == NULL)
- return 0;
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- deb_pll("pll init: %x\n",adap->pll_addr);
- deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
- adap->pll_init[2], adap->pll_init[3]);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_init.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- if (buf_len != 5)
- return -EINVAL;
- if (adap->pll_desc == NULL)
- return 0;
-
- deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
- b[0] = adap->pll_addr;
- dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
- deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
- return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- int ret = 0;
- u8 b[5];
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
- dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_set.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 4030816..4dfab02 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,7 +11,9 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_AFATECH 0x15a4
#define USB_VID_ALCOR_MICRO 0x058f
+#define USB_VID_ALINK 0x05e3
#define USB_VID_ANCHOR 0x0547
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
#define USB_VID_AVERMEDIA 0x07ca
@@ -35,6 +37,7 @@
#define USB_VID_MSI 0x0db0
#define USB_VID_OPERA1 0x695c
#define USB_VID_PINNACLE 0x2304
+#define USB_VID_TERRATEC 0x0ccd
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
@@ -44,6 +47,8 @@
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_ADSTECH_USB2_WARM 0xa334
+#define USB_PID_AFATECH_AF9005 0x9020
+#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
@@ -69,6 +74,7 @@
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9200a30..7b9f35b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -110,7 +110,7 @@
input_dev->name = "IR-receiver inside an USB DVB receiver";
input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &input_dev->id);
- input_dev->cdev.dev = &d->udev->dev;
+ input_dev->dev.parent = &d->udev->dev;
/* set the bits for the keys */
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6f824a5..d1b3c7b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -297,12 +297,6 @@
int feedcount;
int pid_filtering;
- /* tuner programming information */
- u8 pll_addr;
- u8 pll_init[4];
- struct dvb_pll_desc *pll_desc;
- int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
@@ -388,11 +382,6 @@
/* commonly used remote control parsing */
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
/* commonly used firmware download types and function */
struct hexline {
u8 len;
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index e0587e6..f01d99c 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -157,6 +157,7 @@
static struct usb_device_id gl861_table [] = {
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+ { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@
}},
.i2c_algo = &gl861_i2c_algo,
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "MSI Mega Sky 55801 DVB-T USB2.0",
{ &gl861_table[0], NULL },
{ NULL },
},
+ { "A-LINK DTU DVB-T USB2.0",
+ { &gl861_table[1], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c546dde..a956bc5 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -22,6 +22,8 @@
module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
u16 index, void *data, int size)
{
@@ -57,7 +59,8 @@
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
- int ret = 0;
+ int ret = 0, i, epi, flags = 0;
+ int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
if (d->props.rc_query) {
@@ -76,9 +79,51 @@
deb("Initialising remote control success\n");
}
+ for (i = 0; i < d->props.num_adapters; i++)
+ flags |= d->adapter[i].props.caps;
+
+ /* Some devices(Dposh) might crash if we attempt touch at all. */
+ if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+ for (i = 0; i < d->props.num_adapters; i++) {
+ epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+ if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+ printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+ return -EINVAL;
+ }
+
+ adap_enabled[epi] = 1;
+ }
+
+ for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+ if (adap_enabled[i])
+ continue;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+ return ret;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+ return ret;
+ }
+ }
+
return ret;
}
+static int m920x_init_ep(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt;
+
+ if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+ deb("No alt found!\n");
+ return -ENODEV;
+ }
+
+ return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+}
+
static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@
};
/* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
- int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
{
int ret = 0;
@@ -221,10 +265,10 @@
pid |= 0x8000;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
return ret;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
return ret;
return ret;
@@ -233,40 +277,35 @@
static int m920x_update_filters(struct dvb_usb_adapter *adap)
{
struct m920x_state *m = adap->dev->priv;
- int enabled = m->filtering_enabled;
+ int enabled = m->filtering_enabled[adap->id];
int i, ret = 0, filter = 0;
+ int ep = adap->props.stream.endpoint;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if (m->filters[i] == 8192)
+ if (m->filters[adap->id][i] == 8192)
enabled = 0;
/* Disable all filters */
- if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
return ret;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
return ret;
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
- return ret;
-
/* Set */
if (enabled) {
for (i = 0; i < M9206_MAX_FILTERS; i++) {
- if (m->filters[i] == 0)
+ if (m->filters[adap->id][i] == 0)
continue;
- if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
return ret;
filter++;
}
}
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
- return ret;
-
return ret;
}
@@ -274,7 +313,7 @@
{
struct m920x_state *m = adap->dev->priv;
- m->filtering_enabled = onoff ? 1 : 0;
+ m->filtering_enabled[adap->id] = onoff ? 1 : 0;
return m920x_update_filters(adap);
}
@@ -283,7 +322,7 @@
{
struct m920x_state *m = adap->dev->priv;
- m->filters[index] = onoff ? pid : 0;
+ m->filters[adap->id][index] = onoff ? pid : 0;
return m920x_update_filters(adap);
}
@@ -368,6 +407,7 @@
/* demod configurations */
static int m920x_mt352_demod_init(struct dvb_frontend *fe)
{
+ int ret;
u8 config[] = { CONFIG, 0x3d };
u8 clock[] = { CLOCK_CTL, 0x30 };
u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@
u8 unk1[] = { 0x93, 0x1a };
u8 unk2[] = { 0xb5, 0x7a };
- mt352_write(fe, config, ARRAY_SIZE(config));
- mt352_write(fe, clock, ARRAY_SIZE(clock));
- mt352_write(fe, reset, ARRAY_SIZE(reset));
- mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
- mt352_write(fe, agc, ARRAY_SIZE(agc));
- mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
- mt352_write(fe, unk1, ARRAY_SIZE(unk1));
- mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
deb("Demod init!\n");
+ if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+ return ret;
+
return 0;
}
@@ -558,8 +606,7 @@
static int m920x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
+ struct dvb_usb_device *d = NULL;
int ret;
struct m920x_inits *rc_init_seq = NULL;
int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@
* tvwalkertwin_properties already configured both
* tuners, so there is nothing for us to do here
*/
-
- return -ENODEV;
}
found:
- alt = usb_altnum_to_altsetting(intf, 1);
- if (alt == NULL) {
- deb("No alt found!\n");
- return -ENODEV;
- }
-
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- if (ret < 0)
+ if ((ret = m920x_init_ep(intf)) < 0)
return ret;
- if ((ret = m920x_init(d, rc_init_seq)) != 0)
+ if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
return ret;
return ret;
@@ -737,9 +774,9 @@
*
* LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
* TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
* TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
*/
static struct dvb_usb_device_properties tvwalkertwin_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@
.size_of_priv = sizeof(struct m920x_state),
.identify_state = m920x_identify_state,
- .num_adapters = 1,
+ .num_adapters = 2,
.adapter = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 2c8942d..3753289 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,6 +18,7 @@
#define M9206_FW 0x30
#define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
/*
sequences found in logs:
@@ -60,8 +61,8 @@
*/
struct m920x_state {
- u16 filters[M9206_MAX_FILTERS];
- int filtering_enabled;
+ u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+ int filtering_enabled[M9206_MAX_ADAPTERS];
int rep_count;
};
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 518d7ad..d7c0495 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -263,7 +263,7 @@
{
dvb_attach(
dvb_pll_attach, adap->fe, 0xc0>>1,
- &adap->dev->i2c_adap, &dvb_pll_opera1
+ &adap->dev->i2c_adap, DVB_PLL_OPERA1
);
return 0;
}
@@ -435,9 +435,9 @@
{
const struct firmware *fw = NULL;
u8 *b, *p;
- int ret = 0, i;
+ int ret = 0, i,fpgasize=40;
u8 testval;
- info("start downloading fpga firmware");
+ info("start downloading fpga firmware %s",filename);
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@
/* clear fpga ? */
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
OPERA_WRITE_MSG);
- for (i = 0; p[i] != 0 && i < fw->size;) {
+ for (i = 0; i < fw->size;) {
+ if ( (fw->size - i) <fpgasize){
+ fpgasize=fw->size-i;
+ }
b = (u8 *) p + i;
if (opera1_xilinx_rw
- (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
- OPERA_WRITE_MSG) != b[0]
+ (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+ OPERA_WRITE_MSG) != fpgasize
) {
err("error while transferring firmware");
ret = -EINVAL;
break;
}
- i = i + 1 + b[0];
+ i = i + fpgasize;
}
/* restart the CPU */
if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@
static int opera1_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
struct usb_device *udev = interface_to_usbdev(intf);
if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
udev->descriptor.idVendor == USB_VID_OPERA1 &&
- (d == NULL
- || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
- ) {
+ opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+ ) {
return -EINVAL;
}
- if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+ if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
return -EINVAL;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index f77b48f..0dcab3d 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -65,9 +65,7 @@
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6034;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
return 0;
}
@@ -84,8 +82,8 @@
/* do not change the order of the ID table */
static struct usb_device_id umt_table [] = {
-/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, umt_table);
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 27f3865..156b062 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel DVB frontend device drivers.
#
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 335219e..1dc164d 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "cx22702.h"
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 732e94a..0834c06 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -917,7 +917,7 @@
static int cx24123_tune(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
int retval = 0;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 5f96ffd..0c0b947 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -24,6 +24,23 @@
#include "dvb-pll.h"
+struct dvb_pll_desc {
+ char *name;
+ u32 min;
+ u32 max;
+ u32 iffreq;
+ void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+ u8 *initdata;
+ u8 *sleepdata;
+ int count;
+ struct {
+ u32 limit;
+ u32 stepsize;
+ u8 config;
+ u8 cb;
+ } entries[12];
+};
+
/* ----------------------------------------------------------- */
/* descriptions */
@@ -38,7 +55,13 @@
0x50 = AGC Take over point = 103 dBuV */
static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/* 0x04 = 166.67 kHz divider
+
+ 0x80 = AGC Time constant 50ms Iagc = 9 uA
+ 0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
.name = "Thomson dtt7579",
.min = 177000000,
.max = 858000000,
@@ -52,9 +75,8 @@
{ 999999999, 166667, 0xf4, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
.name = "Thomson dtt7610",
.min = 44000000,
.max = 958000000,
@@ -66,19 +88,19 @@
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ == bandwidth)
+ if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
buf[3] |= 0x10;
}
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
.name = "Thomson dtt759x",
.min = 177000000,
.max = 896000000,
- .setbw = thomson_dtt759x_bw,
+ .set = thomson_dtt759x_bw,
.iffreq= 36166667,
.sleepdata = (u8[]){ 2, 0x84, 0x03 },
.count = 5,
@@ -90,9 +112,8 @@
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
.name = "LG z201",
.min = 174000000,
.max = 862000000,
@@ -107,9 +128,8 @@
{ 999999999, 166667, 0xfc, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_z201);
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
.name = "Microtune 4042 FI5",
.min = 57000000,
.max = 858000000,
@@ -121,9 +141,8 @@
{ 999999999, 62500, 0x8e, 0x31 },
},
};
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
.name = "Thomson dtt761x",
.min = 57000000,
@@ -137,9 +156,8 @@
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
.max = 862000000,
@@ -157,12 +175,11 @@
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_unknown_1);
/* Infineon TUA6010XS
* used in Thomson Cable Tuner
*/
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
.name = "Infineon TUA6010XS",
.min = 44250000,
.max = 858000000,
@@ -174,10 +191,9 @@
{ 999999999, 62500, 0x8e, 0x85 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
/* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
.name = "Panasonic ENV57H1XD5",
.min = 44250000,
.max = 858000000,
@@ -190,23 +206,23 @@
{ 999999999, 166667, 0xc2, 0xa4 },
},
};
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
.name = "Philips TDA6650/TDA6651",
.min = 44250000,
.max = 858000000,
- .setbw = tda665x_bw,
+ .set = tda665x_bw,
.iffreq= 36166667,
+ .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
.count = 12,
.entries = {
{ 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
@@ -223,36 +239,34 @@
{ 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
}
};
-EXPORT_SYMBOL(dvb_pll_tda665x);
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ != bandwidth)
+ if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
.name = "Infineon TUA6034",
.min = 44250000,
.max = 858000000,
.iffreq= 36166667,
.count = 3,
- .setbw = tua6034_bw,
+ .set = tua6034_bw,
.entries = {
{ 174500000, 62500, 0xce, 0x01 },
{ 230000000, 62500, 0xce, 0x02 },
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
* used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
.name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
@@ -265,23 +279,25 @@
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
*/
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+ params->frequency >= 158870000)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
.name = "Philips FMD1216ME",
.min = 50870000,
.max = 858000000,
.iffreq= 36125000,
- .setbw = fmd1216me_bw,
+ .set = fmd1216me_bw,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
.count = 7,
.entries = {
{ 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +309,22 @@
{ 999999999, 166667, 0xfc, 0x44 },
}
};
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x04;
}
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
.name = "ALPS TDED4",
.min = 47000000,
.max = 863000000,
.iffreq= 36166667,
- .setbw = tded4_bw,
+ .set = tded4_bw,
.count = 4,
.entries = {
{ 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +333,11 @@
{ 999999999, 166667, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tded4);
/* ALPS TDHU2
* used in AverTVHD MCE A180
*/
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
.name = "ALPS TDHU2",
.min = 54000000,
.max = 864000000,
@@ -336,16 +350,29 @@
{ 999999999, 62500, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tdhu2);
/* Philips TUV1236D
* used in ATI HDTV Wonder
*/
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+{
+ switch (params->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ buf[3] |= 0x08;
+ break;
+ case VSB_8:
+ default:
+ buf[3] &= ~0x08;
+ }
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
.name = "Philips TUV1236D",
.min = 54000000,
.max = 864000000,
.iffreq= 44000000,
+ .set = tuv1236d_rf,
.count = 3,
.entries = {
{ 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +380,11 @@
{ 999999999, 62500, 0xc6, 0x44 },
},
};
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
/* Samsung TBMV30111IN / TBMV30712IN1
* used in Air2PC ATSC - 2nd generation (nxt2002)
*/
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
.name = "Samsung TBMV30111IN / TBMV30712IN1",
.min = 54000000,
.max = 860000000,
@@ -373,12 +399,11 @@
{ 999999999, 166667, 0xfc, 0x02 },
}
};
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
/*
* Philips SD1878 Tuner.
*/
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
.name = "Philips SD1878",
.min = 950000,
.max = 2150000,
@@ -391,19 +416,18 @@
{ 2150000, 500, 0xc4, 0xc0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
/*
* Philips TD1316 Tuner.
*/
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
u8 band;
/* determine band */
- if (freq < 161000000)
+ if (params->frequency < 161000000)
band = 1;
- else if (freq < 444000000)
+ else if (params->frequency < 444000000)
band = 2;
else
band = 4;
@@ -411,16 +435,16 @@
buf[3] |= band;
/* setup PLL filter */
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 1 << 3;
}
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
.name = "Philips TD1316",
.min = 87000000,
.max = 895000000,
.iffreq= 36166667,
- .setbw = td1316_bw,
+ .set = td1316_bw,
.count = 9,
.entries = {
{ 93834000, 166667, 0xca, 0x60},
@@ -434,10 +458,9 @@
{ 858834000, 166667, 0xca, 0xe0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
/* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
.name = "Thomson FE6600",
.min = 44250000,
.max = 858000000,
@@ -450,19 +473,19 @@
{ 999999999, 166667, 0xf4, 0x18 },
}
};
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[2] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
.name = "Opera Tuner",
.min = 900000,
.max = 2250000,
.iffreq= 0,
- .setbw = opera1_bw,
+ .set = opera1_bw,
.count = 8,
.entries = {
{ 1064000, 500, 0xe5, 0xc6 },
@@ -475,7 +498,54 @@
{ 2250000, 500, 0xe5, 0xc4 },
}
};
-EXPORT_SYMBOL(dvb_pll_opera1);
+
+/* Philips FCV1236D
+ */
+struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+ .name = "Philips FCV1236D",
+ .min = 53000000,
+ .max = 803000000,
+ .iffreq= 44000000,
+ .count = 3,
+ .entries = {
+ { 159000000, 62500, 0x8e, 0xa0 },
+ { 453000000, 62500, 0x8e, 0x90 },
+ { 999999999, 62500, 0x8e, 0x30 },
+ },
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+ [DVB_PLL_UNDEFINED] = NULL,
+ [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
+ [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
+ [DVB_PLL_THOMSON_DTT7610] = &dvb_pll_thomson_dtt7610,
+ [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
+ [DVB_PLL_MICROTUNE_4042] = &dvb_pll_microtune_4042,
+ [DVB_PLL_THOMSON_DTT761X] = &dvb_pll_thomson_dtt761x,
+ [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
+ [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
+ [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
+ [DVB_PLL_TUA6034] = &dvb_pll_tua6034,
+ [DVB_PLL_LG_TDVS_H06XF] = &dvb_pll_lg_tdvs_h06xf,
+ [DVB_PLL_TDA665X] = &dvb_pll_tda665x,
+ [DVB_PLL_FMD1216ME] = &dvb_pll_fmd1216me,
+ [DVB_PLL_TDED4] = &dvb_pll_tded4,
+ [DVB_PLL_TUV1236D] = &dvb_pll_tuv1236d,
+ [DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
+ [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
+ [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+ [DVB_PLL_PHILIPS_TD1316] = &dvb_pll_philips_td1316,
+ [DVB_PLL_THOMSON_FE6600] = &dvb_pll_thomson_fe6600,
+ [DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d,
+};
+
+/* ----------------------------------------------------------- */
struct dvb_pll_priv {
/* i2c details */
@@ -497,35 +567,37 @@
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)
+static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
u32 div;
int i;
- if (freq != 0 && (freq < desc->min || freq > desc->max))
- return -EINVAL;
+ if (params->frequency != 0 && (params->frequency < desc->min ||
+ params->frequency > desc->max))
+ return -EINVAL;
for (i = 0; i < desc->count; i++) {
- if (freq > desc->entries[i].limit)
+ if (params->frequency > 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);
+ printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+ params->frequency, i, desc->count);
if (i == desc->count)
return -EINVAL;
- div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
- desc->entries[i].stepsize;
+ div = (params->frequency + desc->iffreq +
+ desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
buf[0] = div >> 8;
buf[1] = div & 0xff;
buf[2] = desc->entries[i].config;
buf[3] = desc->entries[i].cb;
- if (desc->setbw)
- desc->setbw(buf, freq, bandwidth);
+ if (desc->set)
+ desc->set(buf, params);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +606,6 @@
// calculate the frequency we set it to
return (div * desc->entries[i].stepsize) - desc->iffreq;
}
-EXPORT_SYMBOL(dvb_pll_configure);
static int dvb_pll_release(struct dvb_frontend *fe)
{
@@ -578,18 +649,12 @@
{ .addr = priv->pll_i2c_address, .flags = 0,
.buf = buf, .len = sizeof(buf) };
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (priv->i2c == NULL)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
return result;
else
frequency = result;
@@ -601,7 +666,7 @@
}
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
}
@@ -612,18 +677,12 @@
{
struct dvb_pll_priv *priv = fe->tuner_priv;
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (buf_len < 5)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
return result;
else
frequency = result;
@@ -631,7 +690,7 @@
buf[0] = priv->pll_i2c_address;
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 5;
}
@@ -687,13 +746,18 @@
struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
u8 b1 [] = { 0 };
struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
.buf = b1, .len = 1 };
struct dvb_pll_priv *priv = NULL;
int ret;
+ struct dvb_pll_desc *desc;
+
+ BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+ desc = pll_list[pll_desc_id];
if (i2c != NULL) {
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 5209f46..e93a810 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -8,50 +8,29 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-struct dvb_pll_desc {
- char *name;
- u32 min;
- u32 max;
- u32 iffreq;
- void (*setbw)(u8 *buf, u32 freq, int bandwidth);
- u8 *initdata;
- u8 *sleepdata;
- int count;
- struct {
- u32 limit;
- u32 stepsize;
- u8 config;
- u8 cb;
- } entries[12];
-};
-
-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_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED 0
+#define DVB_PLL_THOMSON_DTT7579 1
+#define DVB_PLL_THOMSON_DTT759X 2
+#define DVB_PLL_THOMSON_DTT7610 3
+#define DVB_PLL_LG_Z201 4
+#define DVB_PLL_MICROTUNE_4042 5
+#define DVB_PLL_THOMSON_DTT761X 6
+#define DVB_PLL_UNKNOWN_1 7
+#define DVB_PLL_TUA6010XS 8
+#define DVB_PLL_ENV57H1XD5 9
+#define DVB_PLL_TUA6034 10
+#define DVB_PLL_LG_TDVS_H06XF 11
+#define DVB_PLL_TDA665X 12
+#define DVB_PLL_FMD1216ME 13
+#define DVB_PLL_TDED4 14
+#define DVB_PLL_TUV1236D 15
+#define DVB_PLL_TDHU2 16
+#define DVB_PLL_SAMSUNG_TBMV 17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316 19
+#define DVB_PLL_THOMSON_FE6600 20
+#define DVB_PLL_OPERA1 21
+#define DVB_PLL_FCV1236D 22
/**
* Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@
* @param fe Frontend to attach to.
* @param pll_addr i2c address of the PLL (if used).
* @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc);
+ unsigned int pll_desc_id);
#else
static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
return NULL;
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index b809f83..ddc8489 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -49,7 +49,6 @@
#include <linux/string.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "nxt200x.h"
struct nxt200x_state {
@@ -546,11 +545,6 @@
nxt200x_writebytes(state, 0x17, buf, 1);
}
- /* get tuning information */
- if (fe->ops.tuner_ops.calc_regs) {
- fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
- }
-
/* set additional params */
switch (p->u.vsb.modulation) {
case QAM_64:
@@ -559,27 +553,24 @@
/* This is just a guess since I am unable to test it */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 1);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 1);
break;
case VSB_8:
/* Set non-punctured clock for VSB */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 0);
break;
default:
return -EINVAL;
break;
}
- /* write frequency information */
- nxt200x_writetuner(state, buf);
+ if (fe->ops.tuner_ops.calc_regs) {
+ /* get tuning information */
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+ /* write frequency information */
+ nxt200x_writetuner(state, buf);
+ }
/* reset the agc now that tuning has been completed */
nxt200x_agc_reset(state);
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 28bc559..bb0ef58 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,9 +38,6 @@
/* the demodulator's i2c address */
u8 demod_address;
- /* used to set pll input */
- int (*set_pll_input)(u8* buf, int input);
-
/* need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 4e0aca7..3cc8b44 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -45,7 +45,6 @@
#include "dvb_math.h"
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "or51132.h"
static int debug;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 048d7cf..f46d5a4 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -223,38 +223,13 @@
struct dvb_frontend_parameters *param)
{
struct or51211_state* state = fe->demodulator_priv;
- u32 freq = 0;
- u16 tunerfreq = 0;
- u8 buf[4];
/* Change only if we are actually changing the channel */
if (state->current_frequency != param->frequency) {
- freq = 44000 + (param->frequency/1000);
- tunerfreq = freq * 16/1000;
-
- dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
- param->frequency,tunerfreq);
-
- buf[0] = (tunerfreq >> 8) & 0x7F;
- buf[1] = (tunerfreq & 0xFF);
- buf[2] = 0x8E;
-
- if (param->frequency < 157250000) {
- buf[3] = 0xA0;
- dprintk("set_parameters VHF low range\n");
- } else if (param->frequency < 454000000) {
- buf[3] = 0x90;
- dprintk("set_parameters VHF high range\n");
- } else {
- buf[3] = 0x30;
- dprintk("set_parameters UHF range\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 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,0xC2>>1,buf,4))
- printk(KERN_WARNING "or51211:set_parameters error "
- "writing to tuner\n");
/* Set to ATSC mode */
or51211_setmode(fe,0);
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 18768d2..6c60730 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -249,7 +249,7 @@
dprintk ("%s\n", __FUNCTION__);
stv0299_readregs (state, 0x1f, sfr, 3);
- stv0299_readregs (state, 0x1a, &rtf, 1);
+ stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
srate = (sfr[0] << 8) | sfr[1];
srate *= Mclk;
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index da796e7..4bb06f9 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -478,7 +478,7 @@
state->i2c = i2c;
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
- for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+ for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
if (tda10023_inittab[i] == 0x00) {
state->reg0 = tda10023_inittab[i+2];
break;
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
index ce6a9aa..7ac1287 100644
--- a/drivers/media/dvb/pluto2/Makefile
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7751628..6d53289 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -108,7 +108,7 @@
tristate "Budget cards with analog video inputs"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index aa85ecd..2c11452 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@
obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index ef1108c..2cee9e3 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -137,6 +137,15 @@
if (ret < 0)
printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+ 1, (u16) av7110->display_ar);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set aspect ratio\n");
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+ 1, av7110->display_panscan);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set pan scan\n");
+
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
if (ret < 0)
printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -2639,12 +2648,12 @@
av7110->mixer.volume_left = volume;
av7110->mixer.volume_right = volume;
- init_av7110_av(av7110);
-
ret = av7110_register(av7110);
if (ret < 0)
goto err_arm_thread_stop_10;
+ init_av7110_av(av7110);
+
/* special case DVB-C: these cards have an analog tuner
plus need some special handling, so we have separate
saa7146_ext_vv data for these... */
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 115002b..0cb4395 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -194,6 +194,7 @@
int video_blank;
struct video_status videostate;
+ u16 display_panscan;
int display_ar;
int trickmode;
#define TRICK_NONE 0
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 58678c0..d75e7e4 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -391,7 +391,7 @@
****************************************************************************/
static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
- const char *buf, unsigned long count)
+ const u8 *buf, unsigned long count)
{
unsigned long todo = count;
int free;
@@ -436,7 +436,7 @@
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -499,7 +499,7 @@
return count - todo;
}
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -959,7 +959,7 @@
#define MIN_IFRAME 400000
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
int i, n;
@@ -1082,19 +1082,18 @@
case VIDEO_SET_DISPLAY_FORMAT:
{
video_displayformat_t format = (video_displayformat_t) arg;
- u16 val = 0;
switch (format) {
case VIDEO_PAN_SCAN:
- val = VID_PAN_SCAN_PREF;
+ av7110->display_panscan = VID_PAN_SCAN_PREF;
break;
case VIDEO_LETTER_BOX:
- val = VID_VC_AND_PS_PREF;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
break;
case VIDEO_CENTER_CUT_OUT:
- val = VID_CENTRE_CUT_PREF;
+ av7110->display_panscan = VID_CENTRE_CUT_PREF;
break;
default:
@@ -1104,7 +1103,7 @@
break;
av7110->videostate.display_format = format;
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
- 1, (u16) val);
+ 1, av7110->display_panscan);
break;
}
@@ -1466,8 +1465,9 @@
av7110->videostate.play_state = VIDEO_STOPPED;
av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
av7110->videostate.video_format = VIDEO_FORMAT_4_3;
- av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+ av7110->videostate.display_format = VIDEO_LETTER_BOX;
av7110->display_ar = VIDEO_FORMAT_4_3;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
init_waitqueue_head(&av7110->video_events.wait_queue);
spin_lock_init(&av7110->video_events.lock);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e1c1294..c58e3fc 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -151,7 +151,7 @@
{
int free;
int non_blocking = file->f_flags & O_NONBLOCK;
- char *page = (char *)__get_free_page(GFP_USER);
+ u8 *page = (u8 *)__get_free_page(GFP_USER);
int res;
if (!page)
@@ -208,7 +208,7 @@
return -EINVAL;
DVB_RINGBUFFER_SKIP(cibuf, 2);
- return dvb_ringbuffer_read(cibuf, buf, len, 1);
+ return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
}
static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 70aee4e..515e823 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -158,7 +158,7 @@
}
dprintk(4, "writing DRAM block %d\n", i);
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
bootblock ^= 0x1400;
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@
}
if (rest > 4)
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
else
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@
return 0;
}
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
{
int i, ret;
unsigned long start;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 673d9b3..74d940f 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -393,7 +393,7 @@
}
/* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
{
memcpy(av7110->debi_virt, val, count);
av7110_debiwrite(av7110, config, addr, 0, count);
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index a97f166..6322800 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -356,7 +356,7 @@
input_dev->id.vendor = av7110->dev->pci->vendor;
input_dev->id.product = av7110->dev->pci->device;
}
- input_dev->cdev.dev = &av7110->dev->pci->dev;
+ input_dev->dev.parent = &av7110->dev->pci->dev;
/* initial keymap */
memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
input_register_keys(&av7110->ir);
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index fcd9994..87afaeb 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -333,7 +333,7 @@
return -EINVAL;
memset(t, 0, sizeof(*t));
- strcpy(t->name, "Television");
+ strcpy((char *)t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 0e817d6..0aee7a1 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -828,29 +828,6 @@
0xff, 0xff
};
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- int rc;
- struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
- struct budget *budget = (struct budget *) fe->dvb->priv;
-
- if((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
- params->frequency, 0);
- if(rc < 0) return rc;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
@@ -921,6 +898,7 @@
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS_EASYWATCH_1 0x001a
+#define SUBID_DVBS_EASYWATCH_2 0x001b
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_EASYWATCH 0x002a
@@ -982,10 +960,13 @@
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
case SUBID_DVBS_EASYWATCH:
+ case SUBID_DVBS_EASYWATCH_2:
fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
&budget_av->budget.i2c_adap);
if (fe) {
- fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ dvb_attach(dvb_pll_attach, fe, 0x60,
+ &budget_av->budget.i2c_adap,
+ DVB_PLL_PHILIPS_SD1878_TDA8261);
}
break;
@@ -1264,6 +1245,7 @@
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+ MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9d42f88..873c3ba 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -206,7 +206,7 @@
input_dev->id.vendor = saa->pci->vendor;
input_dev->id.product = saa->pci->device;
}
- input_dev->cdev.dev = &saa->pci->dev;
+ input_dev->dev.parent = &saa->pci->dev;
/* Select keymap and address */
switch (budget_ci->budget.dev->pci->subsystem_device) {
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
index 6ab97f6..fbe2b95 100644
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ b/drivers/media/dvb/ttusb-budget/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
index b41bf1f..2d70a82 100644
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ b/drivers/media/dvb/ttusb-dec/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 194b102..f8bf9fe 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -324,8 +324,8 @@
Enter the I/O port of your Zoltrix radio card.
config USB_DSBR
- tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+ tristate "D-Link/GemTek USB FM radio support"
+ depends on USB && VIDEO_V4L2
---help---
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5adc27c..ce940b1 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -392,7 +392,6 @@
.owner = THIS_MODULE,
.name = "RadioTrack radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9f1adda..9b1f7a9 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -355,7 +355,6 @@
.owner = THIS_MODULE,
.name = "Aztech radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &aztech_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 5e6f17d..4db05b2 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -377,7 +377,6 @@
.owner = THIS_MODULE,
.name = "Gemtek PCI Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &gemtek_pci_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index b04b6a7..eab8c80 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -330,7 +330,6 @@
.owner = THIS_MODULE,
.name = "GemTek radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &gemtek_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 9b493b3..82aedfc 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -297,7 +297,6 @@
.owner = THIS_MODULE,
.name = "RadioTrack II radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index dc33f19..3951653 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -297,7 +297,6 @@
.owner = THIS_MODULE,
.name = "SF16FMx radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmi_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index e6c125d..c432c44 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -442,7 +442,6 @@
.owner = THIS_MODULE,
.name = "SF16FMR2 radio",
. type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmr2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index e43acfd..7e1911c 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -369,7 +369,6 @@
.owner = THIS_MODULE,
.name = "TerraTec ActiveRadio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &terratec_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c27c629..c11981f 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -349,7 +349,6 @@
.owner = THIS_MODULE,
.name = "Trust FM Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &trust_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ff5a23..1366326 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -349,7 +349,6 @@
.owner = THIS_MODULE,
.name = "Typhoon Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &typhoon_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4d45a40..9dcbffd 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -489,6 +489,15 @@
Say Y here to include support for Philips SAB3036 compatible tuners.
If in doubt, say N.
+config TUNER_TEA5761
+ bool "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on I2C
+ select VIDEO_TUNER
+ help
+ Say Y here to include support for Philips TEA5761 radio tuner.
+ If in doubt, say N.
+
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9c2de50..10b4d44 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -7,6 +7,8 @@
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
mt20xx.o tda8290.o tea5767.o tda9887.o
+tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o
+
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
@@ -16,7 +18,7 @@
endif
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,7 +61,7 @@
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 823cd6c..cbab53f 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 05c7820..0d0c554 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 59a4360..12d1b92 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -38,23 +38,24 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 853b1a3..e1028a7 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6b31e50..2aea09c 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -178,8 +178,8 @@
/* this seems to happen as well ... */
{ 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
- { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" },
+ { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" },
{ 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" },
{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
+ { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
{ 0, -1, NULL }
};
@@ -329,7 +330,7 @@
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -344,7 +345,7 @@
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -359,7 +360,7 @@
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -387,13 +388,13 @@
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -408,7 +409,7 @@
.gpiomux = { 0, 1, 0, 1 },
.gpiomute = 3,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -423,7 +424,7 @@
.gpiomux = { 0x0c, 0x04, 0x08, 0x04 },
/* 0x04 for some cards ?? */
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = avermedia_tvphone_audio,
@@ -433,13 +434,13 @@
.name = "MATRIX-Vision MV-Delta",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -457,7 +458,7 @@
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -488,7 +489,7 @@
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -503,7 +504,7 @@
.gpiomux = { 0x20001,0x10001, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -519,7 +520,7 @@
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 13, 14, 11, 7 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -553,7 +554,7 @@
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -568,7 +569,7 @@
.gpiomux = { 0, 0, 1, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -587,7 +588,7 @@
.gpiomute = 0x002000,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
},
[BTTV_BOARD_WINVIEW_601] = {
.name = "Leadtek WinView 601",
@@ -600,7 +601,7 @@
.gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
.gpiomute = 0xcfa007,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winview_audio,
@@ -616,7 +617,7 @@
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 0, 0, 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -624,13 +625,13 @@
.name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x8dff00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -643,7 +644,7 @@
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -674,7 +675,7 @@
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -683,7 +684,7 @@
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, -1 },
.digital_mode = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -740,7 +741,7 @@
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -813,13 +814,13 @@
.name = "Imagenation PXC200",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1, /* was: 4 */
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = PXC200_muxsel,
@@ -836,7 +837,7 @@
.gpiomux = { 0, 0x0800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -860,13 +861,13 @@
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -911,7 +912,7 @@
.needs_tvaudio = 0,
.pll = PLL_28,
.has_radio = 1,
- .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winfast2000_audio,
@@ -928,7 +929,7 @@
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -945,7 +946,7 @@
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -962,7 +963,7 @@
.gpiomute = 0x29,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -978,7 +979,7 @@
.gpiomute = 0x551c00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -995,7 +996,7 @@
.gpiomute = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1030,7 +1031,7 @@
.gpiomux = { 13, 4, 11, 7 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1048,7 +1049,7 @@
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1063,7 +1064,7 @@
.gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
.gpiomute = 0xff3ffc,
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1074,14 +1075,14 @@
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 3,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 1, 0, 2 },
.gpiomute = 3,
.no_msp34xx = 1,
.pll = PLL_NONE,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1089,14 +1090,14 @@
.name = "MATRIX-Vision MV-Delta 2",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1112,7 +1113,7 @@
.gpiomute = 0xbcb03f,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 21,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1129,7 +1130,7 @@
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1148,7 +1149,7 @@
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1206,7 +1207,7 @@
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.pll = PLL_28,
- .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1234,7 +1235,7 @@
1= FM stereo Radio from Tuner */
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1277,7 +1278,7 @@
0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
0x0880: Tuner A2 stereo */
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1313,7 +1314,7 @@
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1324,7 +1325,7 @@
.name = "GrandTec 'Grand Video Capture' (Bt848)",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0,
.muxsel = { 3, 1 },
@@ -1332,7 +1333,7 @@
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1365,7 +1366,7 @@
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 1,
.pll = PLL_28,
- .tuner_type = 0,
+ .tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1377,7 +1378,7 @@
.video_inputs = 2,
.audio_inputs = 2,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 11,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@
.name = "AG Electronics GMV1",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0xF,
.muxsel = { 2, 2 },
@@ -1400,7 +1401,7 @@
.no_msp34xx = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1447,7 +1448,7 @@
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 1,
.muxsel = { 2, 3, 0, 1 },
.gpiomux = { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@
.no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1517,13 +1518,35 @@
/* ---- card 0x44 ---------------------------------- */
[BTTV_BOARD_VOODOOTV_FM] = {
- .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+ .name = "3Dfx VoodooTV FM (Euro)",
/* try "insmod msp3400 simple=0" if you have
* sound problems with this card. */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+ .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff },
+ .gpiomute = 0x947fff,
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+ .muxsel = { 2, 3 ,0 ,1 },
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_VOODOOTV_200] = {
+ .name = "VoodooTV 200 (USA)",
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = UNSET,
.gpiomask = 0x4f8a00,
/* 0x100000: 1=MSP enabled (0=disable again)
* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@
.name = "Active Imaging AIMMS",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -1564,7 +1587,7 @@
.gpiomute = 13,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 25,
+ .tuner_type = TUNER_LG_PAL_I_FM,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -1580,7 +1603,7 @@
.name = "Lifeview FlyVideo 98EZ (capture only) LR51",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
.pll = PLL_28,
@@ -1606,7 +1629,7 @@
.no_msp34xx = 1,
.no_tda9875 = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@
.name = "Sensoray 311",
.video_inputs = 5,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 4,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1641,15 +1664,15 @@
.name = "RemoteVision MX (RV605)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x00,
.gpiomask2 = 0x07ff,
.muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
.no_msp34xx = 1,
.no_tda9875 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = rv605_muxsel,
@@ -1693,15 +1716,15 @@
.name = "GrandTec Multi Capture Card (Bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1724,7 +1747,7 @@
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@
/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
.name = "DSP Design TCVIDEO",
.video_inputs = 4,
- .svhs = -1,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1762,7 +1785,7 @@
.muxsel = { 2, 0, 1, 1 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1791,11 +1814,11 @@
.name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
.video_inputs = 4, /* id-inputs-clock */
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.muxsel = { 3, 2, 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1806,11 +1829,11 @@
.name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1823,11 +1846,11 @@
.name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1838,11 +1861,11 @@
.name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1853,11 +1876,11 @@
.name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1868,8 +1891,8 @@
.name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
.tuner_type = UNSET,
@@ -1885,7 +1908,7 @@
.name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
@@ -1900,7 +1923,7 @@
.name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1915,11 +1938,11 @@
.name = "Osprey 500", /* 500 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1930,9 +1953,9 @@
.name = "Osprey 540", /* 540 */
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1945,7 +1968,7 @@
.name = "Osprey 2000", /* 2000 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1961,11 +1984,11 @@
.name = "IDS Eagle",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 0, 1, 2, 3 },
.muxsel_hook = eagle_muxsel,
@@ -1978,8 +2001,8 @@
.video_inputs = 2,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -2020,13 +2043,13 @@
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.gpiomux = { 0, 1, 2, 3},
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2035,7 +2058,7 @@
.name = "Euresys Picolo",
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
@@ -2052,8 +2075,8 @@
.name = "ProVideo PV150", /* 0x4f */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3 },
.gpiomux = { 0 },
@@ -2080,7 +2103,7 @@
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = adtvk503_audio,
@@ -2098,7 +2121,7 @@
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Notes:
@@ -2121,7 +2144,7 @@
.gpiomask = 0,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -2138,11 +2161,11 @@
.name = "IVC-200",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2 },
.pll = PLL_28,
@@ -2151,9 +2174,9 @@
.name = "Grand X-Guard / Trust 814PCI",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = 4,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask2 = 0xff,
@@ -2169,14 +2192,14 @@
[BTTV_BOARD_NEBULA_DIGITV] = {
.name = "Nebula Electronics DigiTV",
.video_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2189,15 +2212,15 @@
.name = "ProVideo PV143",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2206,14 +2229,14 @@
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2221,14 +2244,14 @@
.name = "PHYTEC VD-009-X1 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2238,7 +2261,7 @@
.name = "PHYTEC VD-009 MiniDIN (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2256,7 +2279,7 @@
.name = "PHYTEC VD-009 Combi (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2274,11 +2297,11 @@
.name = "IVC-100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
@@ -2288,11 +2311,11 @@
.name = "IVC-120G",
.video_inputs = 16,
.audio_inputs = 0, /* card has no audio */
- .tuner = -1, /* card has no tuner */
- .tuner_type = -1,
+ .tuner = UNSET, /* card has no tuner */
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1, /* card has no svhs */
+ .svhs = UNSET, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2333,7 +2356,7 @@
.video_inputs = 3,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.muxsel = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2364,9 +2387,9 @@
.name = "SIMUS GVC1100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2395,14 +2418,14 @@
.name = "LMLBT4",
.video_inputs = 4, /* IN1,IN2,IN3,IN4 */
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2452,8 +2475,8 @@
.name = "Euresys Picolo Tetra",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
.no_msp34xx = 1,
@@ -2464,7 +2487,7 @@
.pll = PLL_28,
.needs_tvaudio = 0,
.muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2490,7 +2513,7 @@
.name = "AVerMedia AVerTV DVB-T 771",
.video_inputs = 2,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2509,14 +2532,14 @@
/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
.name = "AverMedia AverTV DVB-T 761",
.video_inputs = 2,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2528,8 +2551,8 @@
.name = "MATRIX Vision Sigma-SQ",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2546,15 +2569,15 @@
.name = "MATRIX Vision Sigma-SLC",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2 },
.muxsel_hook = sigmaSLC_muxsel,
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2566,7 +2589,7 @@
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xFF,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@
[BTTV_BOARD_DVICO_DVBT_LITE] = {
/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
.name = "DViCO FusionHDTV DVB-T Lite",
- .tuner = -1,
+ .tuner = UNSET,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.no_video = 1,
.has_dvb = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2634,14 +2657,14 @@
.name = "Tibet Systems 'Progress DVR' CS16",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@
.name = "Kodicom 4400R (master)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
/* GPIO bits 0-9 used for analog switch:
* 00 - 03: camera selector
* 04 - 06: channel (controller) selector
@@ -2693,11 +2716,11 @@
.name = "Kodicom 4400R (slave)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0x010000,
.no_gpioirq = 1,
.muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2824,7 +2847,7 @@
.name = "Osprey 440",
.video_inputs = 1,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2 },
.pll = PLL_28,
@@ -2848,7 +2871,7 @@
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2875,14 +2898,14 @@
.name = "Hauppauge ImpactVCB (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0f, /* old: 7 */
.muxsel = { 0, 1, 3, 2 }, /* Composite 0-3 */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2914,10 +2937,10 @@
.name = "SSAI Security Video Interface",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0, 1, 2, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2925,13 +2948,31 @@
.name = "SSAI Ultrasound Video Interface",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 0, 1, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
+ /* ---- card 0x94---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+ .name = "DViCO FusionHDTV 2",
+ .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_ATSC, /* FCV1236D */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .gpiomask = 0x00e00007,
+ .gpiomux = { 0x00400005, 0, 0x00000001, 0 },
+ .gpiomute = 0x00c00007,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3040,7 +3081,7 @@
static void flyvideo_gpio(struct bttv *btv)
{
int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
- int tuner=-1,ttype;
+ int tuner=UNSET,ttype;
gpio_inout(0xffffff, 0);
udelay(8); /* without this we would see the 0x1800 mask */
@@ -3085,7 +3126,7 @@
* gpio & 0x001000 output bit for audio routing */
if(is_capture_only)
- tuner=4; /* No tuner present */
+ tuner = TUNER_ABSENT; /* No tuner present */
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3134,7 @@
btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
is_capture_only?"yes":"no ");
- if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+ if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
btv->tuner_type = tuner;
btv->has_radio = has_radio;
@@ -3302,6 +3343,7 @@
case BTTV_BOARD_HAUPPAUGE878:
boot_msp34xx(btv,5);
break;
+ case BTTV_BOARD_VOODOOTV_200:
case BTTV_BOARD_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
@@ -3328,10 +3370,9 @@
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
- int tda9887;
int addr=ADDR_UNSET;
- btv->tuner_type = -1;
+ btv->tuner_type = UNSET;
if (BTTV_BOARD_UNKNOWN == btv->c.type) {
bttv_readee(btv,eeprom_data,0xa0);
@@ -3479,7 +3520,15 @@
btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
if (UNSET != tuner[btv->c.nr])
btv->tuner_type = tuner[btv->c.nr];
- printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+ if (btv->tuner_type == TUNER_ABSENT ||
+ bttv_tvcards[btv->c.type].tuner == UNSET)
+ printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+ else if(btv->tuner_type == UNSET)
+ printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+ else
+ printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+ btv->tuner_type);
if (btv->tuner_type != UNSET) {
struct tuner_setup tun_setup;
@@ -3521,6 +3570,9 @@
if (!autoload)
return;
+ if (bttv_tvcards[btv->c.type].tuner == UNSET)
+ return; /* no tuner or related drivers to load */
+
/* try to detect audio/fader chips */
if (!bttv_tvcards[btv->c.type].no_msp34xx &&
bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3593,7 @@
if (bttv_tvcards[btv->c.type].needs_tvaudio)
request_module("tvaudio");
- /* tuner modules */
- tda9887 = 0;
- if (btv->tda9887_conf)
- tda9887 = 1;
- if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
- bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
- tda9887 = 1;
- /* Hybrid DVB card, DOES have a tda9887 */
- if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
- tda9887 = 1;
- if (btv->tuner_type != UNSET)
+ if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
request_module("tuner");
}
@@ -3865,11 +3907,15 @@
if(norm==VIDEO_MODE_NTSC) {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
dprintk("bttv_tda9880_setnorm to NTSC\n");
}
else {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
dprintk("bttv_tda9880_setnorm to PAL\n");
}
/* set GPIO according */
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index b1fedb0..cb555f2 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -1218,7 +1218,14 @@
break;
case TVAUDIO_INPUT_TUNER:
default:
- route.input = MSP_INPUT_DEFAULT;
+ /* This is the only card that uses TUNER2, and afaik,
+ is the only difference between the VOODOOTV_FM
+ and VOODOOTV_200 */
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+ MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+ else
+ route.input = MSP_INPUT_DEFAULT;
break;
}
route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@
v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
- if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
@@ -1323,6 +1330,7 @@
switch (btv->c.type) {
case BTTV_BOARD_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_200:
bttv_tda9880_setnorm(btv,norm);
break;
}
@@ -2251,6 +2259,24 @@
printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* bt848 has a 12-bit register space */
+ reg->reg &= 0xfff;
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = btread(reg->reg);
+ else
+ btwrite(reg->val, reg->reg);
+ return 0;
+ }
+#endif
default:
return -ENOIOCTLCMD;
@@ -3561,6 +3587,8 @@
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3943,6 +3971,8 @@
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 6f74c80..94a13d0 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -313,7 +313,7 @@
input_dev->id.vendor = btv->c.pci->vendor;
input_dev->id.product = btv->c.pci->device;
}
- input_dev->cdev.dev = &btv->c.pci->dev;
+ input_dev->dev.parent = &btv->c.pci->dev;
btv->remote = ir;
bttv_ir_start(btv, ir);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f821ba6..dcc847d 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -170,6 +170,8 @@
#define BTTV_BOARD_MACHTV_MAGICTV 0x90
#define BTTV_BOARD_SSAI_SECURITY 0x91
#define BTTV_BOARD_SSAI_ULTRASOUND 0x92
+#define BTTV_BOARD_VOODOOTV_200 0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 8f44f02..bd85f6d 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,12 +33,12 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
-#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <linux/device.h>
#include <media/video-buf.h>
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index fd771c7..55aab8d 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -663,15 +663,13 @@
cpia2_send_command(cam, &cmd);
}
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (cam->params.pnp_id.device_type == DEVICE_STV_672)
retval = apply_vp_patch(cam);
/* wait for vp to go to sleep */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
/***
* If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@
set_default_user_mode(cam);
/* Give VP time to wake up */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
set_all_properties(cam);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 1bda7ad..92778cd 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -105,7 +105,7 @@
{ CPIA2_VP_FRAMERATE_25, "25 fps" },
{ CPIA2_VP_FRAMERATE_30, "30 fps" },
};
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
static struct control_menu_info flicker_controls[] =
{
@@ -113,7 +113,7 @@
{ FLICKER_50, "50 Hz" },
{ FLICKER_60, "60 Hz" },
};
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
static struct control_menu_info lights_controls[] =
{
@@ -122,7 +122,7 @@
{ 128, "Bottom" },
{ 192, "Both" },
};
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
#define GPIO_LIGHTS_MASK 192
static struct v4l2_queryctrl controls[] = {
@@ -235,7 +235,7 @@
.default_value = 0,
},
};
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
/******************************************************************************
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0f9d969..f750a54 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -47,7 +47,7 @@
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
select VIDEO_BUF_DVB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_OR51132 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a80b1cb..f2fcdb9 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -56,8 +56,7 @@
/* ------------------------------------------------------------------ */
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
/* defines below are from ivtv-driver.h */
@@ -405,7 +404,7 @@
u32 value;
int i;
- for (i = 0; i < dev->fw_size; i++) {
+ for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
memory_read(dev->core, i, &value);
if (value == signature[signaturecnt])
signaturecnt++;
@@ -453,15 +452,12 @@
return -1;
}
- if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
- (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
- dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
- firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
- OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+ if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+ dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+ firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
- dev->fw_size = firmware->size;
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index e61102d..6a136dd 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1335,6 +1335,26 @@
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
},
+ [CX88_BOARD_ADSTECH_PTV_390] = {
+ .name = "ADS Tech Instant Video PCI",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3,
+ .gpio0 = 0x04ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x07fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x07fa,
+ }},
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1641,6 +1661,10 @@
.subvendor = 0x1421,
.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
.card = CX88_BOARD_KWORLD_DVBS_100,
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0390,
+ .card = CX88_BOARD_ADSTECH_PTV_390,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index dbfe4dc..1773b40 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,9 +35,7 @@
#include "mt352.h"
#include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
#include "zl10353.h"
#include "cx22702.h"
#include "or51132.h"
@@ -199,7 +197,7 @@
.demod_init = dvico_dual_demod_init,
};
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@
return 0;
}
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
-
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
- int err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = buf, .len = 4 };
- int err;
-
- /* Switch PLL to DVB mode */
- err = philips_fmd1216_pll_init(fe);
- if (err)
- return err;
-
- /* Tune PLL */
- dvb_pll_configure(dev->core->pll_desc, buf,
- params->frequency,
- params->u.ofdm.bandwidth);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
- printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, dev->core->pll_addr, buf[0], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -370,18 +310,8 @@
return 0;
}
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
.set_ts_params = nxt200x_set_ts_param,
};
@@ -456,7 +386,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt759x);
+ DVB_PLL_THOMSON_DTT759X);
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_lg_z201);
+ NULL, DVB_PLL_LG_Z201);
}
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -540,17 +470,16 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_unknown_1);
+ NULL, DVB_PLL_UNKNOWN_1);
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
if (dev->dvb.frontend != NULL) {
- dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
#else
printk("%s: built without vp3054 support\n", dev->core->name);
@@ -563,7 +492,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_fe6600);
+ DVB_PLL_THOMSON_FE6600);
}
break;
case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_microtune_4042);
+ DVB_PLL_MICROTUNE_4042);
}
}
break;
@@ -614,7 +543,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
}
break;
@@ -634,7 +563,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -654,7 +583,7 @@
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -664,7 +593,7 @@
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -705,10 +634,6 @@
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;
- }
/* Ensure all frontends negotiate bus access */
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
@@ -778,11 +703,10 @@
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+ /* If vp3054 isn't enabled, a stub will just return 0 */
err = vp3054_i2c_probe(dev);
if (0 != err)
goto fail_core;
-#endif
/* dvb stuff */
printk("%s/2: cx2388x based dvb card\n", core->name);
@@ -807,9 +731,7 @@
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
vp3054_i2c_remove(dev);
-#endif
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 7919a1f..78bbcfa 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -160,7 +160,7 @@
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.setsda = cx8800_bit_setsda,
.setscl = cx8800_bit_setscl,
.getsda = cx8800_bit_getsda,
@@ -171,18 +171,6 @@
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter cx8800_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
- .client_register = attach_inform,
- .client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
- .name = "cx88xx internal",
-};
-
static char *i2c_devs[128] = {
[ 0x1c >> 1 ] = "lgdt330x",
[ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,14 +200,9 @@
/* Prevents usage of invalid delay values */
if (i2c_udelay<5)
i2c_udelay=5;
- cx8800_i2c_algo_template.udelay=i2c_udelay;
- memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
- sizeof(core->i2c_adap));
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
- memcpy(&core->i2c_client, &cx8800_i2c_client_template,
- sizeof(core->i2c_client));
if (core->tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
@@ -228,10 +211,16 @@
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+ core->i2c_adap.owner = THIS_MODULE;
+ core->i2c_adap.id = I2C_HW_B_CX2388x;
+ core->i2c_adap.client_register = attach_inform;
+ core->i2c_adap.client_unregister = detach_inform;
+ core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap,core);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
+ strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 8136673..f5d4a56 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -74,7 +74,8 @@
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
- if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ switch (core->board) {
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
/* This board apparently uses a combination of 2 GPIO
to represent the keys. Additionally, the second GPIO
can be used for parity.
@@ -90,9 +91,14 @@
auxgpio = cx_read(MO_GP1_IO);
/* Take out the parity part */
gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
- } else
+ break;
+ case CX88_BOARD_WINFAST_DTV1000:
+ gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
auxgpio = gpio;
-
+ break;
+ default:
+ auxgpio = gpio;
+ }
if (ir->polling) {
if (ir->last_gpio == auxgpio)
return;
@@ -148,20 +154,16 @@
static void cx88_ir_work(struct work_struct *work)
{
struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
- unsigned long timeout;
cx88_ir_handle_key(ir);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
+ setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
INIT_WORK(&ir->work, cx88_ir_work);
- init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
@@ -222,7 +224,6 @@
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
@@ -236,6 +237,7 @@
ir->polling = 50; /* ms */
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
+ case CX88_BOARD_WINFAST_DTV1000:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
@@ -328,7 +330,7 @@
input_dev->id.vendor = pci->vendor;
input_dev->id.product = pci->device;
}
- input_dev->cdev.dev = &pci->dev;
+ input_dev->dev.parent = &pci->dev;
/* record handles to ourself */
ir->core = core;
core->ir = ir;
@@ -442,7 +444,6 @@
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 543b05e..317a2a3 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -336,7 +336,7 @@
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(0, "%s\n",__FUNCTION__);
+ dprintk(1, "%s\n",__FUNCTION__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 82bc3a2..cd08776 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -94,7 +94,7 @@
/* ----------------------------------------------------------------------- */
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
.setsda = vp3054_bit_setsda,
.setscl = vp3054_bit_setscl,
.getsda = vp3054_bit_getsda,
@@ -105,12 +105,6 @@
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter vp3054_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
-};
-
int vp3054_i2c_probe(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -125,8 +119,6 @@
return -ENOMEM;
vp3054_i2c = dev->card_priv;
- memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
- sizeof(vp3054_i2c->adap));
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
@@ -135,6 +127,8 @@
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
strlcpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
+ vp3054_i2c->adap.owner = THIS_MODULE;
+ vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
vp3054_i2c->algo.data = dev;
i2c_set_adapdata(&vp3054_i2c->adap, dev);
vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
index 637a7d2..be99c93 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -30,5 +30,12 @@
};
/* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
int vp3054_i2c_probe(struct cx8802_dev *dev);
void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 738d4f2..c4f656e 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -209,6 +209,7 @@
#define CX88_BOARD_NORWOOD_MICRO 54
#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
#define CX88_BOARD_HAUPPAUGE_HVR1300 56
+#define CX88_BOARD_ADSTECH_PTV_390 57
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -316,8 +317,6 @@
/* config info -- dvb */
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
- struct dvb_pll_desc *pll_desc;
- unsigned int pll_addr;
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
#endif
@@ -463,13 +462,10 @@
u32 mailbox;
int width;
int height;
- int fw_size;
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
- void* fe_handle;
- int (*fe_release)(void *handle);
void *card_priv;
#endif
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index 664676f..dcc1a03 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,6 +1,6 @@
config USB_ET61X251
tristate "USB ET61X[12]51 PC Camera Controller support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on Etoms ET61X151
or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 262f98e..02c741d 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "et61x251_sensor.h"
@@ -134,7 +135,7 @@
};
static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
struct et61x251_device {
struct video_device* v4ldev;
@@ -158,12 +159,14 @@
struct et61x251_sysfs_attr sysfs;
struct et61x251_module_param module_param;
+ struct kref kref;
enum et61x251_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -177,7 +180,7 @@
void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor)
+ const struct et61x251_sensor* sensor)
{
memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
}
@@ -195,8 +198,8 @@
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -205,8 +208,8 @@
if ((level) == 1 || (level) == 2) \
pr_info("et61x251: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -222,8 +225,8 @@
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a652551..585bd1f 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -45,11 +45,11 @@
#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \
"PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9)
/*****************************************************************************/
@@ -245,7 +245,8 @@
static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+ const struct et61x251_sensor* sensor)
{
int i, r;
@@ -270,7 +271,7 @@
int
et61x251_i2c_try_read(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address)
+ const struct et61x251_sensor* sensor, u8 address)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -303,7 +304,8 @@
int
et61x251_i2c_try_write(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address, u8 value)
+ const struct et61x251_sensor* sensor, u8 address,
+ u8 value)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -615,7 +617,7 @@
return 0;
free_urbs:
- for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
+ for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -682,7 +684,7 @@
if (len < 4) {
strncpy(str, buff, len);
- str[len+1] = '\0';
+ str[len] = '\0';
} else {
strncpy(str, buff, 4);
str[4] = '\0';
@@ -977,30 +979,30 @@
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
- struct video_device *v4ldev = cam->v4ldev;
+ struct class_device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
goto err_out;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ if ((err = class_device_create_file(classdev, &class_device_attr_val)))
goto err_reg;
if (cam->sensor.sysfs_ops) {
- if ((err = video_device_create_file(v4ldev,
+ if ((err = class_device_create_file(classdev,
&class_device_attr_i2c_reg)))
goto err_val;
- if ((err = video_device_create_file(v4ldev,
+ if ((err = class_device_create_file(classdev,
&class_device_attr_i2c_val)))
goto err_i2c_reg;
}
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+ class_device_remove_file(classdev, &class_device_attr_i2c_reg);
err_val:
- video_device_remove_file(v4ldev, &class_device_attr_val);
+ class_device_remove_file(classdev, &class_device_attr_val);
err_reg:
- video_device_remove_file(v4ldev, &class_device_attr_reg);
+ class_device_remove_file(classdev, &class_device_attr_reg);
err_out:
return err;
}
@@ -1103,7 +1105,8 @@
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1180,80 @@
return 0;
}
+/*****************************************************************************/
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
{
+ struct et61x251_device *cam;
+
mutex_lock(&et61x251_sysfs_lock);
+ cam = container_of(kref, struct et61x251_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&et61x251_sysfs_lock);
-
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int et61x251_open(struct inode* inode, struct file* filp)
{
struct et61x251_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&et61x251_disconnect))
+ if (!down_read_trylock(&et61x251_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&et61x251_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&et61x251_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&et61x251_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&et61x251_disconnect);
- return err;
- }
+ down_read(&et61x251_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&et61x251_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = et61x251_init(cam);
if (err) {
@@ -1259,36 +1278,32 @@
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&et61x251_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
return err;
}
static int et61x251_release(struct inode* inode, struct file* filp)
{
- struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+ struct et61x251_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&et61x251_dev_lock);
+
+ cam = video_get_drvdata(video_devdata(filp));
et61x251_stop_transfer(cam);
-
et61x251_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- et61x251_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, et61x251_release_resources);
+
+ up_write(&et61x251_dev_lock);
return 0;
}
@@ -1324,7 +1339,7 @@
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -1504,7 +1519,12 @@
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -1535,7 +1555,6 @@
vma->vm_ops = &et61x251_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
et61x251_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1783,7 @@
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
/* Preserve R,G or B origin */
@@ -1921,6 +1940,8 @@
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2017,8 @@
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
pix->priv = pfmt->priv; /* bpp */
+ pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pix->colorspace = pfmt->colorspace;
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2036,7 @@
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2129,14 +2152,14 @@
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2284,9 +2307,6 @@
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -2535,8 +2555,6 @@
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ET61X[12]51 PC Camera Controller detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -2568,7 +2586,7 @@
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -2578,7 +2596,7 @@
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2599,11 +2617,15 @@
"device controlling. Error #%d", err);
#else
DBG(2, "Optional device control through 'sysfs' interface disabled");
+ DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+ "configuration option to enable it.");
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2620,40 +2642,31 @@
static void et61x251_usb_disconnect(struct usb_interface* intf)
{
- struct et61x251_device* cam = usb_get_intfdata(intf);
+ struct et61x251_device* cam;
- if (!cam)
- return;
+ down_write(&et61x251_dev_lock);
- down_write(&et61x251_disconnect);
-
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
et61x251_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- et61x251_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, et61x251_release_resources);
- up_write(&et61x251_disconnect);
+ up_write(&et61x251_dev_lock);
}
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 5fadb5d..e145863 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -22,7 +22,7 @@
#define _ET61X251_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
@@ -47,7 +47,7 @@
extern void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor);
+ const struct et61x251_sensor* sensor);
/*****************************************************************************/
@@ -56,10 +56,10 @@
extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
extern int et61x251_i2c_try_write(struct et61x251_device*,
- struct et61x251_sensor*, u8 address,
+ const struct et61x251_sensor*, u8 address,
u8 value);
extern int et61x251_i2c_try_read(struct et61x251_device*,
- struct et61x251_sensor*, u8 address);
+ const struct et61x251_sensor*, u8 address);
extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
u8 data2, u8 data3, u8 data4, u8 data5,
u8 data6, u8 data7, u8 data8, u8 address);
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index b066434..04b7fbb 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -69,7 +69,7 @@
}
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
.name = "TAS5130D1B",
.interface = ET61X251_I2C_3WIRES,
.rsta = ET61X251_I2C_RSTA_STOP,
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index ed92b6f..2d709e0 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -37,6 +37,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/workqueue.h>
#include <asm/semaphore.h>
@@ -60,21 +61,22 @@
/* ----------------------------------------------------------------------- */
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int size, int offset)
{
- unsigned char buf[3];
+ unsigned char buf[6];
int start, range, toggle, dev, code;
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3))
+ if (size != i2c_master_recv(&ir->c,buf,size))
return -EIO;
/* split rc5 data block ... */
- start = (buf[0] >> 7) & 1;
- range = (buf[0] >> 6) & 1;
- toggle = (buf[0] >> 5) & 1;
- dev = buf[0] & 0x1f;
- code = (buf[1] >> 2) & 0x3f;
+ start = (buf[offset] >> 7) & 1;
+ range = (buf[offset] >> 6) & 1;
+ toggle = (buf[offset] >> 5) & 1;
+ dev = buf[offset] & 0x1f;
+ code = (buf[offset+1] >> 2) & 0x3f;
/* rc5 has two start bits
* the first bit must be one
@@ -96,6 +98,16 @@
return 1;
}
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -270,8 +282,9 @@
static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
ir_key_poll(ir);
- mod_timer(&ir->timer, jiffies+HZ/10);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
}
/* ----------------------------------------------------------------------- */
@@ -354,9 +367,21 @@
case 0x7a:
case 0x47:
case 0x71:
- /* Handled by saa7134-input */
- name = "SAA713x remote";
- ir_type = IR_TYPE_OTHER;
+ if (adap->id == I2C_HW_B_CX2388x) {
+ /* Handled by cx88-input */
+ name = "CX2388x remote";
+ ir_type = IR_TYPE_RC5;
+ ir->get_key = get_key_haup_xvr;
+ if (hauppauge == 1) {
+ ir_codes = ir_codes_hauppauge_new;
+ } else {
+ ir_codes = ir_codes_rc5_tv;
+ }
+ } else {
+ /* Handled by saa7134-input */
+ name = "SAA713x remote";
+ ir_type = IR_TYPE_OTHER;
+ }
break;
default:
/* shouldn't happen */
@@ -450,6 +475,7 @@
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+ static const int probe_cx88[] = { 0x18, 0x71, -1 };
const int *probe = NULL;
struct i2c_client c;
unsigned char buf;
@@ -468,6 +494,9 @@
case I2C_HW_B_EM28XX:
probe = probe_em28XX;
break;
+ case I2C_HW_B_CX2388x:
+ probe = probe_cx88;
+ break;
}
if (NULL == probe)
return 0;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index efc6635..4c93466 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -181,7 +181,7 @@
MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
MODULE_PARM_DESC(debug,
"Debug level (bitmask). Default: errors only\n"
- "\t\t\t(debug = 511 gives full debugging)");
+ "\t\t\t(debug = 1023 gives full debugging)");
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -339,6 +339,7 @@
/* In a few cases the PCI subsystem IDs do not correctly
identify the card. A better method is to check the
model number from the eeprom instead. */
+ case 30012 ... 30039: /* Low profile PVR250 */
case 32000 ... 32999:
case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */
case 48400 ... 48599:
@@ -622,6 +623,7 @@
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+ mutex_init(&itv->serialize_lock);
mutex_init(&itv->i2c_bus_lock);
mutex_init(&itv->udma.lock);
@@ -1288,10 +1290,7 @@
IVTV_DEBUG_INFO(" Releasing irq.\n");
free_irq(itv->dev->irq, (void *)itv);
-
- if (itv->dev) {
- ivtv_iounmap(itv);
- }
+ ivtv_iounmap(itv);
IVTV_DEBUG_INFO(" Releasing mem.\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
@@ -1326,9 +1325,9 @@
return -1;
}
- if (ivtv_debug < 0 || ivtv_debug > 511) {
+ if (ivtv_debug < 0 || ivtv_debug > 1023) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n");
+ printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 1023!\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index e6e56f1..6c1a85f 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -268,6 +268,8 @@
#define IVTV_DBGFLG_IRQ (1 << 6)
#define IVTV_DBGFLG_DEC (1 << 7)
#define IVTV_DBGFLG_YUV (1 << 8)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 9)
/* NOTE: extra space before comma in 'itv->num , ## args' is required for
gcc-2.95, otherwise it won't compile. */
@@ -286,6 +288,21 @@
#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+ } while (0)
+#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args)
+#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
#define IVTV_FB_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & ivtv_debug) \
@@ -650,7 +667,6 @@
/* convenience pointer to sliced struct in vbi_in union */
struct v4l2_sliced_vbi_format *sliced_in;
u32 service_set_in;
- u32 service_set_out;
int insert_mpeg;
/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
@@ -723,6 +739,7 @@
int search_pack_header;
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+ struct mutex serialize_lock; /* lock used to serialize starting streams */
/* User based DMA for OSD */
struct ivtv_user_dma udma;
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 555d5e6..ee7e884 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -406,7 +406,7 @@
ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
struct ivtv *itv = s->itv;
- IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+ IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
if (rc > 0)
pos += rc;
return rc;
@@ -497,7 +497,7 @@
struct ivtv_stream *s = &itv->streams[id->type];
int rc;
- IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+ IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name);
rc = ivtv_start_capture(id);
if (rc)
@@ -535,7 +535,7 @@
int rc;
DEFINE_WAIT(wait);
- IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+ IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name);
if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -643,7 +643,7 @@
to transfer the rest. */
if (count && !(filp->f_flags & O_NONBLOCK))
goto retry;
- IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
return bytes_written;
}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index d4c910b..2b6208a 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -56,9 +56,7 @@
volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
const u32 *src = (const u32 *)fw->data;
- /* temporarily allow 256 KB encoding firmwares as well for
- compatibility with blackbird cards */
- if (fw->size != size && fw->size != 256 * 1024) {
+ if (fw->size != size) {
/* Due to race conditions in firmware loading (esp. with udev <0.95)
the wrong file was sometimes loaded. So we check filesizes to
see if at least the right-sized file was loaded. If not, then we
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index bc8f8ca..676418c 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -115,8 +115,7 @@
curout = (curout & ~0xF) | 1;
write_reg(curout, IVTV_REG_GPIO_OUT);
/* We could use something else for smaller time */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
curout |= 2;
write_reg(curout, IVTV_REG_GPIO_OUT);
curdir &= ~0x80;
@@ -138,13 +137,11 @@
curout &= ~(1 << 12);
write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
curout |= (1 << 12);
write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 57af176..4773453 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1159,7 +1159,7 @@
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
fb->fmt.pixelformat = itv->osd_pixelformat;
@@ -1179,7 +1179,7 @@
struct v4l2_framebuffer *fb = arg;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index ba98bf0..1a3ee46 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -48,7 +48,7 @@
struct list_head *p;
int i = 0;
- IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+ IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
s->v4l2dev == NULL || !ivtv_use_pio(s)) {
itv->cur_pio_stream = -1;
@@ -56,7 +56,7 @@
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
return;
}
- IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
list_for_each(p, &s->q_dma.list) {
struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -187,7 +187,7 @@
bytes_needed += UVsize;
}
- IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+ IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -242,7 +242,7 @@
u32 *u32buf;
int x = 0;
- IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+ IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
@@ -321,7 +321,7 @@
unsigned long flags = 0;
int idx = 0;
- IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+ IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
list_for_each(p, &s->q_predma.list) {
struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -368,7 +368,7 @@
struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
int i;
- IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+ IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
@@ -397,7 +397,7 @@
itv->vbi.dma_offset = s_vbi->dma_offset;
s_vbi->SG_length = 0;
set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
- IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
}
/* Mark last buffer size for Interrupt flag */
@@ -431,7 +431,7 @@
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
- IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
/* put SG Handle into register 0x0c */
write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
@@ -447,7 +447,7 @@
struct ivtv_buffer *buf;
int hw_stream_type;
- IVTV_DEBUG_IRQ("DEC DMA READ\n");
+ IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
del_timer(&itv->dma_timer);
if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
@@ -462,7 +462,7 @@
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
hw_stream_type = 0;
}
- IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+ IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
ivtv_stream_sync_for_cpu(s);
@@ -495,7 +495,7 @@
del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
- IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
+ IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
data[1] = 3;
else if (data[1] > 2)
@@ -532,7 +532,7 @@
return;
}
s = &itv->streams[itv->cur_pio_stream];
- IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
+ IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
s->SG_length = 0;
clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
@@ -590,7 +590,7 @@
/* Get DMA destination and size arguments from card */
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
- IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+ IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
@@ -610,7 +610,7 @@
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+ IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
/* If more than two VBI buffers are pending, then
@@ -644,7 +644,7 @@
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
- IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+ IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
!stream_enc_dma_append(s, data)) {
set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +669,7 @@
itv->dma_data_req_offset = data[1];
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
}
- IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+ IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
itv->dma_data_req_offset, itv->dma_data_req_size);
if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -791,10 +791,10 @@
/* Exclude interrupts noted below from the output, otherwise the log is flooded with
these messages */
if (combo & ~0xff6d0400)
- IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+ IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
- IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+ IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
}
if (combo & IVTV_IRQ_DMA_READ) {
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 6af88ae..2871171 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -446,6 +446,9 @@
if (s->v4l2dev == NULL)
return -EINVAL;
+ /* Big serialization lock to ensure no two streams are started
+ simultaneously: that can give all sorts of weird results. */
+ mutex_lock(&itv->serialize_lock);
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
switch (s->type) {
@@ -487,6 +490,7 @@
0, sizeof(itv->vbi.sliced_mpeg_size));
break;
default:
+ mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
s->subtype = subtype;
@@ -568,6 +572,7 @@
if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
{
IVTV_DEBUG_WARN( "Error starting capture!\n");
+ mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
@@ -583,6 +588,7 @@
/* you're live! sit back and await interrupts :) */
atomic_inc(&itv->capturing);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
@@ -762,17 +768,6 @@
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
- /* only run these if we're shutting down the last cap */
- if (atomic_read(&itv->capturing) - 1 == 0) {
- /* event notification (off) */
- if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
- /* type: 0 = refresh */
- /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
- ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
- ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
- }
- }
-
then = jiffies;
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
@@ -812,7 +807,6 @@
then = jiffies;
/* Make sure DMA is complete */
add_wait_queue(&s->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
do {
/* check if DMA is pending */
if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
@@ -827,9 +821,7 @@
} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
break;
}
-
- ivtv_sleep_timeout(HZ / 100, 1);
- } while (then + HZ * 2 > jiffies);
+ } while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies);
set_current_state(TASK_RUNNING);
remove_wait_queue(&s->waitq, &wait);
@@ -840,17 +832,30 @@
/* Clear capture and no-read bits */
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ /* ensure these global cleanup actions are done only once */
+ mutex_lock(&itv->serialize_lock);
+
if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
if (atomic_read(&itv->capturing) > 0) {
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ /* event notification (off) */
+ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+ /* type: 0 = refresh */
+ /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+ ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+ ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+ }
+
wake_up(&s->waitq);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 3ba46e0..a7282a9 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -219,31 +219,23 @@
int found_cc = 0;
int cc_pos = itv->vbi.cc_pos;
- if (itv->vbi.service_set_out == 0)
- return -EPERM;
-
while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
switch (p->id) {
case V4L2_SLICED_CAPTION_525:
- if (p->id == V4L2_SLICED_CAPTION_525 &&
- p->line == 21 &&
- (itv->vbi.service_set_out &
- V4L2_SLICED_CAPTION_525) == 0) {
- break;
- }
- found_cc = 1;
- if (p->field) {
- cc[2] = p->data[0];
- cc[3] = p->data[1];
- } else {
- cc[0] = p->data[0];
- cc[1] = p->data[1];
+ if (p->line == 21) {
+ found_cc = 1;
+ if (p->field) {
+ cc[2] = p->data[0];
+ cc[3] = p->data[1];
+ } else {
+ cc[0] = p->data[0];
+ cc[1] = p->data[1];
+ }
}
break;
case V4L2_SLICED_VPS:
- if (p->line == 16 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
+ if (p->line == 16 && p->field == 0) {
itv->vbi.vps[0] = p->data[2];
itv->vbi.vps[1] = p->data[8];
itv->vbi.vps[2] = p->data[9];
@@ -255,8 +247,7 @@
break;
case V4L2_SLICED_WSS_625:
- if (p->line == 23 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
+ if (p->line == 23 && p->field == 0) {
/* No lock needed for WSS */
itv->vbi.wss = p->data[0] | (p->data[1] << 8);
itv->vbi.wss_found = 1;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 3bb7d66..507b1d4 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -157,8 +157,7 @@
break;
v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@
break;
v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index c7c9f3f8..7549114 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -7,7 +7,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
/* ---------------------------------------------------------------------- */
@@ -37,6 +37,19 @@
[ MT2050 ] = "MT2050",
};
+struct microtune_priv {
+ unsigned int xogc;
+ unsigned int radio_if2;
+};
+
+static void microtune_release(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
// IsSpurInBand()?
static int mt2032_spurcheck(struct i2c_client *c,
int f1, int f2, int spectrum_from,int spectrum_to)
@@ -218,6 +231,7 @@
unsigned char buf[21];
int lint_try,ret,sel,lock=0;
struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = t->priv;
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
@@ -227,7 +241,7 @@
i2c_master_recv(c,buf,21);
buf[0]=0;
- ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+ ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
if (ret<0)
return;
@@ -251,10 +265,10 @@
tuner_dbg("mt2032: re-init PLLs by LINT\n");
buf[0]=7;
- buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+ buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
i2c_master_send(c,buf,2);
mdelay(10);
- buf[1]=8+t->xogc;
+ buf[1]=8+priv->xogc;
i2c_master_send(c,buf,2);
}
@@ -294,17 +308,25 @@
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;
+ struct microtune_priv *priv = t->priv;
+ int if2 = priv->radio_if2;
// per Manual for FM tuning: first if center freq. 1085 MHz
mt2032_set_if_freq(c, freq * 1000 / 16,
1085*1000*1000,if2,if2,if2);
}
+static struct tuner_operations mt2032_tuner_ops = {
+ .set_tv_freq = mt2032_set_tv_freq,
+ .set_radio_freq = mt2032_set_radio_freq,
+ .release = microtune_release,
+};
+
// 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);
+ struct microtune_priv *priv = t->priv;
unsigned char buf[21];
int ret,xogc,xok=0;
@@ -351,23 +373,23 @@
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
} while (xok != 1 );
- t->xogc=xogc;
+ priv->xogc=xogc;
- t->set_tv_freq = mt2032_set_tv_freq;
- t->set_radio_freq = mt2032_set_radio_freq;
+ memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations));
+
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;
+ 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);
+ 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)
@@ -456,12 +478,19 @@
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;
+ struct microtune_priv *priv = t->priv;
+ int if2 = priv->radio_if2;
mt2050_set_if_freq(c, freq * 1000 / 16, if2);
mt2050_set_antenna(c, radio_antenna);
}
+static struct tuner_operations mt2050_tuner_ops = {
+ .set_tv_freq = mt2050_set_tv_freq,
+ .set_radio_freq = mt2050_set_radio_freq,
+ .release = microtune_release,
+};
+
static int mt2050_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -481,28 +510,35 @@
i2c_master_recv(c,buf,1);
tuner_dbg("mt2050: sro is %x\n",buf[0]);
- t->set_tv_freq = mt2050_set_tv_freq;
- t->set_radio_freq = mt2050_set_radio_freq;
+
+ memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations));
+
return 0;
}
int microtune_init(struct i2c_client *c)
{
+ struct microtune_priv *priv = NULL;
struct tuner *t = i2c_get_clientdata(c);
char *name;
unsigned char buf[21];
int company_code;
+ priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
+ priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+
memset(buf,0,sizeof(buf));
- t->set_tv_freq = NULL;
- t->set_radio_freq = NULL;
- t->standby = NULL;
+
if (t->std & V4L2_STD_525_60) {
tuner_dbg("pinnacle ntsc\n");
- t->radio_if2 = 41300 * 1000;
+ priv->radio_if2 = 41300 * 1000;
} else {
tuner_dbg("pinnacle pal\n");
- t->radio_if2 = 33300 * 1000;
+ priv->radio_if2 = 33300 * 1000;
}
name = "unknown";
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 3ceb8a6..f8f21dd 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -617,7 +617,7 @@
},
};
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
/*
@@ -1183,7 +1183,7 @@
.query = ov7670_q_hflip,
},
};
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
static struct ov7670_control *ov7670_find_control(__u32 id)
{
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 085332a..9c0e8d1 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1099,7 +1099,7 @@
return -EBUSY;
}
- down(&pdev->modlock);
+ mutex_lock(&pdev->modlock);
if (!pdev->usb_init) {
PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
@@ -1131,7 +1131,7 @@
if (i < 0) {
PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1172,7 +1172,7 @@
if (i) {
PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1181,7 +1181,7 @@
PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1191,7 +1191,7 @@
pdev->vopen++;
file->private_data = vdev;
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
@@ -1685,7 +1685,7 @@
pdev->angle_range.tilt_max = 2500;
}
- init_MUTEX(&pdev->modlock);
+ mutex_init(&pdev->modlock);
spin_lock_init(&pdev->ptrlock);
pdev->udev = udev;
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index acbb931..910a04f 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -31,7 +31,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/errno.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
@@ -244,7 +244,7 @@
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */
- struct semaphore modlock; /* to prevent races in video_open(), etc */
+ struct mutex modlock; /* to prevent races in video_open(), etc */
spinlock_t ptrlock; /* for manipulating the buffer pointers */
/*** motorized pan/tilt feature */
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index c1a392e..7ae2d64 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -37,23 +37,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 87c3144..677df51 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -35,28 +35,26 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
-
#include <linux/slab.h>
-
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 309dca3..9f1417a 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -40,7 +40,7 @@
depends on VIDEO_SAA7134 && DVB_CORE
select VIDEO_BUF_DVB
select FW_LOADER
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_NXT200X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ffb0f64..3c0fc90 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -75,7 +75,8 @@
struct saa7134_dev *dev;
unsigned long iobase;
- int irq;
+ s16 irq;
+ u16 mute_was_on;
spinlock_t lock;
} snd_card_saa7134_t;
@@ -589,8 +590,10 @@
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
struct saa7134_dev *dev = saa7134->dev;
- dev->ctl_mute = 1;
- saa7134_tvaudio_setmute(dev);
+ if (saa7134->mute_was_on) {
+ dev->ctl_mute = 1;
+ saa7134_tvaudio_setmute(dev);
+ }
return 0;
}
@@ -637,8 +640,11 @@
runtime->private_free = snd_card_saa7134_runtime_free;
runtime->hw = snd_card_saa7134_capture;
- dev->ctl_mute = 0;
- saa7134_tvaudio_setmute(dev);
+ if (dev->ctl_mute != 0) {
+ saa7134->mute_was_on = 1;
+ dev->ctl_mute = 0;
+ saa7134_tvaudio_setmute(dev);
+ }
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 50f15ad..8ec83bd 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -400,7 +400,7 @@
.inputs = {{
.name = name_tv,
.vmux = 1,
- .amux = LINE2,
+ .amux = TV,
.tv = 1,
.gpio = 0x20000,
},{
@@ -3502,6 +3502,38 @@
.amux = TV,
},
},
+ [SAA7134_BOARD_10MOONSTVMASTER3] = {
+ /* Tony Wan <aloha_cn@hotmail.com> */
+ .name = "10MOONS TM300 TV Card",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x7000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ }},
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x3000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4219,6 +4251,12 @@
.subdevice = 0x2003, /* OEM cardbus */
.driver_data = SAA7134_BOARD_SABRENT_TV_PCB05,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2304,
+ .driver_data = SAA7134_BOARD_10MOONSTVMASTER3,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4330,6 +4368,7 @@
case SAA7134_BOARD_AVERMEDIA_A16AR:
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ case SAA7134_BOARD_10MOONSTVMASTER3:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e0eec80..1f6bd33 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -175,18 +175,6 @@
return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
- if (buf_len < 5)
- return -EINVAL;
-
- pllbuf[0] = 0x61;
- dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 5;
-}
-
static struct mt352_config pinnacle_300i = {
.demod_address = 0x3c >> 1,
.adc_clock = 20333,
@@ -444,135 +432,6 @@
/* ------------------------------------------------------------------ */
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
-
- return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message actually turns the tuner back to analog mode */
- u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- fmd1216_init[2] = 0x86;
- fmd1216_init[3] = 0x54;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
- sizeof(tuner_buf) };
- int tuner_frequency = 0;
- int divider = 0;
- u8 band, mode, cp;
-
- /* determine charge pump */
- tuner_frequency = params->frequency + 36130000;
- if (tuner_frequency < 87000000)
- return -EINVAL;
- /* low band */
- else if (tuner_frequency < 180000000) {
- band = 1;
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 195000000) {
- band = 1;
- mode = 6;
- cp = 1;
- /* mid band */
- } else if (tuner_frequency < 366000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 478000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 6;
- cp = 1;
- /* high band */
- } else if (tuner_frequency < 662000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 840000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 6;
- cp = 1;
- } else {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 1;
-
- }
- /* calculate divisor */
- /* ((36166000 + Finput) / 166666) rounded! */
- divider = (tuner_frequency + 83333) / 166667;
-
- /* setup tuner buffer */
- tuner_buf[0] = (divider >> 8) & 0x7f;
- tuner_buf[1] = divider & 0xff;
- tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
- tuner_buf[3] = 0x40 | band;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
- wprintk("could not write to tuner at addr: 0x%02x\n",
- addr << 1);
- return -EIO;
- }
- return 0;
-}
-
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -958,18 +817,8 @@
.demod_address = 0x0a,
};
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
};
/* ==================================================================
@@ -1005,7 +854,8 @@
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, DVB_PLL_PHILIPS_TD1316);
}
break;
case SAA7134_BOARD_MD7134:
@@ -1013,9 +863,8 @@
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +962,7 @@
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tdhu2);
+ NULL, DVB_PLL_TDHU2);
}
break;
case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +970,7 @@
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +993,9 @@
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index f521603..fc260ec 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -96,6 +96,10 @@
if (dev->empress_users)
goto done_up;
+ /* Unmute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
dev->empress_users++;
file->private_data = dev;
err = 0;
@@ -121,6 +125,10 @@
/* stop the encoder */
ts_reset_encoder(dev);
+ /* Mute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
mutex_unlock(&dev->empress_tsq.lock);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index c0de37e..1b6dfd8 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -153,21 +153,18 @@
static void saa7134_input_timer(unsigned long data)
{
- struct saa7134_dev *dev = (struct saa7134_dev*)data;
+ struct saa7134_dev *dev = (struct saa7134_dev *)data;
struct card_ir *ir = dev->remote;
- unsigned long timeout;
build_key(dev);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = saa7134_input_timer;
- ir->timer.data = (unsigned long)dev;
+ setup_timer(&ir->timer, saa7134_input_timer,
+ (unsigned long)dev);
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
@@ -314,6 +311,7 @@
mask_keycode = 0x003F00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_FLYDVBTDUO:
ir_codes = ir_codes_flydvb;
@@ -333,6 +331,12 @@
mask_keyup = 0x040000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ ir_codes = ir_codes_encore_enltv;
+ mask_keycode = 0x5f80000;
+ mask_keyup = 0x8000000;
+ polling = 50; //ms
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +378,7 @@
input_dev->id.vendor = dev->pci->vendor;
input_dev->id.product = dev->pci->device;
}
- input_dev->cdev.dev = &dev->pci->dev;
+ input_dev->dev.parent = &dev->pci->dev;
dev->remote = ir;
saa7134_ir_start(dev, ir);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 30395d6..18b4817 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/div64.h>
@@ -341,10 +342,8 @@
static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&dev->thread.wq, &wait);
- if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+ if (dev->thread.scan1 == dev->thread.scan2 &&
+ !kthread_should_stop()) {
if (timeout < 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
@@ -353,7 +352,6 @@
(msecs_to_jiffies(timeout));
}
}
- remove_wait_queue(&dev->thread.wq, &wait);
return dev->thread.scan1 != dev->thread.scan2;
}
@@ -505,11 +503,10 @@
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -618,7 +615,7 @@
for (;;) {
if (tvaudio_sleep(dev,5000))
goto restart;
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
break;
if (UNSET == dev->thread.mode) {
rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +631,6 @@
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
@@ -782,7 +778,6 @@
struct saa7134_dev *dev = data;
u32 value, norms, clock;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +791,7 @@
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -876,7 +871,6 @@
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
@@ -973,7 +967,6 @@
int saa7134_tvaudio_init2(struct saa7134_dev *dev)
{
- DECLARE_MUTEX_LOCKED(sem);
int (*my_thread)(void *data) = NULL;
switch (dev->pci->device) {
@@ -986,15 +979,15 @@
break;
}
- dev->thread.pid = -1;
+ dev->thread.thread = NULL;
if (my_thread) {
/* start tvaudio thread */
- init_waitqueue_head(&dev->thread.wq);
- init_completion(&dev->thread.exit);
- dev->thread.pid = kernel_thread(my_thread,dev,0);
- if (dev->thread.pid < 0)
+ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+ if (IS_ERR(dev->thread.thread)) {
printk(KERN_WARNING "%s: kernel_thread() failed\n",
dev->name);
+ /* XXX: missing error handling here */
+ }
saa7134_tvaudio_do_scan(dev);
}
@@ -1005,11 +998,9 @@
int saa7134_tvaudio_fini(struct saa7134_dev *dev)
{
/* shutdown tvaudio thread */
- if (dev->thread.pid > 0) {
- dev->thread.shutdown = 1;
- wake_up_interruptible(&dev->thread.wq);
- wait_for_completion(&dev->thread.exit);
- }
+ if (dev->thread.thread)
+ kthread_stop(dev->thread.thread);
+
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
return 0;
}
@@ -1020,10 +1011,10 @@
dprintk("sound IF not in use, skipping scan\n");
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
- } else if (dev->thread.pid >= 0) {
+ } else if (dev->thread.thread) {
dev->thread.mode = UNSET;
dev->thread.scan2++;
- wake_up_interruptible(&dev->thread.wq);
+ wake_up_process(dev->thread.thread);
} else {
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1031,3 @@
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 15623b2..d32a856 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -238,6 +238,7 @@
#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
#define SAA7134_BOARD_KWORLD_DVBT_210 114
#define SAA7134_BOARD_SABRENT_TV_PCB05 115
+#define SAA7134_BOARD_10MOONSTVMASTER3 116
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -327,10 +328,7 @@
/* tvaudio thread status */
struct saa7134_thread {
- pid_t pid;
- struct completion exit;
- wait_queue_head_t wq;
- unsigned int shutdown;
+ struct task_struct *thread;
unsigned int scan1;
unsigned int scan2;
unsigned int mode;
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 339592e..66cc92c 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 11fcb49..2e3c3de 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/stddef.h>
+#include <linux/kref.h>
#include "sn9c102_config.h"
#include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@
};
static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
struct sn9c102_device {
struct video_device* v4ldev;
@@ -122,12 +123,14 @@
struct sn9c102_module_param module_param;
+ struct kref kref;
enum sn9c102_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 74a204f..36d8a455 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -48,8 +48,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47)
/*****************************************************************************/
@@ -64,9 +64,10 @@
static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
module_param_array(video_nr, short, NULL, 0444);
MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L2 minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
+ " <-1|n[,...]>"
+ "\nSpecify V4L2 minor mode number."
+ "\n-1 = use next available (default)"
+ "\n n = use minor number n (integer >= 0)"
"\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
" cameras this way."
"\nFor example:"
@@ -79,13 +80,14 @@
SN9C102_FORCE_MUNMAP};
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force the application to unmap previously"
+ " <0|1[,...]>"
+ "\nForce the application to unmap previously"
"\nmapped buffer memory before calling any VIDIOC_S_CROP or"
"\nVIDIOC_S_FMT ioctl's. Not all the applications support"
"\nthis feature. This parameter is specific for each"
"\ndetected camera."
- "\n 0 = do not force memory unmapping"
- "\n 1 = force memory unmapping (save memory)"
+ "\n0 = do not force memory unmapping"
+ "\n1 = force memory unmapping (save memory)"
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
"\n");
@@ -93,7 +95,8 @@
SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
- "\n<0|n[,...]> Timeout for a video frame in seconds before"
+ " <0|n[,...]>"
+ "\nTimeout for a video frame in seconds before"
"\nreturning an I/O error; 0 for infinity."
"\nThis parameter is specific for each detected camera."
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +106,8 @@
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
+ " <n>"
+ "\nDebugging information level, from 0 to 3:"
"\n0 = none (use carefully)"
"\n1 = critical errors"
"\n2 = significant informations"
@@ -1616,7 +1620,8 @@
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
} else { /* use current values */
@@ -1706,21 +1711,27 @@
return 0;
}
+/*****************************************************************************/
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
{
+ struct sn9c102_device *cam;
+
mutex_lock(&sn9c102_sysfs_lock);
+ cam = container_of(kref, struct sn9c102_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&sn9c102_sysfs_lock);
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int sn9c102_open(struct inode* inode, struct file* filp)
{
@@ -1728,43 +1739,78 @@
int err = 0;
/*
- This is the only safe way to prevent race conditions with
- disconnect
+ A read_trylock() in open() is the only safe way to prevent race
+ conditions with disconnect(), one close() and multiple (not
+ necessarily simultaneous) attempts to open(). For example, it
+ prevents from waiting for a second access, while the device
+ structure is being deallocated, after a possible disconnect() and
+ during a following close() holding the write lock: given that, after
+ this deallocation, no access will be possible anymore, using the
+ non-trylock version would have let open() gain the access to the
+ device structure improperly.
+ For this reason the lock must also not be per-device.
*/
- if (!down_read_trylock(&sn9c102_disconnect))
+ if (!down_read_trylock(&sn9c102_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&sn9c102_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&sn9c102_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ /*
+ Make sure to isolate all the simultaneous opens.
+ */
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, sn9c102_release_resources);
+ up_read(&sn9c102_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
DBG(3, "Simultaneous opens are not supported");
+ /*
+ open() must follow the open flags and should block
+ eventually while the device is in use.
+ */
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&sn9c102_dev_lock);
+ /*
+ We will not release the "open_mutex" lock, so that only one
+ process can be in the wait queue below. This way the process
+ will be sleeping while holding the lock, without loosing its
+ priority after any wake_up().
+ */
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&sn9c102_disconnect);
- return err;
- }
+ down_read(&sn9c102_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&sn9c102_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = sn9c102_init(cam);
if (err) {
@@ -1789,36 +1835,33 @@
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&sn9c102_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_read(&sn9c102_dev_lock);
return err;
}
static int sn9c102_release(struct inode* inode, struct file* filp)
{
- struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+ struct sn9c102_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&sn9c102_dev_lock);
+
+ cam = video_get_drvdata(video_devdata(filp));
sn9c102_stop_transfer(cam);
-
sn9c102_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- sn9c102_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_write(&sn9c102_dev_lock);
return 0;
}
@@ -2085,7 +2128,6 @@
vma->vm_ops = &sn9c102_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
sn9c102_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3257,6 @@
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
r = sn9c102_read_reg(cam, 0x00);
if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3322,7 @@
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -3292,7 +3332,7 @@
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -3318,8 +3358,10 @@
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -3336,40 +3378,31 @@
static void sn9c102_usb_disconnect(struct usb_interface* intf)
{
- struct sn9c102_device* cam = usb_get_intfdata(intf);
+ struct sn9c102_device* cam;
- if (!cam)
- return;
+ down_write(&sn9c102_dev_lock);
- down_write(&sn9c102_disconnect);
-
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
sn9c102_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- sn9c102_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, sn9c102_release_resources);
- up_write(&sn9c102_disconnect);
+ up_write(&sn9c102_dev_lock);
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index e683234..e4856fd 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -104,6 +104,145 @@
err += sn9c102_i2c_write(cam, 0x74, 0x21);
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+ {0x1a, 0x04}, {0x03, 0x10},
+ {0x0a, 0x14}, {0xe2, 0x17},
+ {0x0b, 0x18}, {0x00, 0x19},
+ {0x1d, 0x1a}, {0x10, 0x1b},
+ {0x02, 0x1c}, {0x03, 0x1d},
+ {0x0f, 0x1e}, {0x0c, 0x1f},
+ {0x00, 0x20}, {0x24, 0x21},
+ {0x3b, 0x22}, {0x47, 0x23},
+ {0x60, 0x24}, {0x71, 0x25},
+ {0x80, 0x26}, {0x8f, 0x27},
+ {0x9d, 0x28}, {0xaa, 0x29},
+ {0xb8, 0x2a}, {0xc4, 0x2b},
+ {0xd1, 0x2c}, {0xdd, 0x2d},
+ {0xe8, 0x2e}, {0xf4, 0x2f},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
+ {0x44, 0x42}, {0x00, 0x43},
+ {0x44, 0x44}, {0x00, 0x45},
+ {0x44, 0x46}, {0x00, 0x47},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
+ {0x44, 0x50}, {0x00, 0x51},
+ {0x44, 0x52}, {0x00, 0x53},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
+ {0x44, 0x66}, {0x00, 0x67},
+ {0x44, 0x68}, {0x00, 0x69},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
+ {0x44, 0x72}, {0x00, 0x73},
+ {0x44, 0x74}, {0x00, 0x75},
+ {0x44, 0x76}, {0x00, 0x77},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
+ {0x17, 0x84}, {0x00, 0x85},
+ {0x2e, 0x86}, {0x00, 0x87},
+ {0x09, 0x88}, {0x00, 0x89},
+ {0xe8, 0x8a}, {0x0f, 0x8b},
+ {0xda, 0x8c}, {0x0f, 0x8d},
+ {0x40, 0x8e}, {0x00, 0x8f},
+ {0x37, 0x90}, {0x00, 0x91},
+ {0xcf, 0x92}, {0x0f, 0x93},
+ {0xfa, 0x94}, {0x0f, 0x95},
+ {0x00, 0x96}, {0x00, 0x97},
+ {0x00, 0x98}, {0x66, 0x99},
+ {0x00, 0x9a}, {0x40, 0x9b},
+ {0x20, 0x9c}, {0x00, 0x9d},
+ {0x00, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x00, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3c, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x60, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x80);
+ err += sn9c102_i2c_write(cam, 0x12, 0x48);
+ err += sn9c102_i2c_write(cam, 0x01, 0x80);
+ err += sn9c102_i2c_write(cam, 0x02, 0x80);
+ err += sn9c102_i2c_write(cam, 0x03, 0x80);
+ err += sn9c102_i2c_write(cam, 0x04, 0x10);
+ err += sn9c102_i2c_write(cam, 0x05, 0x20);
+ err += sn9c102_i2c_write(cam, 0x06, 0x80);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+ err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+ err += sn9c102_i2c_write(cam, 0x15, 0x80);
+ err += sn9c102_i2c_write(cam, 0x16, 0x03);
+ err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+ err += sn9c102_i2c_write(cam, 0x19, 0x05);
+ err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x22, 0x00);
+ err += sn9c102_i2c_write(cam, 0x23, 0xde);
+ err += sn9c102_i2c_write(cam, 0x24, 0x10);
+ err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0xca);
+ err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+ err += sn9c102_i2c_write(cam, 0x29, 0x74);
+ err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+ err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+ err += sn9c102_i2c_write(cam, 0x30, 0x00);
+ err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+ err += sn9c102_i2c_write(cam, 0x33, 0x08);
+ err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+ err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x60, 0x05);
+ err += sn9c102_i2c_write(cam, 0x61, 0x40);
+ err += sn9c102_i2c_write(cam, 0x62, 0x12);
+ err += sn9c102_i2c_write(cam, 0x63, 0x57);
+ err += sn9c102_i2c_write(cam, 0x64, 0x73);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x66, 0x55);
+ err += sn9c102_i2c_write(cam, 0x67, 0x01);
+ err += sn9c102_i2c_write(cam, 0x68, 0xac);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+ err += sn9c102_i2c_write(cam, 0x70, 0x01);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x72, 0x10);
+ err += sn9c102_i2c_write(cam, 0x73, 0x50);
+ err += sn9c102_i2c_write(cam, 0x74, 0x20);
+ err += sn9c102_i2c_write(cam, 0x76, 0x01);
+ err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x78, 0x90);
+ err += sn9c102_i2c_write(cam, 0x79, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+ err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+ break;
default:
break;
}
@@ -115,6 +254,7 @@
static int ov7630_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -123,13 +263,20 @@
return -EIO;
break;
case V4L2_CID_RED_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
ctrl->value = sn9c102_pread_reg(cam, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ break;
break;
case V4L2_CID_GAIN:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@
static int ov7630_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -184,13 +332,19 @@
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
case V4L2_CID_RED_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_write_reg(cam, ctrl->value, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
break;
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@
{
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+ break;
+ default:
+ break;
+ }
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@
{
int err = 0;
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- else
- err += sn9c102_write_reg(cam, 0x50, 0x19);
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+ else
+ err += sn9c102_write_reg(cam, 0x20, 0x19);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+ err += sn9c102_write_reg(cam, 0xe5, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x04);
+ } else {
+ err += sn9c102_write_reg(cam, 0xe2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x02);
+ }
+ break;
+ default:
+ break;
+ }
return err;
}
@@ -254,7 +439,8 @@
static const struct sn9c102_sensor ov7630 = {
.name = "OV7630",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+ BRIDGE_SN9C105 | BRIDGE_SN9C120,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@
err += sn9c102_write_const_regs(cam, {0x01, 0x01},
{0x00, 0x01});
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+ {0x29, 0x01}, {0x74, 0x02},
+ {0x0e, 0x01}, {0x44, 0x01});
+ break;
default:
break;
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index 4b64740..8aae416 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -41,65 +41,65 @@
{0xbb, 0x2a}, {0xc7, 0x2b},
{0xd3, 0x2c}, {0xde, 0x2d},
{0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3F},
- {0xC7, 0x40}, {0x01, 0x41},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
{0x44, 0x42}, {0x00, 0x43},
{0x44, 0x44}, {0x00, 0x45},
{0x44, 0x46}, {0x00, 0x47},
- {0xC7, 0x48}, {0x01, 0x49},
- {0xC7, 0x4A}, {0x01, 0x4B},
- {0xC7, 0x4C}, {0x01, 0x4D},
- {0x44, 0x4E}, {0x00, 0x4F},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
{0x44, 0x50}, {0x00, 0x51},
{0x44, 0x52}, {0x00, 0x53},
- {0xC7, 0x54}, {0x01, 0x55},
- {0xC7, 0x56}, {0x01, 0x57},
- {0xC7, 0x58}, {0x01, 0x59},
- {0x44, 0x5A}, {0x00, 0x5B},
- {0x44, 0x5C}, {0x00, 0x5D},
- {0x44, 0x5E}, {0x00, 0x5F},
- {0xC7, 0x60}, {0x01, 0x61},
- {0xC7, 0x62}, {0x01, 0x63},
- {0xC7, 0x64}, {0x01, 0x65},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
{0x44, 0x66}, {0x00, 0x67},
{0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6A}, {0x00, 0x6B},
- {0xC7, 0x6C}, {0x01, 0x6D},
- {0xC7, 0x6E}, {0x01, 0x6F},
- {0xC7, 0x70}, {0x01, 0x71},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
{0x44, 0x72}, {0x00, 0x73},
{0x44, 0x74}, {0x00, 0x75},
{0x44, 0x76}, {0x00, 0x77},
- {0xC7, 0x78}, {0x01, 0x79},
- {0xC7, 0x7A}, {0x01, 0x7B},
- {0xC7, 0x7C}, {0x01, 0x7D},
- {0x44, 0x7E}, {0x00, 0x7F},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
{0x14, 0x84}, {0x00, 0x85},
{0x27, 0x86}, {0x00, 0x87},
{0x07, 0x88}, {0x00, 0x89},
- {0xEC, 0x8A}, {0x0f, 0x8B},
- {0xD8, 0x8C}, {0x0f, 0x8D},
- {0x3D, 0x8E}, {0x00, 0x8F},
- {0x3D, 0x90}, {0x00, 0x91},
- {0xCD, 0x92}, {0x0f, 0x93},
+ {0xec, 0x8a}, {0x0f, 0x8b},
+ {0xd8, 0x8c}, {0x0f, 0x8d},
+ {0x3d, 0x8e}, {0x00, 0x8f},
+ {0x3d, 0x90}, {0x00, 0x91},
+ {0xcd, 0x92}, {0x0f, 0x93},
{0xf7, 0x94}, {0x0f, 0x95},
- {0x0C, 0x96}, {0x00, 0x97},
+ {0x0c, 0x96}, {0x00, 0x97},
{0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9A}, {0x00, 0x9B},
- {0x04, 0x9C}, {0x00, 0x9D},
- {0x08, 0x9E}, {0x00, 0x9F},
- {0x2D, 0xC0}, {0x2D, 0xC1},
- {0x3A, 0xC2}, {0x05, 0xC3},
- {0x04, 0xC4}, {0x3F, 0xC5},
- {0x00, 0xC6}, {0x00, 0xC7},
- {0x50, 0xC8}, {0x3C, 0xC9},
- {0x28, 0xCA}, {0xD8, 0xCB},
- {0x14, 0xCC}, {0xEC, 0xCD},
- {0x32, 0xCE}, {0xDD, 0xCF},
- {0x32, 0xD0}, {0xDD, 0xD1},
- {0x6A, 0xD2}, {0x50, 0xD3},
- {0x00, 0xD4}, {0x00, 0xD5},
- {0x00, 0xD6});
+ {0x05, 0x9a}, {0x00, 0x9b},
+ {0x04, 0x9c}, {0x00, 0x9d},
+ {0x08, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x05, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3C, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x00, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
err += sn9c102_i2c_write(cam, 0x12, 0x80);
err += sn9c102_i2c_write(cam, 0x11, 0x09);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3e736be..eb22046 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1321,7 +1321,7 @@
u32 format;
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
- if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+ if (p.palette < ARRAY_SIZE(palette2fmt)) {
format = palette2fmt[p.palette];
saa->win.color_fmt = format;
saawrite(format | 0x60,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index bf3aa8d..4dc5bc7 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -715,8 +715,11 @@
stv680_video_irq, stv680);
stv680->urb[i] = urb;
err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
- if (err)
- PDEBUG (0, "STV(e): urb burned down in start stream");
+ if (err) {
+ PDEBUG (0, "STV(e): urb burned down with err "
+ "%d in start stream %d", err, i);
+ goto nomem_err;
+ }
} /* i STV680_NUMSBUF */
stv680->framecount = 0;
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 1a1bef0..59cff5a 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -21,7 +21,17 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+ unsigned char tda8290_easy_mode;
+ unsigned char tda827x_lpsel;
+ unsigned char tda827x_addr;
+ unsigned char tda827x_ver;
+ unsigned int sgIF;
+};
/* ---------------------------------------------------------------------- */
@@ -76,7 +86,8 @@
u32 N;
int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+ struct tda8290_priv *priv = t->priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
if (t->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
@@ -95,7 +106,7 @@
tuner_reg[1] = (unsigned char)(N>>8);
tuner_reg[2] = (unsigned char) N;
tuner_reg[3] = 0x40;
- tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+ tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) +
(tda827x_analog[i].bs <<3) + tda827x_analog[i].bp;
tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -146,8 +157,9 @@
static void tda827x_agcf(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char data[] = {0x80, 0x0c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
i2c_transfer(c->adapter, &msg, 1);
}
@@ -234,7 +246,8 @@
u32 N;
int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+ struct tda8290_priv *priv = t->priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
tda827xa_lna_gain( c, 1);
msleep(10);
@@ -271,7 +284,7 @@
tuner_reg[1] = 0xff;
tuner_reg[2] = 0xe0;
tuner_reg[3] = 0;
- tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+ tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
msg.len = 5;
i2c_transfer(c->adapter, &msg, 1);
@@ -311,15 +324,16 @@
i2c_transfer(c->adapter, &msg, 1);
tuner_reg[0] = 0xc0;
- tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
+ tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
i2c_transfer(c->adapter, &msg, 1);
}
static void tda827xa_agcf(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char data[] = {0x80, 0x2c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
i2c_transfer(c->adapter, &msg, 1);
}
@@ -347,8 +361,9 @@
static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char soft_reset[] = { 0x00, 0x00 };
- unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
+ unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode };
unsigned char expert_mode[] = { 0x01, 0x80 };
unsigned char agc_out_on[] = { 0x02, 0x00 };
unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -375,18 +390,18 @@
i2c_master_send(c, soft_reset, 2);
msleep(1);
- expert_mode[1] = t->tda8290_easy_mode + 0x80;
+ expert_mode[1] = priv->tda8290_easy_mode + 0x80;
i2c_master_send(c, expert_mode, 2);
i2c_master_send(c, gainset_off, 2);
i2c_master_send(c, if_agc_spd, 2);
- if (t->tda8290_easy_mode & 0x60)
+ if (priv->tda8290_easy_mode & 0x60)
i2c_master_send(c, adc_head_9, 2);
else
i2c_master_send(c, adc_head_6, 2);
i2c_master_send(c, pll_bw_nom, 2);
tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
tda827xa_tune(c, ifc, freq);
else
tda827x_tune(c, ifc, freq);
@@ -418,7 +433,7 @@
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
tda827xa_agcf(c);
else
tda827x_agcf(c);
@@ -437,7 +452,7 @@
}
/* l/ l' deadlock? */
- if(t->tda8290_easy_mode & 0x60) {
+ if(priv->tda8290_easy_mode & 0x60) {
i2c_master_send(c, &addr_adc_sat, 1);
i2c_master_recv(c, &adc_sat, 1);
i2c_master_send(c, &addr_pll_stat, 1);
@@ -459,41 +474,42 @@
static void set_audio(struct tuner *t)
{
+ struct tda8290_priv *priv = t->priv;
char* mode;
- t->tda827x_lpsel = 0;
+ priv->tda827x_lpsel = 0;
if (t->std & V4L2_STD_MN) {
- t->sgIF = 92;
- t->tda8290_easy_mode = 0x01;
- t->tda827x_lpsel = 1;
+ priv->sgIF = 92;
+ priv->tda8290_easy_mode = 0x01;
+ priv->tda827x_lpsel = 1;
mode = "MN";
} else if (t->std & V4L2_STD_B) {
- t->sgIF = 108;
- t->tda8290_easy_mode = 0x02;
+ priv->sgIF = 108;
+ priv->tda8290_easy_mode = 0x02;
mode = "B";
} else if (t->std & V4L2_STD_GH) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x04;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x04;
mode = "GH";
} else if (t->std & V4L2_STD_PAL_I) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x08;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x08;
mode = "I";
} else if (t->std & V4L2_STD_DK) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
mode = "DK";
} else if (t->std & V4L2_STD_SECAM_L) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x20;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x20;
mode = "L";
} else if (t->std & V4L2_STD_SECAM_LC) {
- t->sgIF = 20;
- t->tda8290_easy_mode = 0x40;
+ priv->sgIF = 20;
+ priv->tda8290_easy_mode = 0x40;
mode = "LC";
} else {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
mode = "xx";
}
tuner_dbg("setting tda8290 to system %s\n", mode);
@@ -502,9 +518,10 @@
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
set_audio(t);
- tda8290_tune(c, t->sgIF, freq);
+ tda8290_tune(c, priv->sgIF, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -528,13 +545,14 @@
static void standby(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char cb1[] = { 0x30, 0xD0 };
unsigned char tda8290_standby[] = { 0x00, 0x02 };
unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
cb1[1] = 0x90;
i2c_transfer(c->adapter, &msg, 1);
tda8290_i2c_bridge(c, 0);
@@ -560,13 +578,14 @@
static void tda8290_init_tuner(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
.buf=tda8275_init, .len = 14};
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
msg.buf = tda8275a_init;
tda8290_i2c_bridge(c, 1);
@@ -576,14 +595,36 @@
/*---------------------------------------------------------------------*/
+static void tda8290_release(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
+static struct tuner_operations tda8290_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = has_signal,
+ .standby = standby,
+ .release = tda8290_release,
+};
+
int tda8290_init(struct i2c_client *c)
{
+ struct tda8290_priv *priv = NULL;
struct tuner *t = i2c_get_clientdata(c);
u8 data;
int i, ret, tuners_found;
u32 tuner_addrs;
struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+ priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
tda8290_i2c_bridge(c, 1);
/* probe for tuner chip */
tuners_found = 0;
@@ -618,7 +659,7 @@
tuner_addrs = tuner_addrs & 0xff;
tuner_info ("setting tuner address to %x\n", tuner_addrs);
}
- t->tda827x_addr = tuner_addrs;
+ priv->tda827x_addr = tuner_addrs;
msg.addr = tuner_addrs;
tda8290_i2c_bridge(c, 1);
@@ -627,18 +668,16 @@
tuner_warn ("TDA827x access failed!\n");
if ((data & 0x3c) == 0) {
strlcpy(c->name, "tda8290+75", sizeof(c->name));
- t->tda827x_ver = 0;
+ priv->tda827x_ver = 0;
} else {
strlcpy(c->name, "tda8290+75a", sizeof(c->name));
- t->tda827x_ver = 2;
+ priv->tda827x_ver = 2;
}
tuner_info("type set to %s\n", c->name);
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = has_signal;
- t->standby = standby;
- t->tda827x_lpsel = 0;
+ memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations));
+
+ priv->tda827x_lpsel = 0;
t->mode = V4L2_TUNER_ANALOG_TV;
tda8290_init_tuner(c);
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index fde576f..a8f7732 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -11,6 +11,7 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
+#include "tuner-driver.h"
/* Chips:
@@ -29,6 +30,9 @@
printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+struct tda9887_priv {
+ unsigned char data[4];
+};
/* ---------------------------------------------------------------------- */
@@ -508,10 +512,11 @@
static void tda9887_configure(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
+ struct tda9887_priv *priv = t->priv;
int rc;
- memset(t->tda9887_data,0,sizeof(t->tda9887_data));
- tda9887_set_tvnorm(t,t->tda9887_data);
+ memset(priv->data,0,sizeof(priv->data));
+ tda9887_set_tvnorm(t,priv->data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
@@ -526,22 +531,22 @@
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->tda9887_data[1] |= cOutputPort1Inactive;
- t->tda9887_data[1] |= cOutputPort2Inactive;
+ priv->data[1] |= cOutputPort1Inactive;
+ priv->data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->tda9887_data);
- tda9887_set_insmod(t,t->tda9887_data);
+ tda9887_set_config(t,priv->data);
+ tda9887_set_insmod(t,priv->data);
if (t->mode == T_STANDBY) {
- t->tda9887_data[1] |= cForcedMuteAudioON;
+ priv->data[1] |= cForcedMuteAudioON;
}
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ priv->data[1],priv->data[2],priv->data[3]);
if (tuner_debug > 1)
- dump_write_message(t, t->tda9887_data);
+ dump_write_message(t, priv->data);
- if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+ if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (tuner_debug > 2) {
@@ -555,7 +560,8 @@
static void tda9887_tuner_status(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+ struct tda9887_priv *priv = t->priv;
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
}
static int tda9887_get_afc(struct i2c_client *client)
@@ -586,20 +592,39 @@
tda9887_configure(client);
}
-int tda9887_tuner_init(struct i2c_client *c)
+static void tda9887_release(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
+static struct tuner_operations tda9887_tuner_ops = {
+ .set_tv_freq = tda9887_set_freq,
+ .set_radio_freq = tda9887_set_freq,
+ .standby = tda9887_standby,
+ .tuner_status = tda9887_tuner_status,
+ .get_afc = tda9887_get_afc,
+ .release = tda9887_release,
+};
+
+int tda9887_tuner_init(struct i2c_client *c)
+{
+ struct tda9887_priv *priv = NULL;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
strlcpy(c->name, "tda9887", sizeof(c->name));
tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
t->i2c.driver->driver.name);
- t->set_tv_freq = tda9887_set_freq;
- t->set_radio_freq = tda9887_set_freq;
- t->standby = tda9887_standby;
- t->tuner_status = tda9887_tuner_status;
- t->get_afc = tda9887_get_afc;
+ memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
return 0;
}
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644
index 0000000..ae105c2
--- /dev/null
+++ b/drivers/media/video/tea5761.c
@@ -0,0 +1,243 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include "tuner-driver.h"
+
+#define PREFIX "TEA5761 "
+
+/* from tuner-core.c */
+extern int tuner_debug;
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+ /* first byte for reading */
+#define TEA5761_INTREG_IFFLAG 0x10
+#define TEA5761_INTREG_LEVFLAG 0x8
+#define TEA5761_INTREG_FRRFLAG 0x2
+#define TEA5761_INTREG_BLFLAG 0x1
+
+ /* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK 0x10
+#define TEA5761_INTREG_LEVMSK 0x8
+#define TEA5761_INTREG_FRMSK 0x2
+#define TEA5761_INTREG_BLMSK 0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+ /* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+ /* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM 0x04
+#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC 0x01
+
+ /* second byte */
+
+#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1 0x40
+#define TEA5761_TNCTRL_SSL_0 0x20
+#define TEA5761_TNCTRL_HLSI 0x10
+#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */
+#define TEA5761_TNCTRL_SWP 0x04
+#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI 0x01
+
+/* FRQCHECK - Read: bytes 6 and 7 */
+ /* First byte */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9 */
+
+ /* First byte */
+#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */
+#define TEA5761_TUNCHECK_TUNTO 0x01
+
+ /* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */
+#define TEA5761_TUNCHECK_LD 0x08
+#define TEA5761_TUNCHECK_STEREO 0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+ /* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+ /* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */
+
+ /* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+ /* First byte - should be 0x57 */
+
+ /* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+ unsigned int div, frq;
+
+ div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+ frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */
+
+ printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+ unsigned div;
+ int rc;
+
+ tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+
+ if (t->mode == T_STANDBY) {
+ tuner_dbg("TEA5761 set to standby mode\n");
+ buffer[5] |= TEA5761_TNCTRL_MU;
+ } else {
+ buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+ }
+
+
+ if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ tuner_dbg("TEA5761 set to mono\n");
+ buffer[5] |= TEA5761_TNCTRL_MST;
+;
+ } else {
+ tuner_dbg("TEA5761 set to stereo\n");
+ }
+
+ div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+ buffer[1] = (div >> 8) & 0x3f;
+ buffer[2] = div & 0xff;
+
+ if (tuner_debug)
+ tea5761_status_dump(buffer);
+
+ if (7 != (rc = i2c_master_send(c, buffer, 7)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+}
+
+static int tea5761_signal(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+}
+
+static int tea5761_stereo(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ rc = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+ tuner_dbg("TEA5761 radio ST GET = %02x\n", rc);
+
+ return (rc ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+int tea5761_autodetection(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (16 != (rc = i2c_master_recv(c, buffer, 16))) {
+ tuner_warn("it is not a TEA5761. Received %i chars.\n", rc);
+ return EINVAL;
+ }
+
+ if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+ tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+ return EINVAL;
+ }
+ tuner_warn("TEA5761 detected.\n");
+ return 0;
+}
+
+static struct tuner_operations tea5761_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = tea5761_signal,
+ .is_stereo = tea5761_stereo,
+};
+
+int tea5761_tuner_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (tea5761_autodetection(c) == EINVAL)
+ return EINVAL;
+
+ tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio");
+ strlcpy(c->name, "tea5761", sizeof(c->name));
+
+ memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations));
+
+ return (0);
+}
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index d1c4178..4985d47 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -13,7 +13,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
#define PREFIX "TEA5767 "
@@ -343,6 +343,14 @@
return 0;
}
+static struct tuner_operations tea5767_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = tea5767_signal,
+ .is_stereo = tea5767_stereo,
+ .standby = tea5767_standby,
+};
+
int tea5767_tuner_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -350,11 +358,7 @@
tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
strlcpy(c->name, "tea5767", sizeof(c->name));
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = tea5767_signal;
- t->is_stereo = tea5767_stereo;
- t->standby = tea5767_standby;
+ memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
return (0);
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 505591a..e646465 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -20,11 +20,15 @@
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include "tuner-driver.h"
#define UNSET (-1U)
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+ 0x10,
+#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -77,7 +81,7 @@
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_tv_freq) {
+ if (NULL == t->ops.set_tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
@@ -92,7 +96,7 @@
else
freq = tv_range[1] * 16;
}
- t->set_tv_freq(c, freq);
+ t->ops.set_tv_freq(c, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +107,7 @@
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_radio_freq) {
+ if (NULL == t->ops.set_radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
@@ -119,7 +123,7 @@
freq = radio_range[1] * 16000;
}
- t->set_radio_freq(c, freq);
+ t->ops.set_radio_freq(c, freq);
}
static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -174,6 +178,14 @@
return;
}
+ /* discard private data, in case set_type() was previously called */
+ if (t->ops.release)
+ t->ops.release(c);
+ else {
+ kfree(t->priv);
+ t->priv = NULL;
+ }
+
switch (t->type) {
case TUNER_MT2032:
microtune_init(c);
@@ -189,6 +201,16 @@
}
t->mode_mask = T_RADIO;
break;
+#ifdef CONFIG_TUNER_TEA5761
+ case TUNER_TEA5761:
+ if (tea5761_tuner_init(c) == EINVAL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
+ t->mode_mask = T_RADIO;
+ break;
+#endif
case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -408,11 +430,11 @@
tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
if (t->mode != V4L2_TUNER_RADIO)
return;
- if (t->has_signal) {
- tuner_info("Signal strength: %d\n", t->has_signal(client));
+ if (t->ops.has_signal) {
+ tuner_info("Signal strength: %d\n", t->ops.has_signal(client));
}
- if (t->is_stereo) {
- tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
+ if (t->ops.is_stereo) {
+ tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no");
}
}
@@ -437,10 +459,9 @@
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 */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
- t->tuner_status = tuner_status;
+ t->ops.tuner_status = tuner_status;
if (show_i2c) {
unsigned char buffer[16];
@@ -460,6 +481,19 @@
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+ case 0x10:
+ if (tea5761_autodetection(&t->i2c) != EINVAL) {
+ t->type = TUNER_TEA5761;
+ t->mode_mask = T_RADIO;
+ t->mode = T_STANDBY;
+ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+ default_mode_mask &= ~T_RADIO;
+
+ goto register_client;
+ }
+ break;
+#endif
case 0x42:
case 0x43:
case 0x4a:
@@ -533,6 +567,11 @@
return err;
}
+ if (t->ops.release)
+ t->ops.release(client);
+ else {
+ kfree(t->priv);
+ }
kfree(t);
return 0;
}
@@ -553,8 +592,8 @@
if (check_mode(t, cmd) == EINVAL) {
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby (client);
return EINVAL;
}
return 0;
@@ -602,8 +641,8 @@
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby (client);
break;
#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
@@ -662,10 +701,10 @@
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
- if (t->has_signal)
- vt->signal = t->has_signal(client);
- if (t->is_stereo) {
- if (t->is_stereo(client))
+ if (t->ops.has_signal)
+ vt->signal = t->ops.has_signal(client);
+ if (t->ops.is_stereo) {
+ if (t->ops.is_stereo(client))
vt->flags |=
VIDEO_TUNER_STEREO_ON;
else
@@ -693,8 +732,8 @@
if (check_v4l2(t) == EINVAL)
return 0;
- if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
- va->mode = t->is_stereo(client)
+ if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo)
+ va->mode = t->ops.is_stereo(client)
? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
return 0;
}
@@ -759,8 +798,8 @@
switch_v4l2();
tuner->type = t->mode;
- if (t->get_afc)
- tuner->afc=t->get_afc(client);
+ if (t->ops.get_afc)
+ tuner->afc=t->ops.get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,13 +809,13 @@
}
/* radio mode */
- if (t->has_signal)
- tuner->signal = t->has_signal(client);
+ if (t->ops.has_signal)
+ tuner->signal = t->ops.has_signal(client);
tuner->rxsubchans =
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (t->is_stereo) {
- tuner->rxsubchans = t->is_stereo(client) ?
+ if (t->ops.is_stereo) {
+ tuner->rxsubchans = t->ops.is_stereo(client) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
}
@@ -804,8 +843,8 @@
break;
}
case VIDIOC_LOG_STATUS:
- if (t->tuner_status)
- t->tuner_status(client);
+ if (t->ops.tuner_status)
+ t->ops.tuner_status(client);
break;
}
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644
index 0000000..0334a91
--- /dev/null
+++ b/drivers/media/video/tuner-driver.h
@@ -0,0 +1,107 @@
+/*
+ tuner-driver.h - interface for different tuners
+
+ Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+ minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ 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 __TUNER_HW_H__
+#define __TUNER_HW_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern unsigned const int tuner_count;
+
+struct tuner_operations {
+ void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
+ void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
+ int (*has_signal)(struct i2c_client *c);
+ int (*is_stereo)(struct i2c_client *c);
+ int (*get_afc)(struct i2c_client *c);
+ void (*tuner_status)(struct i2c_client *c);
+ void (*standby)(struct i2c_client *c);
+ void (*release)(struct i2c_client *c);
+};
+
+struct tuner {
+ /* device */
+ struct i2c_client i2c;
+
+ unsigned int type; /* chip type */
+
+ unsigned int mode;
+ unsigned int mode_mask; /* Combination of allowable modes */
+
+ unsigned int tv_freq; /* keep track of the current settings */
+ unsigned int radio_freq;
+ u16 last_div;
+ unsigned int audmode;
+ v4l2_std_id std;
+
+ int using_v4l2;
+ void *priv;
+
+ /* used by tda9887 */
+ unsigned int tda9887_config;
+
+ unsigned int config;
+ int (*tuner_callback) (void *dev, int command,int arg);
+
+ struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int default_tuner_init(struct i2c_client *c);
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+
+extern int microtune_init(struct i2c_client *c);
+
+extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
+
+extern int tea5761_tuner_init(struct i2c_client *c);
+extern int tea5761_autodetection(struct i2c_client *c);
+
+extern int tea5767_autodetection(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+ extern int tuner_debug; \
+ if (tuner_debug) \
+ printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_HW_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c40b92c..2d57e8b 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -8,6 +8,8 @@
#include <linux/videodev.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-driver.h"
static int offset = 0;
module_param(offset, int, 0664);
@@ -54,9 +56,9 @@
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'
+#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
/* Control byte */
@@ -207,11 +209,11 @@
/* 0x04 -> ??? PAL others / SECAM others ??? */
cb &= ~0x03;
if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
- cb |= PHILIPS_MF_SET_PAL_L;
+ cb |= PHILIPS_MF_SET_STD_L;
else if (t->std & V4L2_STD_SECAM_LC)
- cb |= PHILIPS_MF_SET_PAL_L2;
+ cb |= PHILIPS_MF_SET_STD_LC;
else /* V4L2_STD_B|V4L2_STD_GH */
- cb |= PHILIPS_MF_SET_BG;
+ cb |= PHILIPS_MF_SET_STD_BG;
break;
case TUNER_TEMIC_4046FM5:
@@ -479,6 +481,13 @@
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
}
+static struct tuner_operations simple_tuner_ops = {
+ .set_tv_freq = default_set_tv_freq,
+ .set_radio_freq = default_set_radio_freq,
+ .has_signal = tuner_signal,
+ .is_stereo = tuner_stereo,
+};
+
int default_tuner_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -487,11 +496,7 @@
t->type, tuners[t->type].name);
strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
- t->set_tv_freq = default_set_tv_freq;
- t->set_radio_freq = default_set_radio_freq;
- t->has_signal = tuner_signal;
- t->is_stereo = tuner_stereo;
- t->standby = NULL;
+ memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations));
return 0;
}
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 74c3e6f..417f642b 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -594,19 +594,19 @@
},
};
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
{ 16 * 999.99 , 0x8e, 0x30, },
};
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_atsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_atsc_ranges),
+ .ranges = tuner_philips_fcv1236d_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
},
};
@@ -1296,9 +1296,9 @@
.count = ARRAY_SIZE(tuner_philips_pal_mk_params),
},
[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
- .name = "Philips 1236D ATSC/NTSC dual in",
- .params = tuner_philips_atsc_params,
- .count = ARRAY_SIZE(tuner_philips_atsc_params),
+ .name = "Philips FCV1236D ATSC/NTSC dual in",
+ .params = tuner_philips_fcv1236d_params,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_params),
},
[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
.name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1463,10 @@
.name = "Philips TDA988[5,6,7] IF PLL Demodulator",
/* see tda9887.c for details */
},
+ [TUNER_TEA5761] = { /* Philips RADIO */
+ .name = "Philips TEA5761 FM Radio",
+ /* see tea5767.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index a1136da..fdc3def 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -183,7 +183,7 @@
{ TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
{ TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
- { TUNER_ABSENT, "Philips FQ1216LME MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +490,7 @@
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+2] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +523,7 @@
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+1] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +678,7 @@
tveeprom_info("audio processor is unknown (no idx)\n");
tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
} else {
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tveeprom_info("audio processor is %s (idx %d)\n",
audioIC[audioic].name,audioic);
else
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index d5ec05f..e2f1c97 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1006,7 +1006,7 @@
{
struct v4l2_control *ctrl = arg;
u8 i, n;
- n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ n = ARRAY_SIZE(tvp5150_qctrl);
for (i = 0; i < n; i++)
if (ctrl->id == tvp5150_qctrl[i].id) {
if (ctrl->value <
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index abe2146..491505d 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -236,7 +236,7 @@
input_dev->name = "Konicawc snapshot button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index ec0ff22..dd1a6d6 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -100,7 +100,7 @@
input_dev->name = "QCM button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@
int ret;
int i;
- for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
CHECK_RET(ret, qcm_stv_setb(uvd->dev,
regval_table[i].reg,
regval_table[i].val));
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 982b115..2d9c0dd 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -42,7 +42,6 @@
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include "usbvideo.h"
@@ -417,11 +416,6 @@
u8 open_count;
u8 bulkEndpoint;
int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
- struct proc_dir_entry *proc_dir;
-#endif
-
};
static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@
return 0;
}
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
- int count, int *eof, int value)
-{
- char *out = page;
- int len;
-
- out += sprintf(out, "%d",value);
-
- len = out - page;
- len -= off;
- if (len < count) {
- *eof = 1;
- if (len <= 0)
- return 0;
- } else
- len = count;
-
- *start = page + off;
- return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 stmp;
- char kbuf[8];
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 6)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- stmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (stmp < 4 || stmp > 32000)
- return -EINVAL;
-
- cam->shutter_speed = stmp;
-
- return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 gtmp;
- char kbuf[8];
-
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 4)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (gtmp > 255)
- return -EINVAL;
- cam->gain = gtmp;
-
- return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
- vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
- if (vicam_proc_root)
- vicam_proc_root->owner = THIS_MODULE;
- else
- printk(KERN_ERR
- "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
- if (vicam_proc_root)
- remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
- char name[64];
- struct proc_dir_entry *ent;
-
- DBG(KERN_INFO "vicam: creating proc entry\n");
-
- if (!vicam_proc_root || !cam) {
- printk(KERN_INFO
- "vicam: could not create proc entry, %s pointer is null.\n",
- (!cam ? "camera" : "root"));
- return;
- }
-
- sprintf(name, "video%d", cam->vdev.minor);
-
- cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
- if ( !cam->proc_dir )
- return; // FIXME: We should probably return an error here
-
- ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_shutter;
- ent->write_proc = vicam_write_proc_shutter;
- ent->size = 64;
- }
-
- ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_gain;
- ent->write_proc = vicam_write_proc_gain;
- ent->size = 64;
- }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
- struct vicam_camera *cam = (struct vicam_camera *) ptr;
- char name[16];
-
- if ( !cam->proc_dir )
- return;
-
- sprintf(name, "video%d", cam->vdev.minor);
- remove_proc_entry("shutter", cam->proc_dir);
- remove_proc_entry("gain", cam->proc_dir);
- remove_proc_entry(name,vicam_proc_root);
- cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
static const struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
@@ -1330,8 +1155,6 @@
return -EIO;
}
- vicam_create_proc_entry(cam);
-
printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
usb_set_intfdata (intf, cam);
@@ -1363,8 +1186,6 @@
cam->udev = NULL;
- vicam_destroy_proc_entry(cam);
-
/* the only thing left to do is synchronize with
* our close/release function on who should release
* the camera memory. if there are any users using the
@@ -1390,7 +1211,6 @@
{
int retval;
DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
- vicam_create_proc_root();
retval = usb_register(&vicam_driver);
if (retval)
printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1224,6 @@
"ViCam-based WebCam driver shutdown\n");
usb_deregister(&vicam_driver);
- vicam_destroy_proc_root();
}
module_init(usb_vicam_init);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 51ab265..380564c 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -79,7 +79,7 @@
.Interface = -1,
.Codec = CODEC_SAA7113,
.VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
+ .VideoNorm = V4L2_STD_NTSC,
.AudioChannels = 1,
.Radio = 0,
.vbi = 1,
@@ -311,8 +311,8 @@
.vbi = 1,
.Tuner = 1,
.TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = -1,
- .Y_Offset = -1,
+ .X_Offset = 0x80,
+ .Y_Offset = 0x16,
.ModelString = "Hauppauge WinTV USB (PAL/SECAM L)",
},
[HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@
.Radio = 0,
.vbi = 1,
.Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
+ .TunerType = TUNER_LG_PAL_NEW_TAPC,
.X_Offset = 0,
.Y_Offset = 3,
.Dvi_yuv_override = 1,
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 7df071eb..5b1e346 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -1742,7 +1742,7 @@
format = ISOC_MODE_YUV420;
}
value[0] = 0x0A; //TODO: See the effect of the filter
- value[1] = format;
+ value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1831,10 @@
frameRate = FRAMERATE_MAX;
}
- if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+ if (usbvision->tvnormId & V4L2_STD_625_50) {
frameDrop = frameRate * 32 / 25 - 1;
}
- else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+ else if (usbvision->tvnormId & V4L2_STD_525_60) {
frameDrop = frameRate * 32 / 30 - 1;
}
@@ -2067,7 +2067,7 @@
}
- if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+ if (usbvision->tvnormId & V4L2_STD_PAL) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2076,7 +2076,7 @@
value[5] = 0x00; //0x0060 -> 96 Input video h offset
value[6] = 0x16;
value[7] = 0x00; //0x0016 -> 22 Input video v offset
- } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+ } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2537,7 +2537,9 @@
int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
{
- int mode[4];
+ /* inputs #0 and #3 are constant for every SAA711x. */
+ /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+ int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
int audio[]= {1, 0, 0, 0};
struct v4l2_routing route;
//channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2549,6 @@
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
- route.input = SAA7115_COMPOSITE1;
- route.output = 0;
- call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
// set the new channel
// Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2556,27 @@
switch (usbvision_device_data[usbvision->DevModel].Codec) {
case CODEC_SAA7113:
- if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module.
- mode[2] = 1;
+ mode[1] = SAA7115_COMPOSITE2;
+ if (SwitchSVideoInput) {
+ /* To handle problems with S-Video Input for
+ * some devices. Use SwitchSVideoInput
+ * parameter when loading the module.*/
+ mode[2] = SAA7115_COMPOSITE1;
}
else {
- mode[2] = 7;
- }
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices
- }
- else {
- mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+ mode[2] = SAA7115_SVIDEO1;
}
break;
case CODEC_SAA7111:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
- break;
default:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+ /* modes for saa7111 */
+ mode[1] = SAA7115_COMPOSITE1;
+ mode[2] = SAA7115_SVIDEO1;
+ break;
}
route.input = mode[channel];
+ route.output = 0;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- usbvision->channel = channel;
usbvision_set_audio(usbvision, audio[channel]);
return 0;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index aa3258b..868b688 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -36,7 +36,8 @@
* - use submit_urb for all setup packets
* - Fix memory settings for nt1004. It is 4 times as big as the
* nt1003 memory.
- * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one?
+ * - Add audio on endpoint 3 for nt1004 chip.
+ * Seems impossible, needs a codec interface. Which one?
* - Clean up the driver.
* - optimization for performance.
* - Add Videotext capability (VBI). Working on it.....
@@ -77,7 +78,8 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -85,20 +87,25 @@
#define USBVISION_DRIVER_VERSION_MAJOR 0
#define USBVISION_DRIVER_VERSION_MINOR 9
#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
#ifdef USBVISION_DEBUG
#define PDEBUG(level, fmt, args...) \
- if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+ if (video_debug & (level)) \
+ info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+ ## args)
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
-#define DBG_IOCTL 1<<0
#define DBG_IO 1<<1
#define DBG_PROBE 1<<2
#define DBG_MMAP 1<<3
@@ -108,7 +115,8 @@
#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
-static int usbvision_nr = 0; // sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
@@ -121,55 +129,32 @@
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
};
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
- {
- .name = "PAL",
- .id = V4L2_STD_PAL,
- }, {
- .name = "NTSC",
- .id = V4L2_STD_NTSC,
- }, {
- .name = "SECAM",
- .id = V4L2_STD_SECAM,
- }, {
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
static void usbvision_release(struct usb_usbvision *usbvision);
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint
-static int video_debug = 0; // Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1; // Set the default device to power on at startup
-static int video_nr = -1; // Sequential Number of Video Device
-static int radio_nr = -1; // Sequential Number of Radio Device
-static int vbi_nr = -1; // Sequential Number of VBI Device
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
-// Grab parameters for the device driver
+/* Grab parameters for the device driver */
-#if defined(module_param) // Showing parameters under SYSFS
+/* Showing parameters under SYSFS */
module_param(isocMode, int, 0444);
module_param(video_debug, int, 0444);
module_param(PowerOnAtOpen, int, 0444);
module_param(video_nr, int, 0444);
module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
-#else // Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
@@ -187,19 +172,21 @@
MODULE_ALIAS(DRIVER_ALIAS);
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module. */
-/* Device information is located at /sys/class/video4linux/video0 */
-/* Device parameters information is located at /sys/module/usbvision */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module. */
+/* Device information is located at /sys/class/video4linux/video0 */
+/* Device parameters information is located at /sys/module/usbvision */
+/* Device USB Information is located at */
+/* /sys/bus/usb/drivers/USBVision Video Grabber */
+/*****************************************************************************/
#define YES_NO(x) ((x) ? "Yes" : "No")
static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
return video_get_drvdata(vdev);
}
@@ -211,15 +198,18 @@
static ssize_t show_model(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+ return sprintf(buf, "%s\n",
+ usbvision_device_data[usbvision->DevModel].ModelString);
}
static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
static ssize_t show_hue(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
@@ -232,7 +222,8 @@
static ssize_t show_contrast(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
@@ -245,7 +236,8 @@
static ssize_t show_brightness(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -258,7 +250,8 @@
static ssize_t show_saturation(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
@@ -271,23 +264,28 @@
static ssize_t show_streaming(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->streaming==Stream_On?1:0));
}
static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
static ssize_t show_compression(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
}
static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
static ssize_t show_device_bridge(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%d\n", usbvision->bridgeType);
}
@@ -376,7 +374,8 @@
static int usbvision_v4l2_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "open");
@@ -390,7 +389,8 @@
/* Allocate memory for the scratch ring buffer */
errCode = usbvision_scratch_alloc(usbvision);
if (isocMode==ISOC_MODE_COMPRESS) {
- /* Allocate intermediate decompression buffers only if needed */
+ /* Allocate intermediate decompression buffers
+ only if needed */
errCode = usbvision_decompress_alloc(usbvision);
}
if (errCode) {
@@ -421,11 +421,10 @@
if (!errCode) {
usbvision_begin_streaming(usbvision);
errCode = usbvision_init_isoc(usbvision);
- /* device needs to be initialized before isoc transfer */
+ /* device must be initialized before isoc transfer */
usbvision_muxsel(usbvision,0);
usbvision->user++;
- }
- else {
+ } else {
if (PowerOnAtOpen) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
@@ -456,7 +455,8 @@
static int usbvision_v4l2_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_IO, "close");
down(&usbvision->lock);
@@ -473,7 +473,8 @@
usbvision->user--;
if (PowerOnAtOpen) {
- /* power off in a little while to avoid off/on every close/open short sequences */
+ /* power off in a little while
+ to avoid off/on every close/open short sequences */
usbvision_set_powerOffTimer(usbvision);
usbvision->initialized = 0;
}
@@ -498,583 +499,612 @@
* This is part of Video 4 Linux API. The procedure handles ioctl() calls.
*
*/
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EFAULT;
-
- switch (cmd) {
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the NT100x registers */
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- int errCode;
-
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- /* NT100x has a 8-bit register space */
- if (cmd == VIDIOC_DBG_G_REGISTER)
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- else
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
- if (errCode < 0) {
- err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
- return errCode;
- }
- if (cmd == VIDIOC_DBG_S_REGISTER)
- reg->val = (u8)errCode;
-
- PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
- (unsigned int)reg->reg, (unsigned int)reg->val);
- return 0;
- }
-#endif
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *vi = arg;
- int chan;
-
- if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
- return -EINVAL;
- if (usbvision->have_tuner) {
- chan = vi->index;
- }
- else {
- chan = vi->index + 1; //skip Television string
- }
- switch(chan) {
- case 0:
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "White Video Input");
- }
- else {
- strcpy(vi->name, "Television");
- vi->type = V4L2_INPUT_TYPE_TUNER;
- vi->audioset = 1;
- vi->tuner = chan;
- vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
- }
- break;
- case 1:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Green Video Input");
- }
- else {
- strcpy(vi->name, "Composite Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 2:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Yellow Video Input");
- }
- else {
- strcpy(vi->name, "S-Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 3:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(vi->name, "Red Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
- vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
- return 0;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
- int ret;
-
- i = e->index;
- if (i >= TVNORMS)
- return -EINVAL;
- ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (ret < 0)
- return ret;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- int *input = arg;
- *input = usbvision->ctl_input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
- if ((*input >= usbvision->video_inputs) || (*input < 0) )
- return -EINVAL;
- usbvision->ctl_input = *input;
-
- down(&usbvision->lock);
- usbvision_muxsel(usbvision, usbvision->ctl_input);
- usbvision_set_input(usbvision);
- usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
- up(&usbvision->lock);
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
-
- *id = usbvision->tvnorm->id;
-
- PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
-
- for (i = 0; i < TVNORMS; i++)
- if (*id == tvnorms[i].id)
- break;
- if (i == TVNORMS)
- for (i = 0; i < TVNORMS; i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == TVNORMS)
- return -EINVAL;
-
- down(&usbvision->lock);
- usbvision->tvnorm = &tvnorms[i];
-
- call_i2c_clients(usbvision, VIDIOC_S_STD,
- &usbvision->tvnorm->id);
-
- up(&usbvision->lock);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- if (!usbvision->have_tuner || vt->index) // Only tuner 0
- return -EINVAL;
- strcpy(vt->name, "Television");
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- freq->tuner = 0; // Only one tuner
- freq->type = V4L2_TUNER_ANALOG_TV;
- freq->frequency = usbvision->freq;
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || freq->tuner)
- return -EINVAL;
-
- usbvision->freq = freq->frequency;
- call_i2c_clients(usbvision, cmd, freq);
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *v = arg;
- memset(v,0, sizeof(v));
- strcpy(v->name, "TV");
- PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- {
- struct v4l2_audio *v = arg;
- if(v->index) {
- return -EINVAL;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
-
- call_i2c_clients(usbvision, cmd, arg);
-
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
-
- PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- return 0;
- }
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *vr = arg;
- int ret;
-
- RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
-
- // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
- if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vr->memory != V4L2_MEMORY_MMAP))
- return -EINVAL;
-
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
-
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision,vr->count);
-
- usbvision->curFrame = NULL;
-
- PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
- return 0;
- }
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
-
- // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
-
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
- // Updating the corresponding frame state
- vb->flags = 0;
- frame = &usbvision->frame[vb->index];
- if(frame->grabstate >= FrameState_Ready)
- vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if(frame->grabstate >= FrameState_Done)
- vb->flags |= V4L2_BUF_FLAG_DONE;
- if(frame->grabstate == FrameState_Unused)
- vb->flags |= V4L2_BUF_FLAG_MAPPED;
- vb->memory = V4L2_MEMORY_MMAP;
-
- vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
- vb->timestamp = usbvision->frame[vb->index].timestamp;
- vb->sequence = usbvision->frame[vb->index].sequence;
- return 0;
- }
- case VIDIOC_QBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
- unsigned long lock_flags;
-
- // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
-
- frame = &usbvision->frame[vb->index];
-
- if (frame->grabstate != FrameState_Unused) {
- return -EAGAIN;
- }
-
- /* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
-
- vb->flags &= ~V4L2_BUF_FLAG_DONE;
-
- /* set v4l2_format index */
- frame->v4l2_format = usbvision->palette;
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
- return 0;
- }
- case VIDIOC_DQBUF:
- {
- struct v4l2_buffer *vb = arg;
- int ret;
- struct usbvision_frame *f;
- unsigned long lock_flags;
-
- if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == Stream_Idle)
- return -EINVAL;
- ret = wait_event_interruptible
- (usbvision->wait_frame,
- !list_empty(&(usbvision->outqueue)));
- if (ret)
- return ret;
- }
-
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- f = list_entry(usbvision->outqueue.next,
- struct usbvision_frame, frame);
- list_del(usbvision->outqueue.next);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- f->grabstate = FrameState_Unused;
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
- vb->index = f->index;
- vb->sequence = f->sequence;
- vb->timestamp = f->timestamp;
- vb->field = V4L2_FIELD_NONE;
- vb->bytesused = f->scanlength;
-
- return 0;
- }
- case VIDIOC_STREAMON:
- {
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- usbvision->streaming = Stream_On;
-
- call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
-
- return 0;
- }
- case VIDIOC_STREAMOFF:
- {
- int *type = arg;
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if(usbvision->streaming == Stream_On) {
- usbvision_stream_interrupt(usbvision);
- // Stop all video streamings
- call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
- }
- usbvision_empty_framequeues(usbvision);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
- return 0;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *vfd = arg;
-
- if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
- return -EINVAL;
- }
- vfd->flags = 0;
- vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
- vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- memset(vfd->reserved, 0, sizeof(vfd->reserved));
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *vf = arg;
-
- switch (vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- vf->fmt.pix.width = usbvision->curwidth;
- vf->fmt.pix.height = usbvision->curheight;
- vf->fmt.pix.pixelformat = usbvision->palette.format;
- vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
- vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *vf = arg;
- int formatIdx,ret;
-
- switch(vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- /* Find requested format in available ones */
- for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
- if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
- usbvision->palette = usbvision_v4l2_format[formatIdx];
- break;
- }
- }
- /* robustness */
- if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
- return -EINVAL;
- }
- RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
- RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
- vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
- if(cmd == VIDIOC_TRY_FMT) {
- PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
-
- /* stop io in case it is already in progress */
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
-
- usbvision->curFrame = NULL;
-
- // by now we are committed to the new data...
- down(&usbvision->lock);
- usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
- up(&usbvision->lock);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- return -EINVAL;
- }
- }
- default:
- return -ENOIOCTLCMD;
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (errCode < 0) {
+ err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
}
return 0;
}
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
{
- return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ reg->val = (u8)usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ if (reg->val < 0) {
+ err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
+ }
+ return 0;
+}
+#endif
+
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *vc)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card,
+ usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+ strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+ sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ return 0;
}
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *vi)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int chan;
+
+ if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+ return -EINVAL;
+ if (usbvision->have_tuner) {
+ chan = vi->index;
+ } else {
+ chan = vi->index + 1; /*skip Television string*/
+ }
+ /* Determine the requested input characteristics
+ specific for each usbvision card model */
+ switch(chan) {
+ case 0:
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "White Video Input");
+ } else {
+ strcpy(vi->name, "Television");
+ vi->type = V4L2_INPUT_TYPE_TUNER;
+ vi->audioset = 1;
+ vi->tuner = chan;
+ vi->std = USBVISION_NORMS;
+ }
+ break;
+ case 1:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Green Video Input");
+ } else {
+ strcpy(vi->name, "Composite Video Input");
+ }
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 2:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Yellow Video Input");
+ } else {
+ strcpy(vi->name, "S-Video Input");
+ }
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 3:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(vi->name, "Red Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ }
+ return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ *input = usbvision->ctl_input;
+ return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ if ((input >= usbvision->video_inputs) || (input < 0) )
+ return -EINVAL;
+
+ down(&usbvision->lock);
+ usbvision_muxsel(usbvision, input);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision,
+ usbvision->curwidth,
+ usbvision->curheight);
+ up(&usbvision->lock);
+ return 0;
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ usbvision->tvnormId=*id;
+
+ down(&usbvision->lock);
+ call_i2c_clients(usbvision, VIDIOC_S_STD,
+ &usbvision->tvnormId);
+ up(&usbvision->lock);
+ /* propagate the change to the decoder */
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
+
+ return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ return -EINVAL;
+ if(usbvision->radio) {
+ strcpy(vt->name, "Radio");
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strcpy(vt->name, "Television");
+ }
+ /* Let clients fill in the remainder of this struct */
+ call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+
+ return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+ return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ freq->tuner = 0; // Only one tuner
+ if(usbvision->radio) {
+ freq->type = V4L2_TUNER_RADIO;
+ } else {
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ }
+ freq->frequency = usbvision->freq;
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || freq->tuner)
+ return -EINVAL;
+
+ usbvision->freq = freq->frequency;
+ call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
+
+ return 0;
+}
+
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ memset(a,0,sizeof(*a));
+ if(usbvision->radio) {
+ strcpy(a->name,"Radio");
+ } else {
+ strcpy(a->name, "TV");
+ }
+
+ return 0;
+}
+
+static int vidioc_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ if(a->index) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int id=ctrl->id;
+
+ memset(ctrl,0,sizeof(*ctrl));
+ ctrl->id=id;
+
+ call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
+
+ if (!ctrl->type)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+ void *priv, struct v4l2_requestbuffers *vr)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+ /* Check input validity:
+ the user must do a VIDEO CAPTURE and MMAP method. */
+ if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (vr->memory != V4L2_MEMORY_MMAP))
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+ usbvision->curFrame = NULL;
+
+ return 0;
+}
+
+static int vidioc_querybuf (struct file *file,
+ void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+
+ /* FIXME : must control
+ that buffers are mapped (VIDIOC_REQBUFS has been called) */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+ /* Updating the corresponding frame state */
+ vb->flags = 0;
+ frame = &usbvision->frame[vb->index];
+ if(frame->grabstate >= FrameState_Ready)
+ vb->flags |= V4L2_BUF_FLAG_QUEUED;
+ if(frame->grabstate >= FrameState_Done)
+ vb->flags |= V4L2_BUF_FLAG_DONE;
+ if(frame->grabstate == FrameState_Unused)
+ vb->flags |= V4L2_BUF_FLAG_MAPPED;
+ vb->memory = V4L2_MEMORY_MMAP;
+
+ vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->field = V4L2_FIELD_NONE;
+ vb->length = usbvision->curwidth*
+ usbvision->curheight*
+ usbvision->palette.bytes_per_pixel;
+ vb->timestamp = usbvision->frame[vb->index].timestamp;
+ vb->sequence = usbvision->frame[vb->index].sequence;
+ return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+ unsigned long lock_flags;
+
+ /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+
+ frame = &usbvision->frame[vb->index];
+
+ if (frame->grabstate != FrameState_Unused) {
+ return -EAGAIN;
+ }
+
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = FrameState_Ready;
+ frame->scanstate = ScanState_Scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ return 0;
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+ if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == Stream_Idle)
+ return -EINVAL;
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ f = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ f->grabstate = FrameState_Unused;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->flags = V4L2_BUF_FLAG_MAPPED |
+ V4L2_BUF_FLAG_QUEUED |
+ V4L2_BUF_FLAG_DONE;
+ vb->index = f->index;
+ vb->sequence = f->sequence;
+ vb->timestamp = f->timestamp;
+ vb->field = V4L2_FIELD_NONE;
+ vb->bytesused = f->scanlength;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+ return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+ void *priv, enum v4l2_buf_type type)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ usbvision_stream_interrupt(usbvision);
+ /* Stop all video streamings */
+ call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *vfd)
+{
+ if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ return -EINVAL;
+ }
+ vfd->flags = 0;
+ vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+ memset(vfd->reserved, 0, sizeof(vfd->reserved));
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ vf->fmt.pix.width = usbvision->curwidth;
+ vf->fmt.pix.height = usbvision->curheight;
+ vf->fmt.pix.pixelformat = usbvision->palette.format;
+ vf->fmt.pix.bytesperline =
+ usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+ vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int formatIdx;
+
+ /* Find requested format in available ones */
+ for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+ if(vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[formatIdx].format) {
+ usbvision->palette = usbvision_v4l2_format[formatIdx];
+ break;
+ }
+ }
+ /* robustness */
+ if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ return -EINVAL;
+ }
+ RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+ RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+ vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+ usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+ return ret;
+ }
+
+ /* stop io in case it is already in progress */
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->curFrame = NULL;
+
+ /* by now we are committed to the new data... */
+ down(&usbvision->lock);
+ usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+ up(&usbvision->lock);
+
+ return 0;
+}
static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int noblock = file->f_flags & O_NONBLOCK;
unsigned long lock_flags;
int ret,i;
struct usbvision_frame *frame;
- PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+ (unsigned long)count, noblock);
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
return -EFAULT;
- /* This entry point is compatible with the mmap routines so that a user can do either
- VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+ /* This entry point is compatible with the mmap routines
+ so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+ to get frames or call read on the device. */
if(!usbvision->num_frames) {
- /* First, allocate some frames to work with if this has not been done with
- VIDIOC_REQBUF */
+ /* First, allocate some frames to work with
+ if this has not been done with VIDIOC_REQBUF */
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1116,24 @@
call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
}
- /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ /* Then, enqueue as many frames as possible
+ (like a user of VIDIOC_QBUF would do) */
for(i=0;i<usbvision->num_frames;i++) {
frame = &usbvision->frame[i];
if(frame->grabstate == FrameState_Unused) {
/* Mark it as ready and enqueue frame */
frame->grabstate = FrameState_Ready;
frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+ /* Accumulated in usbvision_parse_data() */
+ frame->scanlength = 0;
/* set v4l2_format index */
frame->v4l2_format = usbvision->palette;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
list_add_tail(&frame->frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ spin_unlock_irqrestore(&usbvision->queue_lock,
+ lock_flags);
}
}
@@ -1128,8 +1161,9 @@
return 0;
}
- PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
- frame->index, frame->bytes_read, frame->scanlength);
+ PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+ __FUNCTION__,
+ frame->index, frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1174,11 @@
}
frame->bytes_read += count;
- PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
- (unsigned long)count, frame->bytes_read);
+ PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+ __FUNCTION__,
+ (unsigned long)count, frame->bytes_read);
- // For now, forget the frame if it has not been read in one shot.
+ /* For now, forget the frame if it has not been read in one shot. */
/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */
frame->bytes_read = 0;
@@ -1162,7 +1197,8 @@
u32 i;
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_MMAP, "mmap");
@@ -1180,11 +1216,13 @@
}
for (i = 0; i < usbvision->num_frames; i++) {
- if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+ vma->vm_pgoff)
break;
}
if (i == usbvision->num_frames) {
- PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+ PDEBUG(DBG_MMAP,
+ "mmap: user supplied mapping address is out of range");
up(&usbvision->lock);
return -EINVAL;
}
@@ -1218,8 +1256,8 @@
static int usbvision_radio_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
- struct v4l2_frequency freq;
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1287,6 @@
// If so far no errors then we shall start the radio
usbvision->radio = 1;
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
- freq.frequency = 1517; //SWR3 @ 94.8MHz
- call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
@@ -1270,7 +1306,8 @@
static int usbvision_radio_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "");
@@ -1304,149 +1341,6 @@
return errCode;
}
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EIO;
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
-
- call_i2c_clients(usbvision, cmd, arg);
- PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
-
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
-
- if (t->index > 0)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
- PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
-
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
-
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- memset(f,0,sizeof(*f));
-
- f->type = V4L2_TUNER_RADIO;
- f->frequency = usbvision->freq;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (f->tuner != 0)
- return -EINVAL;
- usbvision->freq = f->frequency;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- default:
- {
- PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
- return -ENOIOCTLCMD;
- }
- }
- return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
/*
* Here comes the stuff for vbi on usbvision based devices
*
@@ -1454,21 +1348,21 @@
static int usbvision_vbi_open(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_vbi_close(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
/* TODO */
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1383,11 @@
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
.mmap = usbvision_v4l2_mmap,
- .ioctl = usbvision_v4l2_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+/* .poll = video_poll, */
+ .mmap = usbvision_v4l2_mmap,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_video_template = {
.owner = THIS_MODULE,
@@ -1500,6 +1397,39 @@
.name = "usbvision-video",
.release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* .vidiocgmbuf = vidiocgmbuf, */
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
@@ -1508,8 +1438,9 @@
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
- .ioctl = usbvision_radio_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_radio_template=
@@ -1518,11 +1449,26 @@
.type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_radio_fops,
- .release = video_device_release,
.name = "usbvision-radio",
+ .release = video_device_release,
.minor = -1,
-};
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
+};
// vbi template
static const struct file_operations usbvision_vbi_fops = {
@@ -1531,6 +1477,7 @@
.release = usbvision_vbi_close,
.ioctl = usbvision_vbi_ioctl,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_vbi_template=
@@ -1574,11 +1521,11 @@
{
// vbi Device:
if (usbvision->vbi) {
- PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+ usbvision->vbi->minor & 0x1f);
if (usbvision->vbi->minor != -1) {
video_unregister_device(usbvision->vbi);
- }
- else {
+ } else {
video_device_release(usbvision->vbi);
}
usbvision->vbi = NULL;
@@ -1586,11 +1533,11 @@
// Radio Device:
if (usbvision->rdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+ usbvision->rdev->minor & 0x1f);
if (usbvision->rdev->minor != -1) {
video_unregister_device(usbvision->rdev);
- }
- else {
+ } else {
video_device_release(usbvision->rdev);
}
usbvision->rdev = NULL;
@@ -1598,11 +1545,11 @@
// Video Device:
if (usbvision->vdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+ usbvision->vdev->minor & 0x1f);
if (usbvision->vdev->minor != -1) {
video_unregister_device(usbvision->vdev);
- }
- else {
+ } else {
video_device_release(usbvision->vdev);
}
usbvision->vdev = NULL;
@@ -1613,37 +1560,52 @@
static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
{
// Video Device:
- usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+ usbvision->vdev = usbvision_vdev_init(usbvision,
+ &usbvision_video_template,
+ "USBVision Video");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+ if (video_register_device(usbvision->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+ usbvision->nr,usbvision->vdev->minor & 0x1f);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
// usbvision has radio
- usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+ usbvision->rdev = usbvision_vdev_init(usbvision,
+ &usbvision_radio_template,
+ "USBVision Radio");
if (usbvision->rdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+ if (video_register_device(usbvision->rdev,
+ VFL_TYPE_RADIO,
+ radio_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+ usbvision->nr, usbvision->rdev->minor & 0x1f);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
- usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+ usbvision->vbi = usbvision_vdev_init(usbvision,
+ &usbvision_vbi_template,
+ "USBVision VBI");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+ if (video_register_device(usbvision->vbi,
+ VFL_TYPE_VBI,
+ vbi_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+ usbvision->nr,usbvision->vbi->minor & 0x1f);
}
// all done
return 0;
@@ -1657,7 +1619,8 @@
/*
* usbvision_alloc()
*
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
*
* Returns NULL on error, a pointer to usb_usbvision else.
*
@@ -1666,7 +1629,8 @@
{
struct usb_usbvision *usbvision;
- if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+ if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+ NULL) {
goto err_exit;
}
@@ -1728,11 +1692,11 @@
}
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
static void usbvision_configure_video(struct usb_usbvision *usbvision)
{
- int model,i;
+ int model;
if (usbvision == NULL)
return;
@@ -1741,25 +1705,23 @@
usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
- usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+ usbvision->Vin_Reg2_Preset =
+ usbvision_device_data[usbvision->DevModel].Vin_Reg2;
} else {
usbvision->Vin_Reg2_Preset = 0;
}
- for (i = 0; i < TVNORMS; i++)
- if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
- break;
- if (i == TVNORMS)
- i = 0;
- usbvision->tvnorm = &tvnorms[i]; /* set default norm */
+ usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
usbvision->ctl_input = 0;
/* This should be here to make i2c clients to be able to register */
- usbvision_audio_off(usbvision); //first switch off audio
+ /* first switch off audio */
+ usbvision_audio_off(usbvision);
if (!PowerOnAtOpen) {
- usbvision_power_on(usbvision); //and then power up the noisy tuner
+ /* and then power up the noisy tuner */
+ usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
}
}
@@ -1796,18 +1758,22 @@
if (usbvision_device_data[model].Interface >= 0) {
interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
- }
- else {
+ } else {
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
- err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
- err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ err("%s: interface %d. has non-ISO endpoint!",
+ __FUNCTION__, ifnum);
+ err("%s: Endpoint attributes %d",
+ __FUNCTION__, endpoint->bmAttributes);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_OUT) {
+ err("%s: interface %d. has ISO OUT endpoint!",
+ __FUNCTION__, ifnum);
return -ENODEV;
}
@@ -1818,11 +1784,9 @@
if (dev->descriptor.bNumConfigurations > 1) {
usbvision->bridgeType = BRIDGE_NT1004;
- }
- else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+ } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
usbvision->bridgeType = BRIDGE_NT1005;
- }
- else {
+ } else {
usbvision->bridgeType = BRIDGE_NT1003;
}
PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1883,11 @@
up(&usbvision->lock);
if (usbvision->user) {
- printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+ printk(KERN_INFO "%s: In use, disconnect pending\n",
+ __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
- }
- else {
+ } else {
usbvision_release(usbvision);
}
@@ -1950,7 +1914,6 @@
PDEBUG(DBG_PROBE, "");
- PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]");
PDEBUG(DBG_IO, "IO debugging is enabled [video]");
PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index c759d00..c5b6c50 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -221,6 +221,8 @@
#define I2C_USB_ADAP_MAX 16
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
/* ----------------------------------------------------------------- */
/* usbvision video structures */
/* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@
__u16 frameHeight; /* 10 - 11 after endian correction*/
};
-/* tvnorms */
-struct usbvision_tvnorm {
- char *name;
- v4l2_std_id id;
- /* mode for saa7113h */
- int mode;
-};
-
struct usbvision_frame {
char *data; /* Frame buffer */
struct usbvision_frame_header isocHeader; /* Header from stream */
@@ -386,7 +380,6 @@
int tuner_type;
int tuner_addr;
int bridgeType; // NT1003, NT1004, NT1005
- int channel;
int radio;
int video_inputs; // # of inputs
unsigned long freq;
@@ -441,7 +434,7 @@
struct v4l2_capability vcap; /* Video capabilities */
unsigned int ctl_input; /* selected input */
- struct usbvision_tvnorm *tvnorm; /* selected tv norm */
+ v4l2_std_id tvnormId; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
// Decompression stuff:
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 0c658b7..e94a9a6 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2077,12 +2077,10 @@
init_waitqueue_entry(&wait, current);
/* add ourselves into wait queue */
add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
- /* and set current state */
- set_current_state(TASK_INTERRUPTIBLE);
/* to ensure that schedule_timeout will return immediately
- * if VINO interrupt was triggred meanwhile */
- schedule_timeout(HZ / 10);
+ * if VINO interrupt was triggered meanwhile */
+ schedule_timeout_interruptible(HZ / 10);
if (signal_pending(current))
err = -EINTR;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3ef4d01..f6d3a94 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/version.h>
+#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -145,9 +146,6 @@
struct vivi_fmt *fmt;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr;
-#endif
};
struct vivi_dmaqueue {
@@ -168,7 +166,7 @@
struct vivi_dev {
struct list_head vivi_devlist;
- struct semaphore lock;
+ struct mutex lock;
int users;
@@ -232,68 +230,13 @@
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
- struct videobuf_buffer *vb)
-{
- int i, pos=0;
- for (i=0;i<vb->dma.nr_pages;i++) {
- to_addr[i].sg=&vb->dma.sglist[i];
- to_addr[i].pos=pos;
- pos += vb->dma.sglist[i].length;
- }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
- int p1=0,p2=pages-1,p3=pages/2;
-
- /* Sanity test */
- BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
- while (p1+1<p2) {
- if (pos < to_addr[p3].pos) {
- p2=p3;
- } else {
- p1=p3;
- }
- p3=(p1+p2)/2;
- }
- if (pos >= to_addr[p2].pos)
- p1=p2;
-
- return (p1);
-}
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
-#else
static void gen_line(char *basep,int inipos,int wmax,
int hmax, int line, char *timestr)
-#endif
{
int w,i,j,pos=inipos,y;
char *p,*s;
u8 chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
- int pgpos,oldpg;
- char *basep;
- struct page *pg;
-
- unsigned long flags;
- spinlock_t spinlock;
-
- spin_lock_init(&spinlock);
-
- /* Get first addr pointed to pixel position */
- oldpg=get_addr_pos(pos,pages,to_addr);
- pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
- spin_lock_irqsave(&spinlock,flags);
- basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
@@ -305,18 +248,7 @@
b=bars[w*7/wmax][2];
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
- kunmap_atomic(basep, KM_BOUNCE_READ);
- basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
switch (color) {
case 0:
@@ -361,23 +293,7 @@
pos=inipos+j*2;
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(
- to_addr[pgpos].sg)
- >> PAGE_SHIFT);
- kunmap_atomic(basep,
- KM_BOUNCE_READ);
- basep= kmap_atomic(pg,
- KM_BOUNCE_READ)+
- to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
y=TO_Y(r,g,b);
@@ -402,12 +318,7 @@
end:
-#ifdef CONFIG_VIVI_SCATTER
- kunmap_atomic(basep, KM_BOUNCE_READ);
- spin_unlock_irqrestore(&spinlock,flags);
-#else
return;
-#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
@@ -415,35 +326,16 @@
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr=buf->to_addr;
- struct videobuf_buffer *vb=&buf->vb;
-#else
char *tmpbuf;
-#endif
-#ifdef CONFIG_VIVI_SCATTER
- /* Test if DMA mapping is ready */
- if (!sg_dma_address(&vb->dma.sglist[0]))
- return;
-
- prep_to_addr(to_addr,vb);
-
- /* Check if there is enough memory */
- BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
if (buf->vb.dma.varea) {
tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
} else {
tmpbuf=buf->vb.dma.vmalloc;
}
-#endif
for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
- gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
if (buf->vb.dma.varea) {
gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
/* FIXME: replacing to __copy_to_user */
@@ -452,7 +344,6 @@
} else {
gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
}
-#endif
pos += wmax*2;
}
@@ -718,11 +609,6 @@
if (in_interrupt())
BUG();
-#ifdef CONFIG_VIVI_SCATTER
- /*FIXME: Maybe a spinlock is required here */
- kfree(buf->to_addr);
- buf->to_addr=NULL;
-#endif
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -768,12 +654,6 @@
buf->vb.state = STATE_PREPARED;
-#ifdef CONFIG_VIVI_SCATTER
- if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
- rc=-ENOMEM;
- goto fail;
- }
-#endif
return 0;
fail:
@@ -838,40 +718,6 @@
free_buffer(vq,buf);
}
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
- int direction)
-{
- int i;
-
- dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
- BUG_ON(direction == DMA_NONE);
-
- for (i = 0; i < nents; i++ ) {
- BUG_ON(!sg[i].page);
-
- sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
- }
-
- return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
-{
- dprintk(1,"%s\n",__FUNCTION__);
- return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
- int direction)
-{
-// dprintk(1,"%s\n",__FUNCTION__);
-
-// flush_write_buffers();
- return 0;
-}
-#endif
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
@@ -893,16 +739,16 @@
static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
{
/* is it free? */
- down(&dev->lock);
+ mutex_lock(&dev->lock);
if (dev->resources) {
/* no, someone else uses it */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
dev->resources =1;
dprintk(1,"res: get\n");
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 1;
}
@@ -913,10 +759,10 @@
static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
{
- down(&dev->lock);
+ mutex_lock(&dev->lock);
dev->resources = 0;
dprintk(1,"res: put\n");
- up(&dev->lock);
+ mutex_lock(&dev->lock);
}
/* ------------------------------------------------------------------
@@ -1260,19 +1106,11 @@
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
-#ifdef CONFIG_VIVI_SCATTER
- videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
- NULL, NULL,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct vivi_buffer),fh);
-#else
videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
-#endif
return 0;
}
@@ -1423,7 +1261,7 @@
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
dev->vidq.timeout.function = vivi_vid_timeout;
dev->vidq.timeout.data = (unsigned long)dev;
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 47cd93f..edb0029 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,6 +1,6 @@
config USB_ZC0301
tristate "USB ZC0301[P] Image Processor and Control Chip support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on the ZC0301 or
ZC0301P Image Processors and Control Chips.
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index 710f12e..a2de50e 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -36,6 +36,7 @@
#include <linux/rwsem.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "zc0301_sensor.h"
@@ -98,7 +99,7 @@
u16 frame_timeout;
};
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
struct zc0301_device {
struct video_device* v4ldev;
@@ -121,12 +122,14 @@
struct zc0301_module_param module_param;
+ struct kref kref;
enum zc0301_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -156,8 +159,8 @@
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -166,8 +169,8 @@
if ((level) == 1 || (level) == 2) \
pr_info("zc0301: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -183,8 +186,8 @@
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index f112055..703b741 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -49,11 +49,11 @@
#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10)
/*****************************************************************************/
@@ -573,7 +573,8 @@
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +635,73 @@
return 0;
}
+/*****************************************************************************/
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
{
+ struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+ kref);
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
kfree(cam->control_buffer);
+ kfree(cam);
}
-/*****************************************************************************/
static int zc0301_open(struct inode* inode, struct file* filp)
{
struct zc0301_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&zc0301_disconnect))
+ if (!down_read_trylock(&zc0301_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&zc0301_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&zc0301_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&zc0301_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&zc0301_disconnect);
- return err;
- }
+ down_read(&zc0301_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&zc0301_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = zc0301_init(cam);
if (err) {
@@ -711,36 +726,32 @@
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&zc0301_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
return err;
}
static int zc0301_release(struct inode* inode, struct file* filp)
{
- struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+ struct zc0301_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&zc0301_dev_lock);
+
+ cam = video_get_drvdata(video_devdata(filp));
zc0301_stop_transfer(cam);
-
zc0301_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- zc0301_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, zc0301_release_resources);
+
+ up_write(&zc0301_dev_lock);
return 0;
}
@@ -775,7 +786,7 @@
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -953,7 +964,12 @@
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -984,7 +1000,6 @@
vma->vm_ops = &zc0301_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
zc0301_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1226,7 @@
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (!s->set_crop) {
@@ -1434,7 +1449,7 @@
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1544,14 +1559,14 @@
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1699,9 +1714,6 @@
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -1949,8 +1961,6 @@
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -1982,7 +1992,7 @@
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -1992,7 +2002,7 @@
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2004,8 +2014,10 @@
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2022,40 +2034,31 @@
static void zc0301_usb_disconnect(struct usb_interface* intf)
{
- struct zc0301_device* cam = usb_get_intfdata(intf);
+ struct zc0301_device* cam;
- if (!cam)
- return;
+ down_write(&zc0301_dev_lock);
- down_write(&zc0301_disconnect);
-
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
zc0301_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- zc0301_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, zc0301_release_resources);
- up_write(&zc0301_disconnect);
+ up_write(&zc0301_dev_lock);
}
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index 3efb92a..24b0dfb 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -327,6 +327,7 @@
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index 5784b1d..9519aba 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -157,6 +157,7 @@
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 44e82cf..70fe6fc 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -23,7 +23,7 @@
#define _ZC0301_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index cf0ed6c..17118a4 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -183,14 +183,7 @@
(sizeof(zoran_formats) / sizeof(struct zoran_format));
// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
-#if defined(CONFIG_BIGPHYS_AREA)
-# include <linux/bigphysarea.h>
-#endif
extern int *zr_debug;
@@ -250,7 +243,6 @@
* Linux with the necessary memory left over).
*/
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
static unsigned long
get_high_mem (unsigned long size)
{
@@ -314,7 +306,6 @@
return hi_mem_ph;
}
-#endif
static int
v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +314,7 @@
struct zoran *zr = fh->zr;
int i, off;
unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
unsigned long pmem = 0;
-#endif
/* we might have old buffers lying around... */
if (fh->v4l_buffers.ready_to_be_freed) {
@@ -369,39 +358,6 @@
ZR_DEVNAME(zr), i, (unsigned long) mem,
virt_to_bus(mem));
} else {
-#if defined(CONFIG_BIGPHYS_AREA)
- /* Use bigphysarea_alloc_pages */
-
- int n =
- (fh->v4l_buffers.buffer_size + PAGE_SIZE -
- 1) / PAGE_SIZE;
-
- mem =
- (unsigned char *) bigphysarea_alloc_pages(n, 0,
- GFP_KERNEL);
- if (mem == 0) {
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
- ZR_DEVNAME(zr), i);
- v4l_fbuffer_free(file);
- return -ENOBUFS;
- }
- fh->v4l_buffers.buffer[i].fbuffer = mem;
- fh->v4l_buffers.buffer[i].fbuffer_phys =
- virt_to_phys(mem);
- fh->v4l_buffers.buffer[i].fbuffer_bus =
- virt_to_bus(mem);
- dprintk(4,
- KERN_INFO
- "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
- ZR_DEVNAME(zr), i, (unsigned) mem,
- (unsigned) virt_to_bus(mem));
-
- /* Zero out the allocated memory */
- memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
- fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
/* Use high memory which has been left at boot time */
@@ -441,20 +397,6 @@
fh->v4l_buffers.buffer[i].fbuffer_bus =
pmem + i * fh->v4l_buffers.buffer_size;
}
-#else
- /* No bigphysarea present, usage of high memory disabled,
- * but user wants buffers of more than MAX_KMALLOC_MEM */
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
- ZR_DEVNAME(zr));
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
- ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
- fh->v4l_buffers.buffer_size >> 10);
- return -ENOBUFS;
-#endif
}
}
@@ -485,11 +427,6 @@
ClearPageReserved(MAP_NR(mem + off));
kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
}
-#if defined(CONFIG_BIGPHYS_AREA)
- else
- bigphysarea_free_pages((void *) fh->v4l_buffers.
- buffer[i].fbuffer);
-#endif
fh->v4l_buffers.buffer[i].fbuffer = NULL;
}
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index b5d3364..6f18925 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -92,6 +92,7 @@
{USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+ {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
{} /* Terminating entry */
};
@@ -792,6 +793,7 @@
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ int err;
DBG("probing...");
@@ -799,12 +801,11 @@
info("model %04x:%04x detected", udev->descriptor.idVendor,
udev->descriptor.idProduct);
- if ((cam =
- kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+ cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+ if (cam == NULL) {
info("cam: out of memory !");
- return -ENODEV;
+ return -ENOMEM;
}
- memset(cam, 0x00, sizeof(struct zr364xx_camera));
/* save the init method used by this camera */
cam->method = id->driver_info;
@@ -812,7 +813,7 @@
if (cam->vdev == NULL) {
info("cam->vdev: out of memory !");
kfree(cam);
- return -ENODEV;
+ return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@
cam->brightness = 64;
mutex_init(&cam->lock);
- if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+ err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (err) {
info("video_register_device failed");
video_device_release(cam->vdev);
kfree(cam->buffer);
kfree(cam);
- return -ENODEV;
+ return err;
}
usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@
static int __init zr364xx_init(void)
{
int retval;
- retval = usb_register(&zr364xx_driver) < 0;
+ retval = usb_register(&zr364xx_driver);
if (retval)
info("usb_register failed!");
else
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 555d594..1cb22bf 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -33,6 +33,7 @@
#include <linux/moduleparam.h>
#include <linux/stringify.h>
#include <linux/stat.h>
+#include <linux/log2.h>
#include "ubi.h"
/* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@
out_wl:
ubi_wl_close(ubi);
out_vtbl:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_si:
ubi_scan_destroy_si(si);
return err;
@@ -422,8 +423,7 @@
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* Make sure minimal I/O unit is power of 2 */
- if (ubi->min_io_size == 0 ||
- (ubi->min_io_size & (ubi->min_io_size - 1))) {
+ if (!is_power_of_2(ubi->min_io_size)) {
ubi_err("bad min. I/O unit");
return -EINVAL;
}
@@ -593,8 +593,6 @@
if (err)
goto out_detach;
- ubi_devices_cnt += 1;
-
ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@
wake_up_process(ubi->bgt_thread);
}
+ ubi_devices_cnt += 1;
return 0;
out_detach:
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_free:
kfree(ubi);
out_mtd:
@@ -650,7 +649,7 @@
uif_close(ubi);
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@
struct mtd_dev_param *p = &mtd_dev_param[i];
cond_resched();
-
- if (!p->name) {
- dbg_err("empty name");
- err = -EINVAL;
- goto out_detach;
- }
-
err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
if (err)
goto out_detach;
@@ -799,7 +791,7 @@
/* Get rid of the final newline */
if (buf[len - 1] == '\n')
- buf[len - 1] = 0;
+ buf[len - 1] = '\0';
for (i = 0; i < 3; i++)
tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@
return -EINVAL;
}
- if (tokens[0] == '\0')
- return -EINVAL;
-
p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 6612eb7..fe4da1e 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -64,6 +64,7 @@
if (ubi_devices[i] && ubi_devices[i]->major == major)
return ubi_devices[i];
BUG();
+ return NULL;
}
/**
@@ -153,7 +154,7 @@
ubi_warn("update of volume %d not finished, volume is damaged",
vol->vol_id);
vol->updating = 0;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
}
ubi_close_volume(desc);
@@ -232,7 +233,7 @@
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -271,7 +272,7 @@
len = count > tbuf_size ? tbuf_size : count;
} while (count);
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -320,7 +321,7 @@
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -355,7 +356,7 @@
len = count > tbuf_size ? tbuf_size : count;
}
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -397,6 +398,7 @@
vol->corrupted = 1;
}
vol->checked = 1;
+ ubi_gluebi_updated(vol);
revoke_exclusive(desc, UBI_READWRITE);
}
@@ -413,19 +415,7 @@
struct ubi_device *ubi = vol->ubi;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
switch (cmd) {
-
/* Volume update command */
case UBI_IOCVOLUP:
{
@@ -471,7 +461,7 @@
{
int32_t lnum;
- err = __get_user(lnum, (__user int32_t *)argp);
+ err = get_user(lnum, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -587,17 +577,6 @@
struct ubi_volume_desc *desc;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
@@ -612,7 +591,7 @@
struct ubi_mkvol_req req;
dbg_msg("create volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_mkvol_req));
if (err) {
err = -EFAULT;
@@ -629,7 +608,7 @@
if (err)
break;
- err = __put_user(req.vol_id, (__user int32_t *)argp);
+ err = put_user(req.vol_id, (__user int32_t *)argp);
if (err)
err = -EFAULT;
@@ -642,7 +621,7 @@
int vol_id;
dbg_msg("remove volume");
- err = __get_user(vol_id, (__user int32_t *)argp);
+ err = get_user(vol_id, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -669,7 +648,7 @@
struct ubi_rsvol_req req;
dbg_msg("re-size volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_rsvol_req));
if (err) {
err = -EFAULT;
@@ -707,7 +686,7 @@
struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE,
.ioctl = ubi_cdev_ioctl,
- .llseek = no_llseek
+ .llseek = no_llseek,
};
/* UBI volume character device operations */
@@ -718,5 +697,5 @@
.llseek = vol_cdev_llseek,
.read = vol_cdev_read,
.write = vol_cdev_write,
- .ioctl = vol_cdev_ioctl
+ .ioctl = vol_cdev_ioctl,
};
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 8636422..310341e 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -35,12 +35,12 @@
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
dbg_msg("erase counter header dump:");
- dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic));
+ dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
dbg_msg("version %d", (int)ec_hdr->version);
- dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec));
- dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset));
- dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset));
- dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+ dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
+ dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
+ dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
+ dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
}
@@ -52,20 +52,20 @@
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
dbg_msg("volume identifier header dump:");
- dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic));
+ dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat);
- dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id));
- dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum));
- dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver));
- dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size));
- dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs));
- dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad));
+ dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
+ dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
+ dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
+ dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
+ dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
+ dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
dbg_msg("sqnum %llu",
- (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
- dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+ (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+ dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:");
}
@@ -91,7 +91,7 @@
if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
- dbg_msg("name %s", vol->name);
+ dbg_msg("name %s", vol->name);
} else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@
*/
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
- int name_len = ubi16_to_cpu(r->name_len);
+ int name_len = be16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx);
- dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs));
- dbg_msg("alignment %d", ubi32_to_cpu(r->alignment));
- dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad));
+ dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
+ dbg_msg("alignment %d", be32_to_cpu(r->alignment));
+ dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
dbg_msg("vol_type %d", (int)r->vol_type);
dbg_msg("upd_marker %d", (int)r->upd_marker);
dbg_msg("name_len %d", name_len);
if (r->name[0] == '\0') {
- dbg_msg("name NULL");
+ dbg_msg("name NULL");
return;
}
if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) {
- dbg_msg("name %s", &r->name[0]);
+ dbg_msg("name %s", &r->name[0]);
} else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]);
}
- dbg_msg("crc %#08x", ubi32_to_cpu(r->crc));
+ dbg_msg("crc %#08x", be32_to_cpu(r->crc));
}
/**
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f816ad9..ff8f395 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -52,7 +52,6 @@
struct ubi_scan_leb;
struct ubi_mkvol_req;
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@
#define dbg_msg(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...) ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c6b223..8aff938 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -425,10 +425,10 @@
} else if (err == UBI_IO_BITFLIPS)
scrub = 1;
- ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
- ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+ ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+ ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
- crc = ubi32_to_cpu(vid_hdr->data_crc);
+ crc = be32_to_cpu(vid_hdr->data_crc);
ubi_free_vid_hdr(ubi, vid_hdr);
}
@@ -518,13 +518,13 @@
goto out_put;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
if (err)
goto write_error;
data_size = offset + len;
- new_buf = kmalloc(data_size, GFP_KERNEL);
+ new_buf = vmalloc(data_size);
if (!new_buf) {
err = -ENOMEM;
goto out_put;
@@ -535,7 +535,7 @@
if (offset > 0) {
err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
if (err && err != UBI_IO_BITFLIPS) {
- kfree(new_buf);
+ vfree(new_buf);
goto out_put;
}
}
@@ -544,11 +544,11 @@
err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
if (err) {
- kfree(new_buf);
+ vfree(new_buf);
goto write_error;
}
- kfree(new_buf);
+ vfree(new_buf);
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -748,17 +748,17 @@
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, data_size);
vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -854,17 +854,17 @@
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, len);
- vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(len);
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->data_size = cpu_to_be32(len);
vid_hdr->copy_flag = 1;
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@
goto write_error;
}
- err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return err;
+ if (vol->eba_tbl[lnum] >= 0) {
+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+ if (err) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+ }
}
vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -965,19 +967,19 @@
uint32_t crc;
void *buf, *buf1 = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
if (vid_hdr->vol_type == UBI_VID_STATIC) {
- data_size = ubi32_to_cpu(vid_hdr->data_size);
+ data_size = be32_to_cpu(vid_hdr->data_size);
aldata_size = ALIGN(data_size, ubi->min_io_size);
} else
data_size = aldata_size =
- ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+ ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
- buf = kmalloc(aldata_size, GFP_KERNEL);
+ buf = vmalloc(aldata_size);
if (!buf)
return -ENOMEM;
@@ -987,7 +989,7 @@
*/
err = leb_write_lock(ubi, vol_id, lnum);
if (err) {
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -1054,10 +1056,10 @@
*/
if (data_size > 0) {
vid_hdr->copy_flag = 1;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->data_crc = cpu_to_be32(crc);
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
if (err)
@@ -1082,7 +1084,7 @@
* We've written the data and are going to read it back to make
* sure it was written correctly.
*/
- buf1 = kmalloc(aldata_size, GFP_KERNEL);
+ buf1 = vmalloc(aldata_size);
if (!buf1) {
err = -ENOMEM;
goto out_unlock;
@@ -1111,15 +1113,15 @@
vol->eba_tbl[lnum] = to;
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return 0;
out_unlock:
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return err;
}
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index fc9478d..41ff74c 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -282,7 +282,6 @@
mtd->flags = MTD_WRITEABLE;
mtd->writesize = ubi->min_io_size;
mtd->owner = THIS_MODULE;
- mtd->size = vol->usable_leb_size * vol->reserved_pebs;
mtd->erasesize = vol->usable_leb_size;
mtd->read = gluebi_read;
mtd->write = gluebi_write;
@@ -290,6 +289,15 @@
mtd->get_device = gluebi_get_device;
mtd->put_device = gluebi_put_device;
+ /*
+ * In case of dynamic volume, MTD device size is just volume size. In
+ * case of a static volume the size is equivalent to the amount of data
+ * bytes, which is zero at this moment and will be changed after volume
+ * update.
+ */
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n");
kfree(mtd->name);
@@ -321,3 +329,20 @@
kfree(mtd->name);
return 0;
}
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+ struct mtd_info *mtd = &vol->gluebi_mtd;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME)
+ mtd->size = vol->used_bytes;
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 438914d..b0d8f4c 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -125,9 +125,9 @@
* o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
* correctable bit-flips were detected; this is harmless but may indicate
* that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- * problems, for example it can me an ECC error in case of NAND; this most
- * probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ * example it can be an ECC error in case of NAND; this most probably means
+ * that the data is corrupted;
* o %-EIO if some I/O error occurred;
* o other negative error codes in case of other errors.
*/
@@ -298,7 +298,7 @@
memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = ubi->mtd;
- ei.addr = pnum * ubi->peb_size;
+ ei.addr = (loff_t)pnum * ubi->peb_size;
ei.len = ubi->peb_size;
ei.callback = erase_callback;
ei.priv = (unsigned long)&wq;
@@ -382,7 +382,7 @@
void *buf;
int err, i, patt_count;
- buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+ buf = vmalloc(ubi->peb_size);
if (!buf)
return -ENOMEM;
@@ -437,7 +437,7 @@
* physical eraseblock which means something is wrong with it.
*/
err = -EIO;
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -557,9 +557,9 @@
long long ec;
int vid_hdr_offset, leb_start;
- ec = ubi64_to_cpu(ec_hdr->ec);
- vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
- leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+ ec = be64_to_cpu(ec_hdr->ec);
+ vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+ leb_start = be32_to_cpu(ec_hdr->data_offset);
if (ec_hdr->version != UBI_VERSION) {
ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@
read_err = err;
}
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
/*
* The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@
}
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -729,12 +729,12 @@
dbg_io("write EC header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+ ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
ec_hdr->version = UBI_VERSION;
- ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
- ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+ ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+ ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+ ec_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
@@ -757,13 +757,13 @@
{
int vol_type = vid_hdr->vol_type;
int copy_flag = vid_hdr->copy_flag;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int lnum = ubi32_to_cpu(vid_hdr->lnum);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int lnum = be32_to_cpu(vid_hdr->lnum);
int compat = vid_hdr->compat;
- int data_size = ubi32_to_cpu(vid_hdr->data_size);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
- int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ int data_size = be32_to_cpu(vid_hdr->data_size);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
+ int data_crc = be32_to_cpu(vid_hdr->data_crc);
int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@
read_err = err;
}
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
/*
* If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@
}
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -1007,10 +1007,10 @@
if (err)
return err > 0 ? -EINVAL: err;
- vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+ vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+ vid_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
@@ -1060,7 +1060,7 @@
int err;
uint32_t magic;
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x",
magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@
goto exit;
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@
int err;
uint32_t magic;
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@
goto exit;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@
void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- buf = kzalloc(len, GFP_KERNEL);
+ buf = vmalloc(len);
if (!buf)
return -ENOMEM;
+ memset(buf, 0, len);
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@
goto fail;
}
- kfree(buf);
+ vfree(buf);
return 0;
fail:
@@ -1252,7 +1253,7 @@
err = 1;
error:
ubi_dbg_dump_stack();
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d352c45..4a458e8 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -37,14 +37,9 @@
{
const struct ubi_device *ubi;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
- !ubi_devices[ubi_num]) {
- module_put(THIS_MODULE);
+ !ubi_devices[ubi_num])
return -ENODEV;
- }
ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@
di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode;
di->cdev = MKDEV(ubi->major, 0);
- module_put(THIS_MODULE);
return 0;
}
EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@
offset + len > vol->usable_leb_size)
return -EINVAL;
- if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
- offset + len > vol->last_eb_bytes)
- return -EINVAL;
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ if (vol->used_ebs == 0)
+ /* Empty static UBI volume */
+ return 0;
+ if (lnum == vol->used_ebs - 1 &&
+ offset + len > vol->last_eb_bytes)
+ return -EINVAL;
+ }
if (vol->upd_marker)
return -EBADF;
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 38d4e67..9e2338c 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -67,7 +67,7 @@
if (vol->vol_type != UBI_STATIC_VOLUME)
return 0;
- buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+ buf = vmalloc(vol->usable_leb_size);
if (!buf)
return -ENOMEM;
@@ -87,7 +87,7 @@
}
}
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 473f320..94ee549 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -24,7 +24,7 @@
* This unit is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image.
*
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
* Information about found volumes is represented by &struct ubi_scan_volume
* objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@
static struct ubi_ec_hdr *ech;
static struct ubi_vid_hdr *vidh;
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+ struct list_head *list)
{
struct ubi_scan_leb *seb;
@@ -121,9 +132,9 @@
const struct ubi_scan_volume *sv, int pnum)
{
int vol_type = vid_hdr->vol_type;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
if (sv->leb_count != 0) {
int sv_vol_type;
@@ -189,7 +200,7 @@
struct ubi_scan_volume *sv;
struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
- ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+ ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */
while (*p) {
@@ -211,11 +222,10 @@
return ERR_PTR(-ENOMEM);
sv->highest_lnum = sv->leb_count = 0;
- si->max_sqnum = 0;
sv->vol_id = vol_id;
sv->root = RB_ROOT;
- sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
sv->compat = vid_hdr->compat;
sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@
int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc;
struct ubi_vid_hdr *vidh = NULL;
- unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+ unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) {
- long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+ long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
/*
* UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@
/* Read the data of the copy and check the CRC */
- len = ubi32_to_cpu(vid_hdr->data_size);
- buf = kmalloc(len, GFP_KERNEL);
+ len = be32_to_cpu(vid_hdr->data_size);
+ buf = vmalloc(len);
if (!buf) {
err = -ENOMEM;
goto out_free_vidh;
@@ -355,7 +365,7 @@
if (err && err != UBI_IO_BITFLIPS)
goto out_free_buf;
- data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ data_crc = be32_to_cpu(vid_hdr->data_crc);
crc = crc32(UBI_CRC32_INIT, buf, len);
if (crc != data_crc) {
dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@
bitflips = !!err;
}
- kfree(buf);
+ vfree(buf);
ubi_free_vid_hdr(ubi, vidh);
if (second_is_newer)
@@ -379,7 +389,7 @@
return second_is_newer | (bitflips << 1) | (corrupted << 2);
out_free_buf:
- kfree(buf);
+ vfree(buf);
out_free_vidh:
ubi_free_vid_hdr(ubi, vidh);
ubi_assert(err < 0);
@@ -396,8 +406,12 @@
* @vid_hdr: the volume identifier header
* @bitflips: if bit-flips were detected when this physical eraseblock was read
*
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
*/
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@
struct ubi_scan_leb *seb;
struct rb_node **p, *parent = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
- sqnum = ubi64_to_cpu(vid_hdr->sqnum);
- leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
+ sqnum = be64_to_cpu(vid_hdr->sqnum);
+ leb_ver = be32_to_cpu(vid_hdr->leb_ver);
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@
if (IS_ERR(sv) < 0)
return PTR_ERR(sv);
+ if (si->max_sqnum < sqnum)
+ si->max_sqnum = sqnum;
+
/*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@
return err;
if (cmp_res & 4)
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->corr);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->corr);
else
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->erase);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->erase);
if (err)
return err;
@@ -508,7 +525,7 @@
if (sv->highest_lnum == lnum)
sv->last_data_size =
- ubi32_to_cpu(vid_hdr->data_size);
+ be32_to_cpu(vid_hdr->data_size);
return 0;
} else {
@@ -517,11 +534,9 @@
* previously.
*/
if (cmp_res & 4)
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->corr);
+ return add_to_list(si, pnum, ec, &si->corr);
else
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->erase);
+ return add_to_list(si, pnum, ec, &si->erase);
}
}
@@ -547,12 +562,9 @@
if (sv->highest_lnum <= lnum) {
sv->highest_lnum = lnum;
- sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+ sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
}
- if (si->max_sqnum < sqnum)
- si->max_sqnum = sqnum;
-
sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@
return -EINVAL;
}
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0);
if (err < 0)
@@ -754,7 +766,7 @@
* @si: scanning information
* @pnum: the physical eraseblock number
*
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure.
*/
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
- return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
- &si->erase);
+ return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
else if (err == UBI_IO_BAD_EC_HDR) {
/*
* We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@
return -EINVAL;
}
- ec = ubi64_to_cpu(ech->ec);
+ ec = be64_to_cpu(ech->ec);
if (ec > UBI_MAX_ERASECOUNTER) {
/*
* Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@
else if (err == UBI_IO_BAD_VID_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
goto adjust_mean_ec;
} else if (err == UBI_IO_PEB_FREE) {
/* No VID header - the physical eraseblock is free */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+ err = add_to_list(si, pnum, ec, &si->free);
if (err)
return err;
goto adjust_mean_ec;
}
- vol_id = ubi32_to_cpu(vidh->vol_id);
+ vol_id = be32_to_cpu(vidh->vol_id);
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
- int lnum = ubi32_to_cpu(vidh->lnum);
+ int lnum = be32_to_cpu(vidh->lnum);
/* Unsupported internal volume */
switch (vidh->compat) {
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, remove it", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
break;
@@ -868,7 +879,7 @@
case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+ err = add_to_list(si, pnum, ec, &si->alien);
if (err)
return err;
si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@
uint8_t *buf;
/*
- * At first, check that scanning information is ok.
+ * At first, check that scanning information is OK.
*/
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
int leb_count = 0;
@@ -1249,12 +1260,12 @@
goto bad_vid_hdr;
}
- if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+ if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
ubi_err("bad sqnum %llu", seb->sqnum);
goto bad_vid_hdr;
}
- if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+ if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
ubi_err("bad vol_id %d", sv->vol_id);
goto bad_vid_hdr;
}
@@ -1264,22 +1275,22 @@
goto bad_vid_hdr;
}
- if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (seb->lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad lnum %d", seb->lnum);
goto bad_vid_hdr;
}
- if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+ if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
ubi_err("bad used_ebs %d", sv->used_ebs);
goto bad_vid_hdr;
}
- if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+ if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
ubi_err("bad data_pad %d", sv->data_pad);
goto bad_vid_hdr;
}
- if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+ if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
ubi_err("bad leb_ver %u", seb->leb_ver);
goto bad_vid_hdr;
}
@@ -1288,12 +1299,12 @@
if (!last_seb)
continue;
- if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad highest_lnum %d", sv->highest_lnum);
goto bad_vid_hdr;
}
- if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+ if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
ubi_err("bad last_data_size %d", sv->last_data_size);
goto bad_vid_hdr;
}
@@ -1310,8 +1321,10 @@
memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum);
- if (err < 0)
+ if (err < 0) {
+ kfree(buf);
return err;
+ }
else if (err)
buf[pnum] = 0;
}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 3949f61..140e82e 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,8 +147,6 @@
list_add_tail(&seb->u.list, list);
}
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list);
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index feb647f..5959f91 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -35,6 +35,7 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@
#ifdef CONFIG_MTD_UBI_GLUEBI
int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
#else
#define ubi_create_gluebi(ubi, vol) 0
#define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
#endif
/* eba.c */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 8925b97..0efc586 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -150,7 +150,7 @@
vol->updating = 0;
}
- vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+ vol->upd_buf = vmalloc(ubi->leb_size);
if (!vol->upd_buf)
return -ENOMEM;
@@ -339,7 +339,7 @@
err = ubi_wl_flush(ubi);
if (err == 0) {
err = to_write;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
vol->updating = 0;
}
}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 622d0d1..ea0d5c8 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -228,7 +228,7 @@
for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
- strcmp(ubi->volumes[i]->name, req->name) == 0) {
+ !strcmp(ubi->volumes[i]->name, req->name)) {
dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
@@ -243,7 +243,6 @@
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
- spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
goto out_unlock;
}
@@ -281,7 +280,8 @@
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
} else {
bytes = vol->used_bytes;
vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@
/* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
- vtbl_rec.alignment = cpu_to_ubi32(vol->alignment);
- vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad);
- vtbl_rec.name_len = cpu_to_ubi16(vol->name_len);
+ vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+ vtbl_rec.alignment = cpu_to_be32(vol->alignment);
+ vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
+ vtbl_rec.name_len = cpu_to_be16(vol->name_len);
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else
@@ -352,6 +352,7 @@
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
out_unlock:
spin_unlock(&ubi->volumes_lock);
kfree(vol);
@@ -368,6 +369,7 @@
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
volume_sysfs_close(vol);
return err;
@@ -503,7 +505,7 @@
/* Change volume table record */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+ vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
@@ -537,7 +539,8 @@
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
}
paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@
* @ubi: UBI device description object
* @vol_id: volume ID
*/
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
- const struct ubi_volume *vol = ubi->volumes[idx];
+ const struct ubi_volume *vol;
long long n;
const char *name;
- reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ spin_lock(&ubi->volumes_lock);
+ reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ vol = ubi->volumes[idx];
if (!vol) {
if (reserved_pebs) {
ubi_err("no volume info, but volume exists");
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
+ return;
+ }
+
+ if (vol->exclusive) {
+ /*
+ * The volume may be being created at the moment, do not check
+ * it (e.g., it may be in the middle of ubi_create_volume().
+ */
+ spin_unlock(&ubi->volumes_lock);
return;
}
@@ -726,7 +741,7 @@
goto fail;
}
- n = vol->used_ebs * vol->usable_leb_size;
+ n = (long long)vol->used_ebs * vol->usable_leb_size;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
if (vol->corrupted != 0) {
ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@
}
}
- alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
- data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
- name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+ alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+ data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+ name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
upd_marker = ubi->vtbl[vol_id].upd_marker;
name = &ubi->vtbl[vol_id].name[0];
if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
return;
fail:
- ubi_err("paranoid check failed");
+ ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ spin_unlock(&ubi->volumes_lock);
BUG();
}
@@ -800,10 +817,8 @@
int i;
mutex_lock(&ubi->vtbl_mutex);
- spin_lock(&ubi->volumes_lock);
for (i = 0; i < ubi->vtbl_slots; i++)
paranoid_check_volume(ubi, i);
- spin_unlock(&ubi->volumes_lock);
mutex_unlock(&ubi->vtbl_mutex);
}
#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index b6fd6bb..bc5df50 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -93,12 +93,9 @@
vtbl_rec = &empty_vtbl_record;
else {
crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
- vtbl_rec->crc = cpu_to_ubi32(crc);
+ vtbl_rec->crc = cpu_to_be32(crc);
}
- dbg_msg("change record %d", idx);
- ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
mutex_lock(&ubi->vtbl_mutex);
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- alignment = ubi32_to_cpu(vtbl[i].alignment);
- data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ alignment = be32_to_cpu(vtbl[i].alignment);
+ data_pad = be32_to_cpu(vtbl[i].data_pad);
upd_marker = vtbl[i].upd_marker;
vol_type = vtbl[i].vol_type;
- name_len = ubi16_to_cpu(vtbl[i].name_len);
+ name_len = be16_to_cpu(vtbl[i].name_len);
name = &vtbl[i].name[0];
crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
- if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+ if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
- i, crc, ubi32_to_cpu(vtbl[i].crc));
+ i, crc, be32_to_cpu(vtbl[i].crc));
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return 1;
}
@@ -225,8 +222,8 @@
/* Checks that all names are unique */
for (i = 0; i < ubi->vtbl_slots - 1; i++) {
for (n = i + 1; n < ubi->vtbl_slots; n++) {
- int len1 = ubi16_to_cpu(vtbl[i].name_len);
- int len2 = ubi16_to_cpu(vtbl[n].name_len);
+ int len1 = be16_to_cpu(vtbl[i].name_len);
+ int len2 = be16_to_cpu(vtbl[n].name_len);
if (len1 > 0 && len1 == len2 &&
!strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
vid_hdr->data_size = vid_hdr->used_ebs =
- vid_hdr->data_pad = cpu_to_ubi32(0);
- vid_hdr->lnum = cpu_to_ubi32(copy);
- vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
- vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+ vid_hdr->data_pad = cpu_to_be32(0);
+ vid_hdr->lnum = cpu_to_be32(copy);
+ vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@
return err;
write_error:
- kfree(new_seb);
- /* May be this physical eraseblock went bad, try to pick another one */
- if (++tries <= 5) {
- err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
- &si->corr);
- if (!err)
- goto retry;
+ if (err == -EIO && ++tries <= 5) {
+ /*
+ * Probably this physical eraseblock went bad, try to pick
+ * another one.
+ */
+ list_add_tail(&new_seb->u.list, &si->corr);
+ goto retry;
}
+ kfree(new_seb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -380,11 +378,12 @@
/* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ leb[seb->lnum] = vmalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) {
err = -ENOMEM;
goto out_free;
}
+ memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size);
@@ -415,7 +414,7 @@
}
/* Both LEB 1 and LEB 2 are OK and consistent */
- kfree(leb[1]);
+ vfree(leb[1]);
return leb[0];
} else {
/* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@
goto out_free;
ubi_msg("volume table was restored");
- kfree(leb[0]);
+ vfree(leb[0]);
return leb[1];
}
out_free:
- kfree(leb[0]);
- kfree(leb[1]);
+ vfree(leb[0]);
+ vfree(leb[1]);
return ERR_PTR(err);
}
@@ -460,9 +459,10 @@
int i;
struct ubi_vtbl_record *vtbl;
- vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ vtbl = vmalloc(ubi->vtbl_size);
if (!vtbl)
return ERR_PTR(-ENOMEM);
+ memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@
err = create_vtbl(ubi, si, i, vtbl);
if (err) {
- kfree(vtbl);
+ vfree(vtbl);
return ERR_PTR(err);
}
}
@@ -500,19 +500,19 @@
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+ if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
continue; /* Empty record */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
- vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
- vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ vol->alignment = be32_to_cpu(vtbl[i].alignment);
+ vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
- vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+ vol->name_len = be16_to_cpu(vtbl[i].name_len);
vol->usable_leb_size = ubi->leb_size - vol->data_pad;
memcpy(vol->name, vtbl[i].name, vol->name_len);
vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
continue;
}
@@ -561,7 +562,8 @@
}
vol->used_ebs = sv->used_ebs;
- vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
vol->used_bytes += sv->last_data_size;
vol->last_eb_bytes = sv->last_data_size;
}
@@ -578,7 +580,8 @@
vol->usable_leb_size = ubi->leb_size;
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->reserved_pebs;
- vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+ vol->used_bytes =
+ (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
vol->vol_id = UBI_LAYOUT_VOL_ID;
ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@
int i, err;
struct ubi_scan_volume *sv;
- empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
/*
* The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@
return 0;
out_free:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
if (ubi->volumes[i]) {
kfree(ubi->volumes[i]);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index ab2174a..9de9537 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -667,7 +667,7 @@
dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (err)
@@ -1060,9 +1060,8 @@
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel)
{
- int err;
struct ubi_wl_entry *e = wl_wrk->e;
- int pnum = e->pnum;
+ int pnum = e->pnum, err, need;
if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@
kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e);
- if (err != -EIO) {
+ if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+ err == -EBUSY) {
+ int err1;
+
+ /* Re-schedule the LEB for erasure */
+ err1 = schedule_erase(ubi, e, 0);
+ if (err1) {
+ err = err1;
+ goto out_ro;
+ }
+ return err;
+ } else if (err != -EIO) {
/*
* If this is not %-EIO, we have no idea what to do. Scheduling
* this physical eraseblock for erasure again would cause
* errors again and again. Well, lets switch to RO mode.
*/
- ubi_ro_mode(ubi);
- return err;
+ goto out_ro;
}
/* It is %-EIO, the PEB went bad */
if (!ubi->bad_allowed) {
ubi_err("bad physical eraseblock %d detected", pnum);
- ubi_ro_mode(ubi);
- err = -EIO;
- } else {
- int need;
-
- spin_lock(&ubi->volumes_lock);
- need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
- if (need > 0) {
- need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
- ubi->avail_pebs -= need;
- ubi->rsvd_pebs += need;
- ubi->beb_rsvd_pebs += need;
- if (need > 0)
- ubi_msg("reserve more %d PEBs", need);
- }
-
- if (ubi->beb_rsvd_pebs == 0) {
- spin_unlock(&ubi->volumes_lock);
- ubi_err("no reserved physical eraseblocks");
- ubi_ro_mode(ubi);
- return -EIO;
- }
-
- spin_unlock(&ubi->volumes_lock);
- ubi_msg("mark PEB %d as bad", pnum);
-
- err = ubi_io_mark_bad(ubi, pnum);
- if (err) {
- ubi_ro_mode(ubi);
- return err;
- }
-
- spin_lock(&ubi->volumes_lock);
- ubi->beb_rsvd_pebs -= 1;
- ubi->bad_peb_count += 1;
- ubi->good_peb_count -= 1;
- ubi_calculate_reserved(ubi);
- if (ubi->beb_rsvd_pebs == 0)
- ubi_warn("last PEB from the reserved pool was used");
- spin_unlock(&ubi->volumes_lock);
+ goto out_ro;
}
+ spin_lock(&ubi->volumes_lock);
+ need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+ if (need > 0) {
+ need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+ ubi->avail_pebs -= need;
+ ubi->rsvd_pebs += need;
+ ubi->beb_rsvd_pebs += need;
+ if (need > 0)
+ ubi_msg("reserve more %d PEBs", need);
+ }
+
+ if (ubi->beb_rsvd_pebs == 0) {
+ spin_unlock(&ubi->volumes_lock);
+ ubi_err("no reserved physical eraseblocks");
+ goto out_ro;
+ }
+
+ spin_unlock(&ubi->volumes_lock);
+ ubi_msg("mark PEB %d as bad", pnum);
+
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ goto out_ro;
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->beb_rsvd_pebs -= 1;
+ ubi->bad_peb_count += 1;
+ ubi->good_peb_count -= 1;
+ ubi_calculate_reserved(ubi);
+ if (ubi->beb_rsvd_pebs == 0)
+ ubi_warn("last PEB from the reserved pool was used");
+ spin_unlock(&ubi->volumes_lock);
+
+ return err;
+
+out_ro:
+ ubi_ro_mode(ubi);
return err;
}
@@ -1634,7 +1641,7 @@
goto out_free;
}
- read_ec = ubi64_to_cpu(ec_hdr->ec);
+ read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) {
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 43d0317..5fb659f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2486,6 +2486,18 @@
source "drivers/s390/net/Kconfig"
+config XEN_NETDEV_FRONTEND
+ tristate "Xen network device frontend driver"
+ depends on XEN
+ default y
+ help
+ The network device frontend driver allows the kernel to
+ access network devices exported exported by a virtual
+ machine containing a physical network device driver. The
+ frontend driver is intended for unprivileged guest domains;
+ if you are compiling a kernel for a Xen guest, you almost
+ certainly want to enable this.
+
config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
depends on PPC_ISERIES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index eb41676..0e286ab 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -127,6 +127,8 @@
obj-$(CONFIG_SLIP) += slip.o
obj-$(CONFIG_SLHC) += slhc.o
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d23861c..a729da0 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -54,8 +54,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.6.2"
-#define DRV_MODULE_RELDATE "July 6, 2007"
+#define DRV_MODULE_VERSION "1.6.3"
+#define DRV_MODULE_RELDATE "July 16, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -126,91 +126,102 @@
static struct flash_spec flash_table[] =
{
+#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
/* Slow EEPROM */
{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - slow"},
/* Expansion entry 0001 */
{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0001"},
/* Saifun SA25F010 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
"Non-buffered flash (128kB)"},
/* Saifun SA25F020 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
"Non-buffered flash (256kB)"},
/* Expansion entry 0100 */
{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0100"},
/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
"Entry 0101: ST M45PE10 (128kB non-bufferred)"},
/* Entry 0110: ST M45PE20 (non-buffered flash)*/
{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
"Entry 0110: ST M45PE20 (256kB non-bufferred)"},
/* Saifun SA25F005 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
"Non-buffered flash (64kB)"},
/* Fast EEPROM */
{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - fast"},
/* Expansion entry 1001 */
{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1001"},
/* Expansion entry 1010 */
{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1010"},
/* ATMEL AT45DB011B (buffered flash) */
{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
"Buffered flash (128kB)"},
/* Expansion entry 1100 */
{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1100"},
/* Expansion entry 1101 */
{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1101"},
/* Ateml Expansion entry 1110 */
{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1110 (Atmel)"},
/* ATMEL AT45DB021B (buffered flash) */
{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
"Buffered flash (256kB)"},
};
+static struct flash_spec flash_5709 = {
+ .flags = BNX2_NV_BUFFERED,
+ .page_bits = BCM5709_FLASH_PAGE_BITS,
+ .page_size = BCM5709_FLASH_PAGE_SIZE,
+ .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
+ .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
+ .name = "5709 Buffered flash (256kB)",
+};
+
MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -3289,7 +3300,7 @@
val = REG_RD(bp, BNX2_MISC_CFG);
REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
- if (!bp->flash_info->buffered) {
+ if (bp->flash_info->flags & BNX2_NV_WREN) {
int j;
REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3349,7 +3360,7 @@
u32 cmd;
int j;
- if (bp->flash_info->buffered)
+ if (bp->flash_info->flags & BNX2_NV_BUFFERED)
/* Buffered flash, no erase needed */
return 0;
@@ -3392,8 +3403,8 @@
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3439,8 +3450,8 @@
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3478,15 +3489,19 @@
bnx2_init_nvram(struct bnx2 *bp)
{
u32 val;
- int j, entry_count, rc;
+ int j, entry_count, rc = 0;
struct flash_spec *flash;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ bp->flash_info = &flash_5709;
+ goto get_flash_size;
+ }
+
/* Determine the selected interface. */
val = REG_RD(bp, BNX2_NVM_CFG1);
entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
- rc = 0;
if (val & 0x40000000) {
/* Flash interface has been reconfigured */
@@ -3542,6 +3557,7 @@
return -ENODEV;
}
+get_flash_size:
val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
if (val)
@@ -3706,7 +3722,7 @@
buf = align_buf;
}
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
flash_buffer = kmalloc(264, GFP_KERNEL);
if (flash_buffer == NULL) {
rc = -ENOMEM;
@@ -3739,7 +3755,7 @@
bnx2_enable_nvram_access(bp);
cmd_flags = BNX2_NVM_COMMAND_FIRST;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
int j;
/* Read the whole page into the buffer
@@ -3767,7 +3783,7 @@
/* Loop to write back the buffer data from page_start to
* data_start */
i = 0;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
/* Erase the page */
if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
goto nvram_write_end;
@@ -3791,7 +3807,7 @@
/* Loop to write the new data from data_start to data_end */
for (addr = data_start; addr < data_end; addr += 4, i += 4) {
if ((addr == page_end - 4) ||
- ((bp->flash_info->buffered) &&
+ ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
(addr == data_end - 4))) {
cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3808,7 +3824,7 @@
/* Loop to write back the buffer data from data_end
* to page_end */
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
for (addr = data_end; addr < page_end;
addr += 4, i += 4) {
@@ -4107,7 +4123,7 @@
if (CHIP_NUM(bp) == CHIP_NUM_5708)
REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
else
- REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+ REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -4127,10 +4143,6 @@
REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
- if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
- BNX2_PORT_FEATURE_ASF_ENABLED)
- bp->flags |= ASF_ENABLE_FLAG;
-
/* Initialize the receive filter. */
bnx2_set_rx_mode(bp->dev);
@@ -5786,8 +5798,9 @@
if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
bp->stats_ticks = USEC_PER_SEC;
}
- if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
- bp->stats_ticks &= 0xffff00;
+ if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+ bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+ bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
if (netif_running(bp->dev)) {
bnx2_netif_stop(bp);
@@ -6629,6 +6642,18 @@
if (i != 2)
bp->fw_version[j++] = '.';
}
+ if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
+ BNX2_PORT_FEATURE_ASF_ENABLED) {
+ bp->flags |= ASF_ENABLE_FLAG;
+
+ for (i = 0; i < 30; i++) {
+ reg = REG_RD_IND(bp, bp->shmem_base +
+ BNX2_BC_STATE_CONDITION);
+ if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+ break;
+ msleep(10);
+ }
+ }
reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
reg &= BNX2_CONDITION_MFW_RUN_MASK;
if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
@@ -6672,7 +6697,7 @@
bp->rx_ticks_int = 18;
bp->rx_ticks = 18;
- bp->stats_ticks = 1000000 & 0xffff00;
+ bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
bp->timer_interval = HZ;
bp->current_interval = HZ;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index d8cd1af..102adfe 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6433,6 +6433,11 @@
#define ST_MICRO_FLASH_PAGE_SIZE 256
#define ST_MICRO_FLASH_BASE_TOTAL_SIZE 65536
+#define BCM5709_FLASH_PAGE_BITS 8
+#define BCM5709_FLASH_PHY_PAGE_SIZE (1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK (BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE 256
+
#define NVRAM_TIMEOUT_COUNT 30000
@@ -6449,7 +6454,10 @@
u32 config2;
u32 config3;
u32 write1;
- u32 buffered;
+ u32 flags;
+#define BNX2_NV_BUFFERED 0x00000001
+#define BNX2_NV_TRANSLATE 0x00000002
+#define BNX2_NV_WREN 0x00000004
u32 page_bits;
u32 page_size;
u32 addr_mask;
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 84aa211..355c6cf 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -320,7 +320,7 @@
sprintf(portarg, "%ld", bc->pdev->port->base);
printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
- return call_usermodehelper(eppconfig_path, argv, envp, 1);
+ return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
}
/* ---------------------------------------------------------------------- */
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 5891a0f..f871760 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -824,6 +824,7 @@
struct pppol2tp_session *session;
struct pppol2tp_tunnel *tunnel;
struct udphdr *uh;
+ unsigned int len;
error = -ENOTCONN;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -912,14 +913,15 @@
}
/* Queue the packet to IP for output */
+ len = skb->len;
error = ip_queue_xmit(skb, 1);
/* Update stats */
if (error >= 0) {
tunnel->stats.tx_packets++;
- tunnel->stats.tx_bytes += skb->len;
+ tunnel->stats.tx_bytes += len;
session->stats.tx_packets++;
- session->stats.tx_bytes += skb->len;
+ session->stats.tx_bytes += len;
} else {
tunnel->stats.tx_errors++;
session->stats.tx_errors++;
@@ -958,6 +960,7 @@
__wsum csum = 0;
struct sk_buff *skb2 = NULL;
struct udphdr *uh;
+ unsigned int len;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
@@ -1046,18 +1049,25 @@
printk("\n");
}
+ memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
+ IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+ IPSKB_REROUTED);
+ nf_reset(skb2);
+
/* Get routing info from the tunnel socket */
+ dst_release(skb2->dst);
skb2->dst = sk_dst_get(sk_tun);
/* Queue the packet to IP for output */
+ len = skb2->len;
rc = ip_queue_xmit(skb2, 1);
/* Update stats */
if (rc >= 0) {
tunnel->stats.tx_packets++;
- tunnel->stats.tx_bytes += skb2->len;
+ tunnel->stats.tx_bytes += len;
session->stats.tx_packets++;
- session->stats.tx_bytes += skb2->len;
+ session->stats.tx_bytes += len;
} else {
tunnel->stats.tx_errors++;
session->stats.tx_errors++;
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 8a667c1..b801e3b 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -12,6 +12,7 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
+#include <linux/mutex.h>
#include <asm/vio.h>
#include <asm/ldc.h>
@@ -497,6 +498,8 @@
vio_link_state_change(vio, event);
spin_unlock_irqrestore(&vio->lock, flags);
+ if (event == LDC_EVENT_RESET)
+ vio_port_up(vio);
return;
}
@@ -875,6 +878,115 @@
return err;
}
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+ struct net_device *dev;
+ struct vnet *vp;
+ int err, i;
+
+ dev = alloc_etherdev(sizeof(*vp));
+ if (!dev) {
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ vp = netdev_priv(dev);
+
+ spin_lock_init(&vp->lock);
+ vp->dev = dev;
+
+ INIT_LIST_HEAD(&vp->port_list);
+ for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&vp->port_hash[i]);
+ INIT_LIST_HEAD(&vp->list);
+ vp->local_mac = *local_mac;
+
+ dev->open = vnet_open;
+ dev->stop = vnet_close;
+ dev->set_multicast_list = vnet_set_rx_mode;
+ dev->set_mac_address = vnet_set_mac_addr;
+ dev->tx_timeout = vnet_tx_timeout;
+ dev->ethtool_ops = &vnet_ethtool_ops;
+ dev->watchdog_timeo = VNET_TX_TIMEOUT;
+ dev->change_mtu = vnet_change_mtu;
+ dev->hard_start_xmit = vnet_start_xmit;
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_dev;
+ }
+
+ printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+ list_add(&vp->list, &vnet_list);
+
+ return vp;
+
+err_out_free_dev:
+ free_netdev(dev);
+
+ return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+ struct vnet *iter, *vp;
+
+ mutex_lock(&vnet_list_mutex);
+ vp = NULL;
+ list_for_each_entry(iter, &vnet_list, list) {
+ if (iter->local_mac == *local_mac) {
+ vp = iter;
+ break;
+ }
+ }
+ if (!vp)
+ vp = vnet_new(local_mac);
+ mutex_unlock(&vnet_list_mutex);
+
+ return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+ u64 port_node)
+{
+ const u64 *local_mac = NULL;
+ u64 a;
+
+ mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+ u64 target = mdesc_arc_target(hp, a);
+ const char *name;
+
+ name = mdesc_get_property(hp, target, "name", NULL);
+ if (!name || strcmp(name, "network"))
+ continue;
+
+ local_mac = mdesc_get_property(hp, target,
+ local_mac_prop, NULL);
+ if (local_mac)
+ break;
+ }
+ if (!local_mac)
+ return ERR_PTR(-ENODEV);
+
+ return vnet_find_or_create(local_mac);
+}
+
static struct ldc_channel_config vnet_ldc_cfg = {
.event = vnet_event,
.mtu = 64,
@@ -887,6 +999,14 @@
.handshake_complete = vnet_handshake_complete,
};
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
const char *remote_macaddr_prop = "remote-mac-address";
static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1019,17 @@
const u64 *rmac;
int len, i, err, switch_port;
- vp = dev_get_drvdata(vdev->dev.parent);
- if (!vp) {
- printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
- return -ENODEV;
- }
+ print_version();
hp = mdesc_grab();
+ vp = vnet_find_parent(hp, vdev->mp);
+ if (IS_ERR(vp)) {
+ printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+ err = PTR_ERR(vp);
+ goto err_out_put_mdesc;
+ }
+
rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
err = -ENODEV;
if (!rmac) {
@@ -1025,139 +1148,14 @@
}
};
-const char *local_mac_prop = "local-mac-address";
-
-static int __devinit vnet_probe(struct vio_dev *vdev,
- const struct vio_device_id *id)
-{
- static int vnet_version_printed;
- struct mdesc_handle *hp;
- struct net_device *dev;
- struct vnet *vp;
- const u64 *mac;
- int err, i, len;
-
- if (vnet_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- hp = mdesc_grab();
-
- mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
- if (!mac) {
- printk(KERN_ERR PFX "vnet lacks %s property.\n",
- local_mac_prop);
- err = -ENODEV;
- goto err_out;
- }
-
- dev = alloc_etherdev(sizeof(*vp));
- if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
- err = -ENOMEM;
- goto err_out;
- }
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
-
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
- SET_NETDEV_DEV(dev, &vdev->dev);
-
- vp = netdev_priv(dev);
-
- spin_lock_init(&vp->lock);
- vp->dev = dev;
- vp->vdev = vdev;
-
- INIT_LIST_HEAD(&vp->port_list);
- for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&vp->port_hash[i]);
-
- dev->open = vnet_open;
- dev->stop = vnet_close;
- dev->set_multicast_list = vnet_set_rx_mode;
- dev->set_mac_address = vnet_set_mac_addr;
- dev->tx_timeout = vnet_tx_timeout;
- dev->ethtool_ops = &vnet_ethtool_ops;
- dev->watchdog_timeo = VNET_TX_TIMEOUT;
- dev->change_mtu = vnet_change_mtu;
- dev->hard_start_xmit = vnet_start_xmit;
-
- err = register_netdev(dev);
- if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
- goto err_out_free_dev;
- }
-
- printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
- dev_set_drvdata(&vdev->dev, vp);
-
- mdesc_release(hp);
-
- return 0;
-
-err_out_free_dev:
- free_netdev(dev);
-
-err_out:
- mdesc_release(hp);
- return err;
-}
-
-static int vnet_remove(struct vio_dev *vdev)
-{
-
- struct vnet *vp = dev_get_drvdata(&vdev->dev);
-
- if (vp) {
- /* XXX unregister port, or at least check XXX */
- unregister_netdevice(vp->dev);
- dev_set_drvdata(&vdev->dev, NULL);
- }
- return 0;
-}
-
-static struct vio_device_id vnet_match[] = {
- {
- .type = "network",
- },
- {},
-};
-MODULE_DEVICE_TABLE(vio, vnet_match);
-
-static struct vio_driver vnet_driver = {
- .id_table = vnet_match,
- .probe = vnet_probe,
- .remove = vnet_remove,
- .driver = {
- .name = "vnet",
- .owner = THIS_MODULE,
- }
-};
-
static int __init vnet_init(void)
{
- int err = vio_register_driver(&vnet_driver);
-
- if (!err) {
- err = vio_register_driver(&vnet_port_driver);
- if (err)
- vio_unregister_driver(&vnet_driver);
- }
-
- return err;
+ return vio_register_driver(&vnet_port_driver);
}
static void __exit vnet_exit(void)
{
vio_unregister_driver(&vnet_port_driver);
- vio_unregister_driver(&vnet_driver);
}
module_init(vnet_init);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 1c88730..7d3a0ca 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -60,11 +60,13 @@
struct net_device *dev;
u32 msg_enable;
- struct vio_dev *vdev;
struct list_head port_list;
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
+
+ struct list_head list;
+ u64 local_mac;
};
#endif /* _SUNVNET_H */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644
index 0000000..489f69c
--- /dev/null
+++ b/drivers/net/xen-netfront.c
@@ -0,0 +1,1863 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+ struct page *page;
+ unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF 0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+ struct list_head list;
+ struct net_device *netdev;
+
+ struct net_device_stats stats;
+
+ struct xen_netif_tx_front_ring tx;
+ struct xen_netif_rx_front_ring rx;
+
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+
+ unsigned int evtchn;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+ unsigned rx_min_target, rx_max_target, rx_target;
+ struct sk_buff_head rx_batch;
+
+ struct timer_list rx_refill_timer;
+
+ /*
+ * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+ * are linked from tx_skb_freelist through skb_entry.link.
+ *
+ * NB. Freelist index entries are always going to be less than
+ * PAGE_OFFSET, whereas pointers to skbs will always be equal or
+ * greater than PAGE_OFFSET: we use this property to distinguish
+ * them.
+ */
+ union skb_entry {
+ struct sk_buff *skb;
+ unsigned link;
+ } tx_skbs[NET_TX_RING_SIZE];
+ grant_ref_t gref_tx_head;
+ grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+ unsigned tx_skb_freelist;
+
+ struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+ grant_ref_t gref_rx_head;
+ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+ struct xenbus_device *xbdev;
+ int tx_ring_ref;
+ int rx_ring_ref;
+
+ unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+ struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+ struct xen_netif_rx_response rx;
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+ unsigned short id)
+{
+ list[id].link = *head;
+ *head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+ union skb_entry *list)
+{
+ unsigned int id = *head;
+ *head = list[id].link;
+ return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+ return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ struct sk_buff *skb = np->rx_skbs[i];
+ np->rx_skbs[i] = NULL;
+ return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ grant_ref_t ref = np->grant_rx_ref[i];
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+ return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ netif_rx_schedule(dev);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+ return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+ (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ if (unlikely(netif_queue_stopped(dev)) &&
+ netfront_tx_slot_available(np) &&
+ likely(netif_running(dev)))
+ netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct page *page;
+ int i, batch_target, notify;
+ RING_IDX req_prod = np->rx.req_prod_pvt;
+ struct xen_memory_reservation reservation;
+ grant_ref_t ref;
+ unsigned long pfn;
+ void *vaddr;
+ int nr_flips;
+ struct xen_netif_rx_request *req;
+
+ if (unlikely(!netif_carrier_ok(dev)))
+ return;
+
+ /*
+ * Allocate skbuffs greedily, even though we batch updates to the
+ * receive ring. This creates a less bursty demand on the memory
+ * allocator, so should reduce the chance of failed allocation requests
+ * both for ourself and for other kernel subsystems.
+ */
+ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+ skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!skb))
+ goto no_skb;
+
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+ if (!page) {
+ kfree_skb(skb);
+no_skb:
+ /* Any skbuffs queued for refill? Force them out. */
+ if (i != 0)
+ goto refill;
+ /* Could not allocate any skbuffs. Try again later. */
+ mod_timer(&np->rx_refill_timer,
+ jiffies + (HZ/10));
+ break;
+ }
+
+ skb_shinfo(skb)->frags[0].page = page;
+ skb_shinfo(skb)->nr_frags = 1;
+ __skb_queue_tail(&np->rx_batch, skb);
+ }
+
+ /* Is the batch large enough to be worthwhile? */
+ if (i < (np->rx_target/2)) {
+ if (req_prod > np->rx.sring->req_prod)
+ goto push;
+ return;
+ }
+
+ /* Adjust our fill target if we risked running out of buffers. */
+ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+ ((np->rx_target *= 2) > np->rx_max_target))
+ np->rx_target = np->rx_max_target;
+
+ refill:
+ for (nr_flips = i = 0; ; i++) {
+ skb = __skb_dequeue(&np->rx_batch);
+ if (skb == NULL)
+ break;
+
+ skb->dev = dev;
+
+ id = xennet_rxidx(req_prod + i);
+
+ BUG_ON(np->rx_skbs[id]);
+ np->rx_skbs[id] = skb;
+
+ ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+ BUG_ON((signed short)ref < 0);
+ np->grant_rx_ref[id] = ref;
+
+ pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+ vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+ req = RING_GET_REQUEST(&np->rx, req_prod + i);
+ gnttab_grant_foreign_access_ref(ref,
+ np->xbdev->otherend_id,
+ pfn_to_mfn(pfn),
+ 0);
+
+ req->id = id;
+ req->gref = ref;
+ }
+
+ if (nr_flips != 0) {
+ reservation.extent_start = np->rx_pfn_array;
+ reservation.nr_extents = nr_flips;
+ reservation.extent_order = 0;
+ reservation.address_bits = 0;
+ reservation.domid = DOMID_SELF;
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* After all PTEs have been zapped, flush the TLB. */
+ np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
+ UVMF_TLB_FLUSH|UVMF_ALL;
+
+ /* Give away a batch of pages. */
+ np->rx_mcl[i].op = __HYPERVISOR_memory_op;
+ np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
+ np->rx_mcl[i].args[1] = (unsigned long)&reservation;
+
+ /* Zap PTEs and give away pages in one big
+ * multicall. */
+ (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
+
+ /* Check return status of HYPERVISOR_memory_op(). */
+ if (unlikely(np->rx_mcl[i].result != i))
+ panic("Unable to reduce memory reservation\n");
+ } else {
+ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+ &reservation) != i)
+ panic("Unable to reduce memory reservation\n");
+ }
+ } else {
+ wmb(); /* barrier so backend seens requests */
+ }
+
+ /* Above is a suitable barrier to ensure backend will see requests. */
+ np->rx.req_prod_pvt = req_prod + i;
+ push:
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ memset(&np->stats, 0, sizeof(np->stats));
+
+ spin_lock_bh(&np->rx_lock);
+ if (netif_carrier_ok(dev)) {
+ xennet_alloc_rx_buffers(dev);
+ np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev);
+ }
+ spin_unlock_bh(&np->rx_lock);
+
+ xennet_maybe_wake_tx(dev);
+
+ return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+ RING_IDX cons, prod;
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ BUG_ON(!netif_carrier_ok(dev));
+
+ do {
+ prod = np->tx.sring->rsp_prod;
+ rmb(); /* Ensure we see responses up to 'rp'. */
+
+ for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+ struct xen_netif_tx_response *txrsp;
+
+ txrsp = RING_GET_RESPONSE(&np->tx, cons);
+ if (txrsp->status == NETIF_RSP_NULL)
+ continue;
+
+ id = txrsp->id;
+ skb = np->tx_skbs[id].skb;
+ if (unlikely(gnttab_query_foreign_access(
+ np->grant_tx_ref[id]) != 0)) {
+ printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+ "-- grant still in use by backend "
+ "domain.\n");
+ BUG();
+ }
+ gnttab_end_foreign_access_ref(
+ np->grant_tx_ref[id], GNTMAP_readonly);
+ gnttab_release_grant_reference(
+ &np->gref_tx_head, np->grant_tx_ref[id]);
+ np->grant_tx_ref[id] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+ dev_kfree_skb_irq(skb);
+ }
+
+ np->tx.rsp_cons = prod;
+
+ /*
+ * Set a new event, then check for race with update of tx_cons.
+ * Note that it is essential to schedule a callback, no matter
+ * how few buffers are pending. Even if there is space in the
+ * transmit ring, higher layers may be blocked because too much
+ * data is outstanding: in such cases notification from Xen is
+ * likely to be the only kick that we'll get.
+ */
+ np->tx.sring->rsp_event =
+ prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+ mb(); /* update shared area */
+ } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+ xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+ struct xen_netif_tx_request *tx)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ char *data = skb->data;
+ unsigned long mfn;
+ RING_IDX prod = np->tx.req_prod_pvt;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+ unsigned int id;
+ grant_ref_t ref;
+ int i;
+
+ /* While the header overlaps a page boundary (including being
+ larger than a page), split it it into page-sized chunks. */
+ while (len > PAGE_SIZE - offset) {
+ tx->size = PAGE_SIZE - offset;
+ tx->flags |= NETTXF_more_data;
+ len -= tx->size;
+ data += tx->size;
+ offset = 0;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ tx->flags = 0;
+ }
+
+ /* Grant backend access to each skb fragment page. */
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+ tx->flags |= NETTXF_more_data;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = pfn_to_mfn(page_to_pfn(frag->page));
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = frag->page_offset;
+ tx->size = frag->size;
+ tx->flags = 0;
+ }
+
+ np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct xen_netif_tx_request *tx;
+ struct xen_netif_extra_info *extra;
+ char *data = skb->data;
+ RING_IDX i;
+ grant_ref_t ref;
+ unsigned long mfn;
+ int notify;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+
+ frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+ if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+ printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+ frags);
+ dump_stack();
+ goto drop;
+ }
+
+ spin_lock_irq(&np->tx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev) ||
+ (frags > 1 && !xennet_can_sg(dev)) ||
+ netif_needs_gso(dev, skb))) {
+ spin_unlock_irq(&np->tx_lock);
+ goto drop;
+ }
+
+ i = np->tx.req_prod_pvt;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb;
+
+ tx = RING_GET_REQUEST(&np->tx, i);
+
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ extra = NULL;
+
+ tx->flags = 0;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
+ tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
+ tx->flags |= NETTXF_data_validated;
+
+ if (skb_shinfo(skb)->gso_size) {
+ struct xen_netif_extra_info *gso;
+
+ gso = (struct xen_netif_extra_info *)
+ RING_GET_REQUEST(&np->tx, ++i);
+
+ if (extra)
+ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+ else
+ tx->flags |= NETTXF_extra_info;
+
+ gso->u.gso.size = skb_shinfo(skb)->gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+ gso->u.gso.pad = 0;
+ gso->u.gso.features = 0;
+
+ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+ gso->flags = 0;
+ extra = gso;
+ }
+
+ np->tx.req_prod_pvt = i + 1;
+
+ xennet_make_frags(skb, dev, tx);
+ tx->size = skb->len;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+
+ xennet_tx_buf_gc(dev);
+
+ if (!netfront_tx_slot_available(np))
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+
+ np->stats.tx_bytes += skb->len;
+ np->stats.tx_packets++;
+
+ return 0;
+
+ drop:
+ np->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ netif_stop_queue(np->netdev);
+ return 0;
+}
+
+static struct net_device_stats *xennet_get_stats(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ return &np->stats;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+ grant_ref_t ref)
+{
+ int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+ BUG_ON(np->rx_skbs[new]);
+ np->rx_skbs[new] = skb;
+ np->grant_rx_ref[new] = ref;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+ np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+ struct xen_netif_extra_info *extras,
+ RING_IDX rp)
+
+{
+ struct xen_netif_extra_info *extra;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ int err = 0;
+
+ do {
+ struct sk_buff *skb;
+ grant_ref_t ref;
+
+ if (unlikely(cons + 1 == rp)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Missing extra info\n");
+ err = -EBADR;
+ break;
+ }
+
+ extra = (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ if (unlikely(!extra->type ||
+ extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Invalid extra type: %d\n",
+ extra->type);
+ err = -EINVAL;
+ } else {
+ memcpy(&extras[extra->type - 1], extra,
+ sizeof(*extra));
+ }
+
+ skb = xennet_get_rx_skb(np, cons);
+ ref = xennet_get_rx_ref(np, cons);
+ xennet_move_rx_slot(np, skb, ref);
+ } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+ np->rx.rsp_cons = cons;
+ return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+ struct netfront_rx_info *rinfo, RING_IDX rp,
+ struct sk_buff_head *list)
+{
+ struct xen_netif_rx_response *rx = &rinfo->rx;
+ struct xen_netif_extra_info *extras = rinfo->extras;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+ grant_ref_t ref = xennet_get_rx_ref(np, cons);
+ int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+ int frags = 1;
+ int err = 0;
+ unsigned long ret;
+
+ if (rx->flags & NETRXF_extra_info) {
+ err = xennet_get_extras(np, extras, rp);
+ cons = np->rx.rsp_cons;
+ }
+
+ for (;;) {
+ if (unlikely(rx->status < 0 ||
+ rx->offset + rx->status > PAGE_SIZE)) {
+ if (net_ratelimit())
+ dev_warn(dev, "rx->offset: %x, size: %u\n",
+ rx->offset, rx->status);
+ xennet_move_rx_slot(np, skb, ref);
+ err = -EINVAL;
+ goto next;
+ }
+
+ /*
+ * This definitely indicates a bug, either in this driver or in
+ * the backend driver. In future this should flag the bad
+ * situation to the system controller to reboot the backed.
+ */
+ if (ref == GRANT_INVALID_REF) {
+ if (net_ratelimit())
+ dev_warn(dev, "Bad rx response id %d.\n",
+ rx->id);
+ err = -EINVAL;
+ goto next;
+ }
+
+ ret = gnttab_end_foreign_access_ref(ref, 0);
+ BUG_ON(!ret);
+
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+ __skb_queue_tail(list, skb);
+
+next:
+ if (!(rx->flags & NETRXF_more_data))
+ break;
+
+ if (cons + frags == rp) {
+ if (net_ratelimit())
+ dev_warn(dev, "Need more frags\n");
+ err = -ENOENT;
+ break;
+ }
+
+ rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+ skb = xennet_get_rx_skb(np, cons + frags);
+ ref = xennet_get_rx_ref(np, cons + frags);
+ frags++;
+ }
+
+ if (unlikely(frags > max)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Too many frags\n");
+ err = -E2BIG;
+ }
+
+ if (unlikely(err))
+ np->rx.rsp_cons = cons + frags;
+
+ return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+ struct xen_netif_extra_info *gso)
+{
+ if (!gso->u.gso.size) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "GSO size must not be zero.\n");
+ return -EINVAL;
+ }
+
+ /* Currently only TCPv4 S.O. is supported. */
+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+ return -EINVAL;
+ }
+
+ skb_shinfo(skb)->gso_size = gso->u.gso.size;
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+ /* Header must be checked, and gso_segs computed. */
+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+ skb_shinfo(skb)->gso_segs = 0;
+
+ return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+ struct sk_buff *skb,
+ struct sk_buff_head *list)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int nr_frags = shinfo->nr_frags;
+ RING_IDX cons = np->rx.rsp_cons;
+ skb_frag_t *frag = shinfo->frags + nr_frags;
+ struct sk_buff *nskb;
+
+ while ((nskb = __skb_dequeue(list))) {
+ struct xen_netif_rx_response *rx =
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ frag->page = skb_shinfo(nskb)->frags[0].page;
+ frag->page_offset = rx->offset;
+ frag->size = rx->status;
+
+ skb->data_len += rx->status;
+
+ skb_shinfo(nskb)->nr_frags = 0;
+ kfree_skb(nskb);
+
+ frag++;
+ nr_frags++;
+ }
+
+ shinfo->nr_frags = nr_frags;
+ return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+
+ iph = (void *)skb->data;
+ th = skb->data + 4 * iph->ihl;
+ if (th >= skb_tail_pointer(skb))
+ goto out;
+
+ skb->csum_start = th - skb->head;
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_ERR "Attempting to checksum a non-"
+ "TCP/UDP packet, dropping a protocol"
+ " %d packet", iph->protocol);
+ goto out;
+ }
+
+ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+ goto out;
+
+ err = 0;
+
+out:
+ return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+ struct sk_buff_head *rxq)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int packets_dropped = 0;
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(rxq)) != NULL) {
+ struct page *page = NETFRONT_SKB_CB(skb)->page;
+ void *vaddr = page_address(page);
+ unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+ memcpy(skb->data, vaddr + offset,
+ skb_headlen(skb));
+
+ if (page != skb_shinfo(skb)->frags[0].page)
+ __free_page(page);
+
+ /* Ethernet work: Delayed to here as it peeks the header. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_setup(skb)) {
+ kfree_skb(skb);
+ packets_dropped++;
+ np->stats.rx_errors++;
+ continue;
+ }
+ }
+
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += skb->len;
+
+ /* Pass it up. */
+ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ }
+
+ return packets_dropped;
+}
+
+static int xennet_poll(struct net_device *dev, int *pbudget)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct netfront_rx_info rinfo;
+ struct xen_netif_rx_response *rx = &rinfo.rx;
+ struct xen_netif_extra_info *extras = rinfo.extras;
+ RING_IDX i, rp;
+ int work_done, budget, more_to_do = 1;
+ struct sk_buff_head rxq;
+ struct sk_buff_head errq;
+ struct sk_buff_head tmpq;
+ unsigned long flags;
+ unsigned int len;
+ int err;
+
+ spin_lock(&np->rx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ spin_unlock(&np->rx_lock);
+ return 0;
+ }
+
+ skb_queue_head_init(&rxq);
+ skb_queue_head_init(&errq);
+ skb_queue_head_init(&tmpq);
+
+ budget = *pbudget;
+ if (budget > dev->quota)
+ budget = dev->quota;
+ rp = np->rx.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ i = np->rx.rsp_cons;
+ work_done = 0;
+ while ((i != rp) && (work_done < budget)) {
+ memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+ memset(extras, 0, sizeof(rinfo.extras));
+
+ err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+ if (unlikely(err)) {
+err:
+ while ((skb = __skb_dequeue(&tmpq)))
+ __skb_queue_tail(&errq, skb);
+ np->stats.rx_errors++;
+ i = np->rx.rsp_cons;
+ continue;
+ }
+
+ skb = __skb_dequeue(&tmpq);
+
+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+ struct xen_netif_extra_info *gso;
+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+ if (unlikely(xennet_set_skb_gso(skb, gso))) {
+ __skb_queue_head(&tmpq, skb);
+ np->rx.rsp_cons += skb_queue_len(&tmpq);
+ goto err;
+ }
+ }
+
+ NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+ NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+ len = rx->status;
+ if (len > RX_COPY_THRESHOLD)
+ len = RX_COPY_THRESHOLD;
+ skb_put(skb, len);
+
+ if (rx->status > len) {
+ skb_shinfo(skb)->frags[0].page_offset =
+ rx->offset + len;
+ skb_shinfo(skb)->frags[0].size = rx->status - len;
+ skb->data_len = rx->status - len;
+ } else {
+ skb_shinfo(skb)->frags[0].page = NULL;
+ skb_shinfo(skb)->nr_frags = 0;
+ }
+
+ i = xennet_fill_frags(np, skb, &tmpq);
+
+ /*
+ * Truesize approximates the size of true data plus
+ * any supervisor overheads. Adding hypervisor
+ * overheads has been shown to significantly reduce
+ * achievable bandwidth with the default receive
+ * buffer size. It is therefore not wise to account
+ * for it here.
+ *
+ * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+ * to RX_COPY_THRESHOLD + the supervisor
+ * overheads. Here, we add the size of the data pulled
+ * in xennet_fill_frags().
+ *
+ * We also adjust for any unused space in the main
+ * data area by subtracting (RX_COPY_THRESHOLD -
+ * len). This is especially important with drivers
+ * which split incoming packets into header and data,
+ * using only 66 bytes of the main data area (see the
+ * e1000 driver for example.) On such systems,
+ * without this last adjustement, our achievable
+ * receive throughout using the standard receive
+ * buffer size was cut by 25%(!!!).
+ */
+ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+ skb->len += skb->data_len;
+
+ if (rx->flags & NETRXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ else if (rx->flags & NETRXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ __skb_queue_tail(&rxq, skb);
+
+ np->rx.rsp_cons = ++i;
+ work_done++;
+ }
+
+ while ((skb = __skb_dequeue(&errq)))
+ kfree_skb(skb);
+
+ work_done -= handle_incoming_queue(dev, &rxq);
+
+ /* If we get a callback with very few responses, reduce fill target. */
+ /* NB. Note exponential increase, linear decrease. */
+ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+ ((3*np->rx_target) / 4)) &&
+ (--np->rx_target < np->rx_min_target))
+ np->rx_target = np->rx_min_target;
+
+ xennet_alloc_rx_buffers(dev);
+
+ *pbudget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done < budget) {
+ local_irq_save(flags);
+
+ RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+ if (!more_to_do)
+ __netif_rx_complete(dev);
+
+ local_irq_restore(flags);
+ }
+
+ spin_unlock(&np->rx_lock);
+
+ return more_to_do;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+ int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+ if (mtu > max)
+ return -EINVAL;
+ dev->mtu = mtu;
+ return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ /* Skip over entries which are actually freelist references */
+ if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+ continue;
+
+ skb = np->tx_skbs[i].skb;
+ gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+ GNTMAP_readonly);
+ gnttab_release_grant_reference(&np->gref_tx_head,
+ np->grant_tx_ref[i]);
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+ struct mmu_update *mmu = np->rx_mmu;
+ struct multicall_entry *mcl = np->rx_mcl;
+ struct sk_buff_head free_list;
+ struct sk_buff *skb;
+ unsigned long mfn;
+ int xfer = 0, noxfer = 0, unused = 0;
+ int id, ref;
+
+ dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+ __func__);
+ return;
+
+ skb_queue_head_init(&free_list);
+
+ spin_lock_bh(&np->rx_lock);
+
+ for (id = 0; id < NET_RX_RING_SIZE; id++) {
+ ref = np->grant_rx_ref[id];
+ if (ref == GRANT_INVALID_REF) {
+ unused++;
+ continue;
+ }
+
+ skb = np->rx_skbs[id];
+ mfn = gnttab_end_foreign_transfer_ref(ref);
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+ np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+ if (0 == mfn) {
+ skb_shinfo(skb)->nr_frags = 0;
+ dev_kfree_skb(skb);
+ noxfer++;
+ continue;
+ }
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Remap the page. */
+ struct page *page = skb_shinfo(skb)->frags[0].page;
+ unsigned long pfn = page_to_pfn(page);
+ void *vaddr = page_address(page);
+
+ MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+ mfn_pte(mfn, PAGE_KERNEL),
+ 0);
+ mcl++;
+ mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+ | MMU_MACHPHYS_UPDATE;
+ mmu->val = pfn;
+ mmu++;
+
+ set_phys_to_machine(pfn, mfn);
+ }
+ __skb_queue_tail(&free_list, skb);
+ xfer++;
+ }
+
+ dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+ __func__, xfer, noxfer, unused);
+
+ if (xfer) {
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Do all the remapping work and M2P updates. */
+ MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+ 0, DOMID_SELF);
+ mcl++;
+ HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+ }
+ }
+
+ while ((skb = __skb_dequeue(&free_list)) != NULL)
+ dev_kfree_skb(skb);
+
+ spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ xennet_release_tx_bufs(np);
+ xennet_release_rx_bufs(np);
+ gnttab_free_grant_references(np->gref_tx_head);
+ gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+ int i, err;
+ struct net_device *netdev;
+ struct netfront_info *np;
+
+ netdev = alloc_etherdev(sizeof(struct netfront_info));
+ if (!netdev) {
+ printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ np = netdev_priv(netdev);
+ np->xbdev = dev;
+
+ spin_lock_init(&np->tx_lock);
+ spin_lock_init(&np->rx_lock);
+
+ skb_queue_head_init(&np->rx_batch);
+ np->rx_target = RX_DFL_MIN_TARGET;
+ np->rx_min_target = RX_DFL_MIN_TARGET;
+ np->rx_max_target = RX_MAX_TARGET;
+
+ init_timer(&np->rx_refill_timer);
+ np->rx_refill_timer.data = (unsigned long)netdev;
+ np->rx_refill_timer.function = rx_refill_timeout;
+
+ /* Initialise tx_skbs as a free chain containing every entry. */
+ np->tx_skb_freelist = 0;
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ np->tx_skbs[i].link = i+1;
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* Clear out rx_skbs */
+ for (i = 0; i < NET_RX_RING_SIZE; i++) {
+ np->rx_skbs[i] = NULL;
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* A grant for every tx ring slot */
+ if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+ &np->gref_tx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ /* A grant for every rx ring slot */
+ if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+ &np->gref_rx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+ err = -ENOMEM;
+ goto exit_free_tx;
+ }
+
+ netdev->open = xennet_open;
+ netdev->hard_start_xmit = xennet_start_xmit;
+ netdev->stop = xennet_close;
+ netdev->get_stats = xennet_get_stats;
+ netdev->poll = xennet_poll;
+ netdev->uninit = xennet_uninit;
+ netdev->change_mtu = xennet_change_mtu;
+ netdev->weight = 64;
+ netdev->features = NETIF_F_IP_CSUM;
+
+ SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &dev->dev);
+
+ np->netdev = netdev;
+
+ netif_carrier_off(netdev);
+
+ return netdev;
+
+ exit_free_tx:
+ gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+ free_netdev(netdev);
+ return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ struct net_device *netdev;
+ struct netfront_info *info;
+
+ netdev = xennet_create_dev(dev);
+ if (IS_ERR(netdev)) {
+ err = PTR_ERR(netdev);
+ xenbus_dev_fatal(dev, err, "creating netdev");
+ return err;
+ }
+
+ info = netdev_priv(netdev);
+ dev->dev.driver_data = info;
+
+ err = register_netdev(info->netdev);
+ if (err) {
+ printk(KERN_WARNING "%s: register_netdev err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ err = xennet_sysfs_addif(info->netdev);
+ if (err) {
+ unregister_netdev(info->netdev);
+ printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ free_netdev(netdev);
+ dev->dev.driver_data = NULL;
+ return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+ /* This frees the page as a side-effect */
+ if (ref != GRANT_INVALID_REF)
+ gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+ /* Stop old i/f to prevent errors whilst we rebuild the state. */
+ spin_lock_bh(&info->rx_lock);
+ spin_lock_irq(&info->tx_lock);
+ netif_carrier_off(info->netdev);
+ spin_unlock_irq(&info->tx_lock);
+ spin_unlock_bh(&info->rx_lock);
+
+ if (info->netdev->irq)
+ unbind_from_irqhandler(info->netdev->irq, info->netdev);
+ info->evtchn = info->netdev->irq = 0;
+
+ /* End access and free the pages */
+ xennet_end_access(info->tx_ring_ref, info->tx.sring);
+ xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->tx.sring = NULL;
+ info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ xennet_disconnect_backend(info);
+ return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+ char *s, *e, *macstr;
+ int i;
+
+ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+ if (IS_ERR(macstr))
+ return PTR_ERR(macstr);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac[i] = simple_strtoul(s, &e, 16);
+ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+ kfree(macstr);
+ return -ENOENT;
+ }
+ s = e+1;
+ }
+
+ kfree(macstr);
+ return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct netfront_info *np = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&np->tx_lock, flags);
+
+ if (likely(netif_carrier_ok(dev))) {
+ xennet_tx_buf_gc(dev);
+ /* Under tx_lock: protects access to rx shared-ring indexes. */
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+ struct xen_netif_tx_sring *txs;
+ struct xen_netif_rx_sring *rxs;
+ int err;
+ struct net_device *netdev = info->netdev;
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->rx.sring = NULL;
+ info->tx.sring = NULL;
+ netdev->irq = 0;
+
+ err = xen_net_read_mac(dev, netdev->dev_addr);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+ goto fail;
+ }
+
+ txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!txs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating tx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(txs);
+ FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+ if (err < 0) {
+ free_page((unsigned long)txs);
+ goto fail;
+ }
+
+ info->tx_ring_ref = err;
+ rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!rxs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating rx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(rxs);
+ FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+ if (err < 0) {
+ free_page((unsigned long)rxs);
+ goto fail;
+ }
+ info->rx_ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+ IRQF_SAMPLE_RANDOM, netdev->name,
+ netdev);
+ if (err < 0)
+ goto fail;
+ netdev->irq = err;
+ return 0;
+
+ fail:
+ return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct netfront_info *info)
+{
+ const char *message;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_netfront(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_ring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+ info->tx_ring_ref);
+ if (err) {
+ message = "writing tx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+ info->rx_ring_ref);
+ if (err) {
+ message = "writing rx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+ 1);
+ if (err) {
+ message = "writing request-rx-copy";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+ if (err) {
+ message = "writing feature-rx-notify";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+ if (err) {
+ message = "writing feature-sg";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+ if (err) {
+ message = "writing feature-gso-tcpv4";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_ring;
+ }
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+ xennet_disconnect_backend(info);
+ out:
+ return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+ "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ } else if (dev->mtu > ETH_DATA_LEN)
+ dev->mtu = ETH_DATA_LEN;
+
+ return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-gso-tcpv4", "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ }
+
+ return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+ /* Turn off all GSO bits except ROBUST. */
+ dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+ dev->features |= NETIF_F_GSO_ROBUST;
+ xennet_set_sg(dev, 0);
+
+ /* We need checksum offload to enable scatter/gather and TSO. */
+ if (!(dev->features & NETIF_F_IP_CSUM))
+ return;
+
+ if (!xennet_set_sg(dev, 1))
+ xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int i, requeue_idx, err;
+ struct sk_buff *skb;
+ grant_ref_t ref;
+ struct xen_netif_rx_request *req;
+ unsigned int feature_rx_copy;
+
+ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-rx-copy", "%u", &feature_rx_copy);
+ if (err != 1)
+ feature_rx_copy = 0;
+
+ if (!feature_rx_copy) {
+ dev_info(&dev->dev,
+ "backend does not support copying recieve path");
+ return -ENODEV;
+ }
+
+ err = talk_to_backend(np->xbdev, np);
+ if (err)
+ return err;
+
+ xennet_set_features(dev);
+
+ spin_lock_bh(&np->rx_lock);
+ spin_lock_irq(&np->tx_lock);
+
+ /* Step 1: Discard all pending TX packet fragments. */
+ xennet_release_tx_bufs(np);
+
+ /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+ if (!np->rx_skbs[i])
+ continue;
+
+ skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+ ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+ req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id,
+ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+ frags->page)),
+ 0);
+ req->gref = ref;
+ req->id = requeue_idx;
+
+ requeue_idx++;
+ }
+
+ np->rx.req_prod_pvt = requeue_idx;
+
+ /*
+ * Step 3: All public and private state should now be sane. Get
+ * ready to start sending and receiving packets and give the driver
+ * domain a kick because we've probably just requeued some
+ * packets.
+ */
+ netif_carrier_on(np->netdev);
+ notify_remote_via_irq(np->netdev->irq);
+ xennet_tx_buf_gc(dev);
+ xennet_alloc_rx_buffers(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+ spin_unlock_bh(&np->rx_lock);
+
+ return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct netfront_info *np = dev->dev.driver_data;
+ struct net_device *netdev = np->netdev;
+
+ dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitWait:
+ if (dev->state != XenbusStateInitialising)
+ break;
+ if (xennet_connect(netdev) != 0)
+ break;
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(dev);
+ break;
+ }
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = xennet_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = xennet_set_tso,
+ .get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target > np->rx_max_target)
+ np->rx_max_target = target;
+ np->rx_min_target = target;
+ if (target > np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target < np->rx_min_target)
+ np->rx_min_target = target;
+ np->rx_max_target = target;
+ if (target < np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+ err = device_create_file(&netdev->dev,
+ &xennet_attrs[i]);
+ if (err)
+ goto fail;
+ }
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+ return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+ { "vif" },
+ { "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ unregister_netdev(info->netdev);
+
+ xennet_disconnect_backend(info);
+
+ del_timer_sync(&info->rx_refill_timer);
+
+ xennet_sysfs_delif(info->netdev);
+
+ free_netdev(info->netdev);
+
+ return 0;
+}
+
+static struct xenbus_driver netfront = {
+ .name = "vif",
+ .owner = THIS_MODULE,
+ .ids = netfront_ids,
+ .probe = netfront_probe,
+ .remove = __devexit_p(xennet_remove),
+ .resume = netfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (is_initial_xendomain())
+ return 0;
+
+ printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+ return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+ if (is_initial_xendomain())
+ return;
+
+ return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 03baf1c..ed112ee 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -147,7 +147,7 @@
info->location_id, info->serial, info->capabilities);
envp[i] = NULL;
- value = call_usermodehelper (argv [0], argv, envp, 0);
+ value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC);
kfree (buf);
kfree (envp);
return 0;
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index a54e414..e821a15 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -7,6 +7,7 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/oplib.h>
#include <asm/ebus.h>
@@ -170,8 +171,6 @@
static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
{
static int shutting_down = 0;
- static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
char *type = "???";
s8 val = -1;
@@ -195,7 +194,7 @@
printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
shutting_down = 1;
- if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+ if (orderly_poweroff(true) < 0)
printk(KERN_CRIT "envctrl: shutdown execution failed\n");
}
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 8328aca..dadabef 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/ebus.h>
#include <asm/uaccess.h>
@@ -966,10 +967,6 @@
static void envctrl_do_shutdown(void)
{
static int inprog = 0;
- static char *envp[] = {
- "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = {
- "/sbin/shutdown", "-h", "now", NULL };
int ret;
if (inprog != 0)
@@ -977,7 +974,7 @@
inprog = 1;
printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
- ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+ ret = orderly_poweroff(true);
if (ret < 0) {
printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n");
inprog = 0; /* unlikely to succeed, but we could try again */
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644
index 0000000..56592f0
--- /dev/null
+++ b/drivers/xen/Makefile
@@ -0,0 +1,2 @@
+obj-y += grant-table.o
+obj-y += xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644
index 0000000..ea94dba
--- /dev/null
+++ b/drivers/xen/grant-table.c
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+ return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+ unsigned long flags;
+ int ref, rc;
+ grant_ref_t head;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+
+ if ((gnttab_free_count < count) &&
+ ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+ return rc;
+ }
+
+ ref = head = gnttab_free_head;
+ gnttab_free_count -= count;
+ while (count-- > 1)
+ head = gnttab_entry(head);
+ gnttab_free_head = gnttab_entry(head);
+ gnttab_entry(head) = GNTTAB_LIST_END;
+
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+ return ref;
+}
+
+static void do_free_callbacks(void)
+{
+ struct gnttab_free_callback *callback, *next;
+
+ callback = gnttab_free_callback_list;
+ gnttab_free_callback_list = NULL;
+
+ while (callback != NULL) {
+ next = callback->next;
+ if (gnttab_free_count >= callback->count) {
+ callback->next = NULL;
+ callback->fn(callback->arg);
+ } else {
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ }
+ callback = next;
+ }
+}
+
+static inline void check_free_callbacks(void)
+{
+ if (unlikely(gnttab_free_callback_list))
+ do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = ref;
+ gnttab_free_count++;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+ unsigned long frame, unsigned flags)
+{
+ /*
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ */
+ shared[ref].frame = frame;
+ shared[ref].domid = domid;
+ wmb();
+ shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly)
+{
+ update_grant_entry(ref, domid, frame,
+ GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+
+ gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+ u16 nflags;
+
+ nflags = shared[ref].flags;
+
+ return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+ u16 flags, nflags;
+
+ nflags = shared[ref].flags;
+ do {
+ flags = nflags;
+ if (flags & (GTF_reading|GTF_writing)) {
+ printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+ return 0;
+ }
+ } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+ unsigned long page)
+{
+ if (gnttab_end_foreign_access_ref(ref, readonly)) {
+ put_free_entry(ref);
+ if (page != 0)
+ free_page(page);
+ } else {
+ /* XXX This needs to be fixed so that the ref and page are
+ placed on a list to be freed up later. */
+ printk(KERN_WARNING
+ "WARNING: leaking g.e. and page still in use!\n");
+ }
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+ gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+ unsigned long pfn)
+{
+ update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+ unsigned long frame;
+ u16 flags;
+
+ /*
+ * If a transfer is not even yet started, try to reclaim the grant
+ * reference and return failure (== 0).
+ */
+ while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+ if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+ return 0;
+ cpu_relax();
+ }
+
+ /* If a transfer is in progress then wait until it is completed. */
+ while (!(flags & GTF_transfer_completed)) {
+ flags = shared[ref].flags;
+ cpu_relax();
+ }
+
+ rmb(); /* Read the frame number /after/ reading completion status. */
+ frame = shared[ref].frame;
+ BUG_ON(frame == 0);
+
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+ unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+ put_free_entry(ref);
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+ put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+ grant_ref_t ref;
+ unsigned long flags;
+ int count = 1;
+ if (head == GNTTAB_LIST_END)
+ return;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ ref = head;
+ while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+ ref = gnttab_entry(ref);
+ count++;
+ }
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = head;
+ gnttab_free_count += count;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+ int h = get_free_entries(count);
+
+ if (h < 0)
+ return -ENOSPC;
+
+ *head = h;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+ return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+ grant_ref_t g = *private_head;
+ if (unlikely(g == GNTTAB_LIST_END))
+ return -ENOSPC;
+ *private_head = gnttab_entry(g);
+ return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release)
+{
+ gnttab_entry(release) = *private_head;
+ *private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ if (callback->next)
+ goto out;
+ callback->fn = fn;
+ callback->arg = arg;
+ callback->count = count;
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ check_free_callbacks();
+out:
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+ struct gnttab_free_callback **pcb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+ if (*pcb == callback) {
+ *pcb = callback->next;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+ unsigned int new_nr_grant_frames, extra_entries, i;
+
+ new_nr_grant_frames = nr_grant_frames + more_frames;
+ extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+ if (!gnttab_list[i])
+ goto grow_nomem;
+ }
+
+
+ for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(i) = gnttab_free_head;
+ gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ gnttab_free_count += extra_entries;
+
+ nr_grant_frames = new_nr_grant_frames;
+
+ check_free_callbacks();
+
+ return 0;
+
+grow_nomem:
+ for ( ; i >= nr_grant_frames; i--)
+ free_page((unsigned long) gnttab_list[i]);
+ return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+ struct gnttab_query_size query;
+ int rc;
+
+ query.dom = DOMID_SELF;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+ if ((rc < 0) || (query.status != GNTST_okay))
+ return 4; /* Legacy max supported number of frames */
+
+ return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+ unsigned int xen_max = __max_nr_grant_frames();
+
+ if (xen_max > boot_max_nr_grant_frames)
+ return boot_max_nr_grant_frames;
+ return xen_max;
+}
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+ unsigned long **frames = (unsigned long **)data;
+
+ set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+ (*frames)++;
+ return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+
+ set_pte_at(&init_mm, addr, pte, __pte(0));
+ return 0;
+}
+
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
+ struct gnttab_setup_table setup;
+ unsigned long *frames;
+ unsigned int nr_gframes = end_idx + 1;
+ int rc;
+
+ frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+ if (!frames)
+ return -ENOMEM;
+
+ setup.dom = DOMID_SELF;
+ setup.nr_frames = nr_gframes;
+ setup.frame_list = frames;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+ if (rc == -ENOSYS) {
+ kfree(frames);
+ return -ENOSYS;
+ }
+
+ BUG_ON(rc || setup.status);
+
+ if (shared == NULL) {
+ struct vm_struct *area;
+ area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
+ BUG_ON(area == NULL);
+ shared = area->addr;
+ }
+ rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_gframes,
+ map_pte_fn, &frames);
+ BUG_ON(rc);
+ frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+ kfree(frames);
+
+ return 0;
+}
+
+static int gnttab_resume(void)
+{
+ if (max_nr_grant_frames() < nr_grant_frames)
+ return -ENOSYS;
+ return gnttab_map(0, nr_grant_frames - 1);
+}
+
+static int gnttab_suspend(void)
+{
+ apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_grant_frames,
+ unmap_pte_fn, NULL);
+
+ return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+ int rc;
+ unsigned int cur, extra;
+
+ cur = nr_grant_frames;
+ extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+ GREFS_PER_GRANT_FRAME);
+ if (cur + extra > max_nr_grant_frames())
+ return -ENOSPC;
+
+ rc = gnttab_map(cur, cur + extra - 1);
+ if (rc == 0)
+ rc = grow_gnttab_list(extra);
+
+ return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+ int i;
+ unsigned int max_nr_glist_frames;
+ unsigned int nr_init_grefs;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ nr_grant_frames = 1;
+ boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+ /* Determine the maximum number of frames required for the
+ * grant reference free list on the current hypervisor.
+ */
+ max_nr_glist_frames = (boot_max_nr_grant_frames *
+ GREFS_PER_GRANT_FRAME /
+ (PAGE_SIZE / sizeof(grant_ref_t)));
+
+ gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+ GFP_KERNEL);
+ if (gnttab_list == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+ if (gnttab_list[i] == NULL)
+ goto ini_nomem;
+ }
+
+ if (gnttab_resume() < 0)
+ return -ENODEV;
+
+ nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+ gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+ gnttab_free_head = NR_RESERVED_ENTRIES;
+
+ printk("Grant table initialized\n");
+ return 0;
+
+ ini_nomem:
+ for (i--; i >= 0; i--)
+ free_page((unsigned long)gnttab_list[i]);
+ kfree(gnttab_list);
+ return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644
index 0000000..5571f5b
--- /dev/null
+++ b/drivers/xen/xenbus/Makefile
@@ -0,0 +1,7 @@
+obj-y += xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644
index 0000000..9fd2f70
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver. In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+ static const char *const name[] = {
+ [ XenbusStateUnknown ] = "Unknown",
+ [ XenbusStateInitialising ] = "Initialising",
+ [ XenbusStateInitWait ] = "InitWait",
+ [ XenbusStateInitialised ] = "Initialised",
+ [ XenbusStateConnected ] = "Connected",
+ [ XenbusStateClosing ] = "Closing",
+ [ XenbusStateClosed ] = "Closed",
+ };
+ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback. Return 0 on
+ * success, or -errno on error. On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free. On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int))
+{
+ int err;
+
+ watch->node = path;
+ watch->callback = callback;
+
+ err = register_xenbus_watch(watch);
+
+ if (err) {
+ watch->node = NULL;
+ watch->callback = NULL;
+ xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error. On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree(). On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int),
+ const char *pathfmt, ...)
+{
+ int err;
+ va_list ap;
+ char *path;
+
+ va_start(ap, pathfmt);
+ path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+ va_end(ap);
+
+ if (!path) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+ return -ENOMEM;
+ }
+ err = xenbus_watch_path(dev, path, watch, callback);
+
+ if (err)
+ kfree(path);
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error. On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+ /* We check whether the state is currently set to the given value, and
+ if not, then the state is set. We don't want to unconditionally
+ write the given state, because we don't want to fire watches
+ unnecessarily. Furthermore, if the node has gone, we don't write
+ to it, as the device will be tearing down, and we don't want to
+ resurrect that directory.
+
+ Note that, because of this cached value of our state, this function
+ will not work inside a Xenstore transaction (something it was
+ trying to in the past) because dev->state would not get reset if
+ the transaction was aborted.
+
+ */
+
+ int current_state;
+ int err;
+
+ if (state == dev->state)
+ return 0;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+ ¤t_state);
+ if (err != 1)
+ return 0;
+
+ err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+ if (err) {
+ if (state != XenbusStateClosing) /* Avoid looping */
+ xenbus_dev_fatal(dev, err, "writing new state");
+ return err;
+ }
+
+ dev->state = state;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+ xenbus_switch_state(dev, XenbusStateClosed);
+ complete(&dev->down);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+ const char *fmt, va_list ap)
+{
+ int ret;
+ unsigned int len;
+ char *printf_buffer = NULL;
+ char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ goto fail;
+
+ len = sprintf(printf_buffer, "%i ", -err);
+ ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+ BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+ dev_err(&dev->dev, "%s\n", printf_buffer);
+
+ path_buffer = error_path(dev);
+
+ if (path_buffer == NULL) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+ if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+fail:
+ kfree(printf_buffer);
+ kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+
+ xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device. Return
+ * 0 on success, or -errno on error. On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+ int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+ if (err < 0)
+ xenbus_dev_fatal(dev, err, "granting access to ring page");
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port. Return 0 on success, or -errno on error. On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+ struct evtchn_alloc_unbound alloc_unbound;
+ int err;
+
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = dev->otherend_id;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (err)
+ xenbus_dev_fatal(dev, err, "allocating event channel");
+ else
+ *port = alloc_unbound.port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+ struct evtchn_bind_interdomain bind_interdomain;
+ int err;
+
+ bind_interdomain.remote_dom = dev->otherend_id;
+ bind_interdomain.remote_port = remote_port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+ &bind_interdomain);
+ if (err)
+ xenbus_dev_fatal(dev, err,
+ "binding to event channel %d from domain %d",
+ remote_port, dev->otherend_id);
+ else
+ *port = bind_interdomain.local_port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+ struct evtchn_close close;
+ int err;
+
+ close.port = port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+ if (err)
+ xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+ struct vm_struct *area;
+
+ *vaddr = NULL;
+
+ area = alloc_vm_area(PAGE_SIZE);
+ if (!area)
+ return -ENOMEM;
+
+ op.host_addr = (unsigned long)area->addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ free_vm_area(area);
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ return op.status;
+ }
+
+ /* Stuff the handle in an unused field */
+ area->phys_addr = (unsigned long)op.handle;
+
+ *vaddr = area->addr;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+ grant_handle_t *handle, void *vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ } else
+ *handle = op.handle;
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+ struct vm_struct *area;
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ };
+
+ /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+ * method so that we don't have to muck with vmalloc internals here.
+ * We could force the user to hang on to their struct vm_struct from
+ * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+ * this API.
+ */
+ read_lock(&vmlist_lock);
+ for (area = vmlist; area != NULL; area = area->next) {
+ if (area->addr == vaddr)
+ break;
+ }
+ read_unlock(&vmlist_lock);
+
+ if (!area) {
+ xenbus_dev_error(dev, -ENOENT,
+ "can't find mapped virtual address %p", vaddr);
+ return GNTST_bad_virt_addr;
+ }
+
+ op.handle = (grant_handle_t)area->phys_addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status == GNTST_okay)
+ free_vm_area(area);
+ else
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ (int16_t)area->phys_addr, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+ grant_handle_t handle, void *vaddr)
+{
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .handle = handle,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay)
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ handle, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+ enum xenbus_state result;
+ int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+ if (err)
+ result = XenbusStateUnknown;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644
index 0000000..6efbe3f
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+ if (unlikely(xenstored_ready == 0)) {
+ xenstored_ready = 1;
+ schedule_work(&probe_work);
+ }
+
+ wake_up(&xb_waitq);
+ return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+ return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+ if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+ *len = XENSTORE_RING_SIZE - (prod - cons);
+ return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ const char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+ if ((prod - cons) < *len)
+ *len = prod - cons;
+ return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ void *dst;
+ unsigned int avail;
+
+ rc = wait_event_interruptible(
+ xb_waitq,
+ (intf->req_prod - intf->req_cons) !=
+ XENSTORE_RING_SIZE);
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->req_cons;
+ prod = intf->req_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->req_cons = intf->req_prod = 0;
+ return -EIO;
+ }
+
+ dst = get_output_chunk(cons, prod, intf->req, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must write data /after/ reading the consumer index. */
+ mb();
+
+ memcpy(dst, data, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see new producer until data is there. */
+ wmb();
+ intf->req_prod += avail;
+
+ /* Implies mb(): other side will see the updated producer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+int xb_data_to_read(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+ return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ unsigned int avail;
+ const char *src;
+
+ rc = xb_wait_for_data_to_read();
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->rsp_cons;
+ prod = intf->rsp_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->rsp_cons = intf->rsp_prod = 0;
+ return -EIO;
+ }
+
+ src = get_input_chunk(cons, prod, intf->rsp, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must read data /after/ reading the producer index. */
+ rmb();
+
+ memcpy(data, src, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see free space until we've copied out */
+ mb();
+ intf->rsp_cons += avail;
+
+ pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+ /* Implies mb(): other side will see the updated consumer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+int xb_init_comms(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ int err;
+
+ if (intf->req_prod != intf->req_cons)
+ printk(KERN_ERR "XENBUS request ring is not quiescent "
+ "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+ if (intf->rsp_prod != intf->rsp_cons) {
+ printk(KERN_WARNING "XENBUS response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ intf->rsp_cons, intf->rsp_prod);
+ intf->rsp_cons = intf->rsp_prod;
+ }
+
+ if (xenbus_irq)
+ unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+ err = bind_evtchn_to_irqhandler(
+ xen_store_evtchn, wake_waiting,
+ 0, "xenbus", &xb_waitq);
+ if (err <= 0) {
+ printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+ return err;
+ }
+
+ xenbus_irq = err;
+
+ return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644
index 0000000..c21db75
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.h
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644
index 0000000..0b769f7
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define DPRINTK(fmt, args...) \
+ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
+ __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+ for (; *arr->devicetype != '\0'; arr++) {
+ if (!strcmp(arr->devicetype, dev->devicetype))
+ return arr;
+ }
+ return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+ if (!drv->ids)
+ return 0;
+
+ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+ nodename = strchr(nodename, '/');
+ if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+ return -EINVAL;
+ }
+
+ strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+ if (!strchr(bus_id, '/')) {
+ printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+ return -EINVAL;
+ }
+ *strchr(bus_id, '/') = '-';
+ return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+ kfree(dev->otherend);
+ dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+ if (dev->otherend_watch.node) {
+ unregister_xenbus_watch(&dev->otherend_watch);
+ kfree(dev->otherend_watch.node);
+ dev->otherend_watch.node = NULL;
+ }
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+ char *id_node, char *path_node)
+{
+ int err = xenbus_gather(XBT_NIL, xendev->nodename,
+ id_node, "%i", &xendev->otherend_id,
+ path_node, NULL, &xendev->otherend,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(xendev, err,
+ "reading other end details from %s",
+ xendev->nodename);
+ return err;
+ }
+ if (strlen(xendev->otherend) == 0 ||
+ !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+ xenbus_dev_fatal(xendev, -ENOENT,
+ "unable to read other end from %s. "
+ "missing or inaccessible.",
+ xendev->nodename);
+ free_otherend_details(xendev);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+ return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+ .root = "device",
+ .levels = 2, /* device/type/<id> */
+ .get_bus_id = frontend_bus_id,
+ .probe = xenbus_probe_frontend,
+ .bus = {
+ .name = "xen",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ },
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenbus_device *dev =
+ container_of(watch, struct xenbus_device, otherend_watch);
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+ enum xenbus_state state;
+
+ /* Protect us against watches firing on old details when the otherend
+ details change, say immediately after a resume. */
+ if (!dev->otherend ||
+ strncmp(dev->otherend, vec[XS_WATCH_PATH],
+ strlen(dev->otherend))) {
+ dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+ return;
+ }
+
+ state = xenbus_read_driver_state(dev->otherend);
+
+ dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+ state, xenbus_strstate(state), dev->otherend_watch.node,
+ vec[XS_WATCH_PATH]);
+
+ /*
+ * Ignore xenbus transitions during shutdown. This prevents us doing
+ * work that can fail e.g., when the rootfs is gone.
+ */
+ if (system_state > SYSTEM_RUNNING) {
+ struct xen_bus_type *bus = bus;
+ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+ /* If we're frontend, drive the state machine to Closed. */
+ /* This should cause the backend to release our resources. */
+ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+ xenbus_frontend_closed(dev);
+ return;
+ }
+
+ if (drv->otherend_changed)
+ drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+ return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+ "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+ const struct xenbus_device_id *id;
+ int err;
+
+ DPRINTK("%s", dev->nodename);
+
+ if (!drv->probe) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ id = match_device(drv->ids, dev);
+ if (!id) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ err = talk_to_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ err = drv->probe(dev, id);
+ if (err)
+ goto fail;
+
+ err = watch_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ return 0;
+fail:
+ xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+ DPRINTK("%s", dev->nodename);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ if (drv->remove)
+ drv->remove(dev);
+
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ unsigned long timeout = 5*HZ;
+
+ DPRINTK("%s", dev->nodename);
+
+ get_device(&dev->dev);
+ if (dev->state != XenbusStateConnected) {
+ printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+ dev->nodename, xenbus_strstate(dev->state));
+ goto out;
+ }
+ xenbus_switch_state(dev, XenbusStateClosing);
+ timeout = wait_for_completion_timeout(&dev->down, timeout);
+ if (!timeout)
+ printk(KERN_INFO "%s: %s timeout closing device\n",
+ __func__, dev->nodename);
+ out:
+ put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name)
+{
+ drv->driver.name = drv->name;
+ drv->driver.bus = &bus->bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
+
+ return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+ struct module *owner, const char *mod_name)
+{
+ int ret;
+
+ drv->read_otherend_details = read_backend_details;
+
+ ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+ owner, mod_name);
+ if (ret)
+ return ret;
+
+ /* If this driver is loaded as a module wait for devices to attach. */
+ wait_for_devices(drv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+ struct xenbus_device *dev;
+ const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+
+ if (!strcmp(xendev->nodename, info->nodename)) {
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+ }
+ return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+ struct bus_type *bus)
+{
+ struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+ bus_for_each_dev(bus, NULL, &info, cmp_dev);
+ return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+ int len = strlen(info->nodename);
+
+ DPRINTK("%s", info->nodename);
+
+ /* Match the info->nodename path, or any subdirectory of that path. */
+ if (strncmp(xendev->nodename, info->nodename, len))
+ return 0;
+
+ /* If the node name is longer, ensure it really is a subdirectory. */
+ if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+ return 0;
+
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+ struct xb_find_info info = { .nodename = path };
+
+ do {
+ info.dev = NULL;
+ bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+ if (info.dev) {
+ device_unregister(&info.dev->dev);
+ put_device(&info.dev->dev);
+ }
+ } while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+ if (dev)
+ kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename)
+{
+ int err;
+ struct xenbus_device *xendev;
+ size_t stringlen;
+ char *tmpstring;
+
+ enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+ if (state != XenbusStateInitialising) {
+ /* Device is not new, so ignore it. This can happen if a
+ device is going away after switching to Closed. */
+ return 0;
+ }
+
+ stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+ xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+ if (!xendev)
+ return -ENOMEM;
+
+ xendev->state = XenbusStateInitialising;
+
+ /* Copy the strings into the extra space. */
+
+ tmpstring = (char *)(xendev + 1);
+ strcpy(tmpstring, nodename);
+ xendev->nodename = tmpstring;
+
+ tmpstring += strlen(tmpstring) + 1;
+ strcpy(tmpstring, type);
+ xendev->devicetype = tmpstring;
+ init_completion(&xendev->down);
+
+ xendev->dev.bus = &bus->bus;
+ xendev->dev.release = xenbus_dev_release;
+
+ err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+ if (err)
+ goto fail;
+
+ /* Register with generic device framework. */
+ err = device_register(&xendev->dev);
+ if (err)
+ goto fail;
+
+ err = device_create_file(&xendev->dev, &dev_attr_nodename);
+ if (err)
+ goto fail_unregister;
+
+ err = device_create_file(&xendev->dev, &dev_attr_devtype);
+ if (err)
+ goto fail_remove_file;
+
+ return 0;
+fail_remove_file:
+ device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+ device_unregister(&xendev->dev);
+fail:
+ kfree(xendev);
+ return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+ xenbus_frontend.root, type, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s", nodename);
+
+ err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+ int err = 0;
+ char **dir;
+ unsigned int dir_n = 0;
+ int i;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = bus->probe(type, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+ int err = 0;
+ char **dir;
+ unsigned int i, dir_n;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = xenbus_probe_device_type(bus, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+ unsigned int i, ret = 0;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c)
+ ret++;
+ return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c) {
+ if (len == 0)
+ return i;
+ len--;
+ }
+ return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+ int exists, rootlen;
+ struct xenbus_device *dev;
+ char type[BUS_ID_SIZE];
+ const char *p, *root;
+
+ if (char_count(node, '/') < 2)
+ return;
+
+ exists = xenbus_exists(XBT_NIL, node, "");
+ if (!exists) {
+ xenbus_cleanup_devices(node, &bus->bus);
+ return;
+ }
+
+ /* backend/<type>/... or device/<type>/... */
+ p = strchr(node, '/') + 1;
+ snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+ type[BUS_ID_SIZE-1] = '\0';
+
+ rootlen = strsep_len(node, '/', bus->levels);
+ if (rootlen < 0)
+ return;
+ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+ if (!root)
+ return;
+
+ dev = xenbus_device_find(root, &bus->bus);
+ if (!dev)
+ xenbus_probe_node(bus, type, root);
+ else
+ put_device(&dev->dev);
+
+ kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ DPRINTK("");
+
+ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+ .node = "device",
+ .callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend)
+ err = drv->suspend(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+ return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend_cancel)
+ err = drv->suspend_cancel(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend_cancel %s failed: %i\n",
+ dev->bus_id, err);
+ return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+ int err;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+
+ err = talk_to_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+
+ xdev->state = XenbusStateInitialising;
+
+ if (drv->resume) {
+ err = drv->resume(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+ }
+
+ err = watch_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus_probe: resume (watch_otherend) %s failed: "
+ "%d.\n", dev->bus_id, err);
+ return err;
+ }
+
+ return 0;
+}
+
+void xenbus_suspend(void)
+{
+ DPRINTK("");
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+ xenbus_backend_suspend(suspend_dev);
+ xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+ xb_init_comms();
+ xs_resume();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+ xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+ xs_suspend_cancel();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+ xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+ int ret = 0;
+
+ if (xenstored_ready > 0)
+ ret = nb->notifier_call(nb, 0, NULL);
+ else
+ blocking_notifier_chain_register(&xenstore_chain, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+ BUG_ON((xenstored_ready <= 0));
+
+ /* Enumerate devices in xenstore and watch for changes. */
+ xenbus_probe_devices(&xenbus_frontend);
+ register_xenbus_watch(&fe_watch);
+ xenbus_backend_probe_and_watch();
+
+ /* Notify others that xenstore is up */
+ blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+ int err = 0;
+
+ DPRINTK("");
+
+ err = -ENODEV;
+ if (!is_running_on_xen())
+ goto out_error;
+
+ /* Register ourselves with the kernel bus subsystem */
+ err = bus_register(&xenbus_frontend.bus);
+ if (err)
+ goto out_error;
+
+ err = xenbus_backend_bus_register();
+ if (err)
+ goto out_unreg_front;
+
+ /*
+ * Domain0 doesn't have a store_evtchn or store_mfn yet.
+ */
+ if (is_initial_xendomain()) {
+ /* dom0 not yet supported */
+ } else {
+ xenstored_ready = 1;
+ xen_store_evtchn = xen_start_info->store_evtchn;
+ xen_store_mfn = xen_start_info->store_mfn;
+ }
+ xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+ /* Initialize the interface to xenstore. */
+ err = xs_init();
+ if (err) {
+ printk(KERN_WARNING
+ "XENBUS: Error initializing xenstore comms: %i\n", err);
+ goto out_unreg_back;
+ }
+
+ if (!is_initial_xendomain())
+ xenbus_probe(NULL);
+
+ return 0;
+
+ out_unreg_back:
+ xenbus_backend_bus_unregister();
+
+ out_unreg_front:
+ bus_unregister(&xenbus_frontend.bus);
+
+ out_error:
+ return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /*
+ * A device with no driver will never connect. We care only about
+ * devices which should currently be in the process of connecting.
+ */
+ if (!dev->driver)
+ return 0;
+
+ /* Is this search limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /* Is this operation limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ if (!dev->driver) {
+ /* Information only: is this too noisy? */
+ printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+ xendev->nodename);
+ } else if (xendev->state != XenbusStateConnected) {
+ printk(KERN_WARNING "XENBUS: Timeout connecting "
+ "to device: %s (state %d)\n",
+ xendev->nodename, xendev->state);
+ }
+
+ return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured. We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+ unsigned long timeout = jiffies + 10*HZ;
+ struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+ if (!ready_to_wait_for_devices || !is_running_on_xen())
+ return;
+
+ while (exists_disconnected_device(drv)) {
+ if (time_after(jiffies, timeout))
+ break;
+ schedule_timeout_interruptible(HZ/10);
+ }
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+ ready_to_wait_for_devices = 1;
+ wait_for_devices(NULL);
+ return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644
index 0000000..e09b194
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+ char *root;
+ unsigned int levels;
+ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+ int (*probe)(const char *type, const char *dir);
+ struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644
index 0000000..9e943fb
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library. We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+ struct list_head list;
+
+ struct xsd_sockmsg hdr;
+
+ union {
+ /* Queued replies. */
+ struct {
+ char *body;
+ } reply;
+
+ /* Queued watch events. */
+ struct {
+ struct xenbus_watch *handle;
+ char **vec;
+ unsigned int vec_size;
+ } watch;
+ } u;
+};
+
+struct xs_handle {
+ /* A list of replies. Currently only one will ever be outstanding. */
+ struct list_head reply_list;
+ spinlock_t reply_lock;
+ wait_queue_head_t reply_waitq;
+
+ /*
+ * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+ * response_mutex is never taken simultaneously with the other three.
+ */
+
+ /* One request at a time. */
+ struct mutex request_mutex;
+
+ /* Protect xenbus reader thread against save/restore. */
+ struct mutex response_mutex;
+
+ /* Protect transactions against save/restore. */
+ struct rw_semaphore transaction_mutex;
+
+ /* Protect watch (de)register against save/restore. */
+ struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+ unsigned int i;
+
+ for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+ if (i == ARRAY_SIZE(xsd_errors) - 1) {
+ printk(KERN_WARNING
+ "XENBUS xen store gave: unknown error %s",
+ errorstring);
+ return EINVAL;
+ }
+ }
+ return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+
+ spin_lock(&xs_state.reply_lock);
+
+ while (list_empty(&xs_state.reply_list)) {
+ spin_unlock(&xs_state.reply_lock);
+ /* XXX FIXME: Avoid synchronous wait for response here. */
+ wait_event(xs_state.reply_waitq,
+ !list_empty(&xs_state.reply_list));
+ spin_lock(&xs_state.reply_lock);
+ }
+
+ msg = list_entry(xs_state.reply_list.next,
+ struct xs_stored_msg, list);
+ list_del(&msg->list);
+
+ spin_unlock(&xs_state.reply_lock);
+
+ *type = msg->hdr.type;
+ if (len)
+ *len = msg->hdr.len;
+ body = msg->u.reply.body;
+
+ kfree(msg);
+
+ return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+ void *ret;
+ struct xsd_sockmsg req_msg = *msg;
+ int err;
+
+ if (req_msg.type == XS_TRANSACTION_START)
+ down_read(&xs_state.transaction_mutex);
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(msg, sizeof(*msg) + msg->len);
+ if (err) {
+ msg->type = XS_ERROR;
+ ret = ERR_PTR(err);
+ } else
+ ret = read_reply(&msg->type, &msg->len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if ((msg->type == XS_TRANSACTION_END) ||
+ ((req_msg.type == XS_TRANSACTION_START) &&
+ (msg->type == XS_ERROR)))
+ up_read(&xs_state.transaction_mutex);
+
+ return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const struct kvec *iovec,
+ unsigned int num_vecs,
+ unsigned int *len)
+{
+ struct xsd_sockmsg msg;
+ void *ret = NULL;
+ unsigned int i;
+ int err;
+
+ msg.tx_id = t.id;
+ msg.req_id = 0;
+ msg.type = type;
+ msg.len = 0;
+ for (i = 0; i < num_vecs; i++)
+ msg.len += iovec[i].iov_len;
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(&msg, sizeof(msg));
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+
+ for (i = 0; i < num_vecs; i++) {
+ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+ }
+
+ ret = read_reply(&msg.type, len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if (IS_ERR(ret))
+ return ret;
+
+ if (msg.type == XS_ERROR) {
+ err = get_error(ret);
+ kfree(ret);
+ return ERR_PTR(-err);
+ }
+
+ if (msg.type != type) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING
+ "XENBUS unexpected type [%d], expected [%d]\n",
+ msg.type, type);
+ kfree(ret);
+ return ERR_PTR(-EINVAL);
+ }
+ return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const char *string,
+ unsigned int *len)
+{
+ struct kvec iovec;
+
+ iovec.iov_base = (void *)string;
+ iovec.iov_len = strlen(string) + 1;
+ return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+ if (IS_ERR(reply))
+ return PTR_ERR(reply);
+ kfree(reply);
+ return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+ unsigned int num;
+ const char *p;
+
+ for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+ num++;
+
+ return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+ char *buffer;
+
+ if (strlen(name) == 0)
+ buffer = kasprintf(GFP_KERNEL, "%s", dir);
+ else
+ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+ return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+ char *p, **ret;
+
+ /* Count the strings. */
+ *num = count_strings(strings, len);
+
+ /* Transfer to one big alloc for easy freeing. */
+ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+ if (!ret) {
+ kfree(strings);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(&ret[*num], strings, len);
+ kfree(strings);
+
+ strings = (char *)&ret[*num];
+ for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+ ret[(*num)++] = p;
+
+ return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *num)
+{
+ char *strings, *path;
+ unsigned int len;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (char **)path;
+
+ strings = xs_single(t, XS_DIRECTORY, path, &len);
+ kfree(path);
+ if (IS_ERR(strings))
+ return (char **)strings;
+
+ return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char **d;
+ int dir_n;
+
+ d = xenbus_directory(t, dir, node, &dir_n);
+ if (IS_ERR(d))
+ return 0;
+ kfree(d);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *len)
+{
+ char *path;
+ void *ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (void *)path;
+
+ ret = xs_single(t, XS_READ, path, len);
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *string)
+{
+ const char *path;
+ struct kvec iovec[2];
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ iovec[0].iov_base = (void *)path;
+ iovec[0].iov_len = strlen(path) + 1;
+ iovec[1].iov_base = (void *)string;
+ iovec[1].iov_len = strlen(string);
+
+ ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_RM, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+ char *id_str;
+
+ down_read(&xs_state.transaction_mutex);
+
+ id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+ if (IS_ERR(id_str)) {
+ up_read(&xs_state.transaction_mutex);
+ return PTR_ERR(id_str);
+ }
+
+ t->id = simple_strtoul(id_str, NULL, 0);
+ kfree(id_str);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+ char abortstr[2];
+ int err;
+
+ if (abort)
+ strcpy(abortstr, "F");
+ else
+ strcpy(abortstr, "T");
+
+ err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+ up_read(&xs_state.transaction_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *val;
+
+ val = xenbus_read(t, dir, node, NULL);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ va_start(ap, fmt);
+ ret = vsscanf(val, fmt, ap);
+ va_end(ap);
+ kfree(val);
+ /* Distinctive errno. */
+ if (ret == 0)
+ return -ERANGE;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+#define PRINTF_BUFFER_SIZE 4096
+ char *printf_buffer;
+
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ return -ENOMEM;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+ ret = xenbus_write(t, dir, node, printf_buffer);
+
+ kfree(printf_buffer);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+ va_list ap;
+ const char *name;
+ int ret = 0;
+
+ va_start(ap, dir);
+ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+ const char *fmt = va_arg(ap, char *);
+ void *result = va_arg(ap, void *);
+ char *p;
+
+ p = xenbus_read(t, dir, name, NULL);
+ if (IS_ERR(p)) {
+ ret = PTR_ERR(p);
+ break;
+ }
+ if (fmt) {
+ if (sscanf(p, fmt, result) == 0)
+ ret = -EINVAL;
+ kfree(p);
+ } else
+ *(char **)result = p;
+ }
+ va_end(ap);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (void *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (void *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (char *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (char *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+ struct xenbus_watch *i, *cmp;
+
+ cmp = (void *)simple_strtoul(token, NULL, 16);
+
+ list_for_each_entry(i, &watches, list)
+ if (i == cmp)
+ return i;
+
+ return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+ /* Pointer in ascii is the token. */
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(find_watch(token));
+ list_add(&watch->list, &watches);
+ spin_unlock(&watches_lock);
+
+ err = xs_watch(watch->node, token);
+
+ /* Ignore errors due to multiple registration. */
+ if ((err != 0) && (err != -EEXIST)) {
+ spin_lock(&watches_lock);
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+ }
+
+ up_read(&xs_state.watch_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+ struct xs_stored_msg *msg, *tmp;
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(!find_watch(token));
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+
+ err = xs_unwatch(watch->node, token);
+ if (err)
+ printk(KERN_WARNING
+ "XENBUS Failed to release watch %s: %i\n",
+ watch->node, err);
+
+ up_read(&xs_state.watch_mutex);
+
+ /* Make sure there are no callbacks running currently (unless
+ its us) */
+ if (current->pid != xenwatch_pid)
+ mutex_lock(&xenwatch_mutex);
+
+ /* Cancel pending watch events. */
+ spin_lock(&watch_events_lock);
+ list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+ if (msg->u.watch.handle != watch)
+ continue;
+ list_del(&msg->list);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watch_events_lock);
+
+ if (current->pid != xenwatch_pid)
+ mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+ down_write(&xs_state.transaction_mutex);
+ down_write(&xs_state.watch_mutex);
+ mutex_lock(&xs_state.request_mutex);
+ mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+ struct xenbus_watch *watch;
+ char token[sizeof(watch) * 2 + 1];
+
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.transaction_mutex);
+
+ /* No need for watches_lock: the watch_mutex is sufficient. */
+ list_for_each_entry(watch, &watches, list) {
+ sprintf(token, "%lX", (long)watch);
+ xs_watch(watch->node, token);
+ }
+
+ up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.watch_mutex);
+ up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+ struct list_head *ent;
+ struct xs_stored_msg *msg;
+
+ for (;;) {
+ wait_event_interruptible(watch_events_waitq,
+ !list_empty(&watch_events));
+
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&xenwatch_mutex);
+
+ spin_lock(&watch_events_lock);
+ ent = watch_events.next;
+ if (ent != &watch_events)
+ list_del(ent);
+ spin_unlock(&watch_events_lock);
+
+ if (ent != &watch_events) {
+ msg = list_entry(ent, struct xs_stored_msg, list);
+ msg->u.watch.handle->callback(
+ msg->u.watch.handle,
+ (const char **)msg->u.watch.vec,
+ msg->u.watch.vec_size);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+
+ mutex_unlock(&xenwatch_mutex);
+ }
+
+ return 0;
+}
+
+static int process_msg(void)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+ int err;
+
+ /*
+ * We must disallow save/restore while reading a xenstore message.
+ * A partial read across s/r leaves us out of sync with xenstored.
+ */
+ for (;;) {
+ err = xb_wait_for_data_to_read();
+ if (err)
+ return err;
+ mutex_lock(&xs_state.response_mutex);
+ if (xb_data_to_read())
+ break;
+ /* We raced with save/restore: pending data 'disappeared'. */
+ mutex_unlock(&xs_state.response_mutex);
+ }
+
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (msg == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(&msg->hdr, sizeof(msg->hdr));
+ if (err) {
+ kfree(msg);
+ goto out;
+ }
+
+ body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+ if (body == NULL) {
+ kfree(msg);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(body, msg->hdr.len);
+ if (err) {
+ kfree(body);
+ kfree(msg);
+ goto out;
+ }
+ body[msg->hdr.len] = '\0';
+
+ if (msg->hdr.type == XS_WATCH_EVENT) {
+ msg->u.watch.vec = split(body, msg->hdr.len,
+ &msg->u.watch.vec_size);
+ if (IS_ERR(msg->u.watch.vec)) {
+ kfree(msg);
+ err = PTR_ERR(msg->u.watch.vec);
+ goto out;
+ }
+
+ spin_lock(&watches_lock);
+ msg->u.watch.handle = find_watch(
+ msg->u.watch.vec[XS_WATCH_TOKEN]);
+ if (msg->u.watch.handle != NULL) {
+ spin_lock(&watch_events_lock);
+ list_add_tail(&msg->list, &watch_events);
+ wake_up(&watch_events_waitq);
+ spin_unlock(&watch_events_lock);
+ } else {
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watches_lock);
+ } else {
+ msg->u.reply.body = body;
+ spin_lock(&xs_state.reply_lock);
+ list_add_tail(&msg->list, &xs_state.reply_list);
+ spin_unlock(&xs_state.reply_lock);
+ wake_up(&xs_state.reply_waitq);
+ }
+
+ out:
+ mutex_unlock(&xs_state.response_mutex);
+ return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+ int err;
+
+ for (;;) {
+ err = process_msg();
+ if (err)
+ printk(KERN_WARNING "XENBUS error %d while reading "
+ "message\n", err);
+ if (kthread_should_stop())
+ break;
+ }
+
+ return 0;
+}
+
+int xs_init(void)
+{
+ int err;
+ struct task_struct *task;
+
+ INIT_LIST_HEAD(&xs_state.reply_list);
+ spin_lock_init(&xs_state.reply_lock);
+ init_waitqueue_head(&xs_state.reply_waitq);
+
+ mutex_init(&xs_state.request_mutex);
+ mutex_init(&xs_state.response_mutex);
+ init_rwsem(&xs_state.transaction_mutex);
+ init_rwsem(&xs_state.watch_mutex);
+
+ /* Initialize the shared memory rings to talk to xenstored */
+ err = xb_init_comms();
+ if (err)
+ return err;
+
+ task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ xenwatch_pid = task->pid;
+
+ task = kthread_run(xenbus_thread, NULL, "xenbus");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+
+ return 0;
+}
diff --git a/fs/Kconfig b/fs/Kconfig
index 613df55..6a64990 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -251,7 +251,7 @@
config JBD2_DEBUG
bool "JBD2 (ext4dev/ext4) debugging support"
- depends on JBD2
+ depends on JBD2 && DEBUG_FS
help
If you are using the ext4dev/ext4 journaled file system (or
potentially any other filesystem/device using JBD2), this option
@@ -260,10 +260,10 @@
By default, the debugging output will be turned off.
If you select Y here, then you will be able to turn on debugging
- with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
- 1 and 5. The higher the number, the more debugging output is
- generated. To turn debugging off again, do
- "echo 0 > /proc/sys/fs/jbd2-debug".
+ with "echo N > /sys/kernel/debug/jbd2/jbd2-debug", where N is a
+ number between 1 and 5. The higher the number, the more debugging
+ output is generated. To turn debugging off again, do
+ "echo 0 > /sys/kernel/debug/jbd2/jbd2-debug".
config FS_MBCACHE
# Meta block cache for Extended Attributes (ext2/ext3/ext4)
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 9de54ae..e53b4af 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -517,7 +517,7 @@
/*
* An HJ special. This is expensive...
*/
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
jbd_unlock_bh_state(bitmap_bh);
{
struct buffer_head *debug_bh;
@@ -1597,7 +1597,7 @@
performed_allocation = 1;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
{
struct buffer_head *debug_bh;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index b9ce241..750c46f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -39,6 +39,7 @@
#include <linux/quotaops.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/falloc.h>
#include <linux/ext4_fs_extents.h>
#include <asm/uaccess.h>
@@ -91,36 +92,6 @@
ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
}
-static int ext4_ext_check_header(const char *function, struct inode *inode,
- struct ext4_extent_header *eh)
-{
- const char *error_msg = NULL;
-
- if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
- error_msg = "invalid magic";
- goto corrupted;
- }
- if (unlikely(eh->eh_max == 0)) {
- error_msg = "invalid eh_max";
- goto corrupted;
- }
- if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
- error_msg = "invalid eh_entries";
- goto corrupted;
- }
- return 0;
-
-corrupted:
- ext4_error(inode->i_sb, function,
- "bad header in inode #%lu: %s - magic %x, "
- "entries %u, max %u, depth %u",
- inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
- le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
- le16_to_cpu(eh->eh_depth));
-
- return -EIO;
-}
-
static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
{
int err;
@@ -269,6 +240,70 @@
return size;
}
+static int
+ext4_ext_max_entries(struct inode *inode, int depth)
+{
+ int max;
+
+ if (depth == ext_depth(inode)) {
+ if (depth == 0)
+ max = ext4_ext_space_root(inode);
+ else
+ max = ext4_ext_space_root_idx(inode);
+ } else {
+ if (depth == 0)
+ max = ext4_ext_space_block(inode);
+ else
+ max = ext4_ext_space_block_idx(inode);
+ }
+
+ return max;
+}
+
+static int __ext4_ext_check_header(const char *function, struct inode *inode,
+ struct ext4_extent_header *eh,
+ int depth)
+{
+ const char *error_msg;
+ int max = 0;
+
+ if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
+ error_msg = "invalid magic";
+ goto corrupted;
+ }
+ if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {
+ error_msg = "unexpected eh_depth";
+ goto corrupted;
+ }
+ if (unlikely(eh->eh_max == 0)) {
+ error_msg = "invalid eh_max";
+ goto corrupted;
+ }
+ max = ext4_ext_max_entries(inode, depth);
+ if (unlikely(le16_to_cpu(eh->eh_max) > max)) {
+ error_msg = "too large eh_max";
+ goto corrupted;
+ }
+ if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
+ error_msg = "invalid eh_entries";
+ goto corrupted;
+ }
+ return 0;
+
+corrupted:
+ ext4_error(inode->i_sb, function,
+ "bad header in inode #%lu: %s - magic %x, "
+ "entries %u, max %u(%u), depth %u(%u)",
+ inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+ max, le16_to_cpu(eh->eh_depth), depth);
+
+ return -EIO;
+}
+
+#define ext4_ext_check_header(inode, eh, depth) \
+ __ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
+
#ifdef EXT_DEBUG
static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
{
@@ -282,7 +317,7 @@
} else if (path->p_ext) {
ext_debug(" %d:%d:%llu ",
le32_to_cpu(path->p_ext->ee_block),
- le16_to_cpu(path->p_ext->ee_len),
+ ext4_ext_get_actual_len(path->p_ext),
ext_pblock(path->p_ext));
} else
ext_debug(" []");
@@ -305,7 +340,7 @@
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
- le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ ext4_ext_get_actual_len(ex), ext_pblock(ex));
}
ext_debug("\n");
}
@@ -329,6 +364,7 @@
/*
* ext4_ext_binsearch_idx:
* binary search for the closest index of the given block
+ * the header must be checked before calling this
*/
static void
ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -336,27 +372,25 @@
struct ext4_extent_header *eh = path->p_hdr;
struct ext4_extent_idx *r, *l, *m;
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
- BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
ext_debug("binsearch for %d(idx): ", block);
l = EXT_FIRST_INDEX(eh) + 1;
- r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
+ r = EXT_LAST_INDEX(eh);
while (l <= r) {
m = l + (r - l) / 2;
if (block < le32_to_cpu(m->ei_block))
r = m - 1;
else
l = m + 1;
- ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
- m, m->ei_block, r, r->ei_block);
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),
+ m, le32_to_cpu(m->ei_block),
+ r, le32_to_cpu(r->ei_block));
}
path->p_idx = l - 1;
ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
- idx_block(path->p_idx));
+ idx_pblock(path->p_idx));
#ifdef CHECK_BINSEARCH
{
@@ -388,6 +422,7 @@
/*
* ext4_ext_binsearch:
* binary search for closest extent of the given block
+ * the header must be checked before calling this
*/
static void
ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -395,9 +430,6 @@
struct ext4_extent_header *eh = path->p_hdr;
struct ext4_extent *r, *l, *m;
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-
if (eh->eh_entries == 0) {
/*
* this leaf is empty:
@@ -409,7 +441,7 @@
ext_debug("binsearch for %d: ", block);
l = EXT_FIRST_EXTENT(eh) + 1;
- r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
+ r = EXT_LAST_EXTENT(eh);
while (l <= r) {
m = l + (r - l) / 2;
@@ -417,15 +449,16 @@
r = m - 1;
else
l = m + 1;
- ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
- m, m->ee_block, r, r->ee_block);
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),
+ m, le32_to_cpu(m->ee_block),
+ r, le32_to_cpu(r->ee_block));
}
path->p_ext = l - 1;
ext_debug(" -> %d:%llu:%d ",
le32_to_cpu(path->p_ext->ee_block),
ext_pblock(path->p_ext),
- le16_to_cpu(path->p_ext->ee_len));
+ ext4_ext_get_actual_len(path->p_ext));
#ifdef CHECK_BINSEARCH
{
@@ -468,11 +501,10 @@
short int depth, i, ppos = 0, alloc = 0;
eh = ext_inode_hdr(inode);
- BUG_ON(eh == NULL);
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ depth = ext_depth(inode);
+ if (ext4_ext_check_header(inode, eh, depth))
return ERR_PTR(-EIO);
- i = depth = ext_depth(inode);
/* account possible depth increase */
if (!path) {
@@ -484,10 +516,12 @@
}
path[0].p_hdr = eh;
+ i = depth;
/* walk through the tree */
while (i) {
ext_debug("depth %d: num %d, max %d\n",
ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+
ext4_ext_binsearch_idx(inode, path + ppos, block);
path[ppos].p_block = idx_pblock(path[ppos].p_idx);
path[ppos].p_depth = i;
@@ -504,7 +538,7 @@
path[ppos].p_hdr = eh;
i--;
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ if (ext4_ext_check_header(inode, eh, i))
goto err;
}
@@ -513,9 +547,6 @@
path[ppos].p_ext = NULL;
path[ppos].p_idx = NULL;
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
- goto err;
-
/* find extent */
ext4_ext_binsearch(inode, path + ppos, block);
@@ -553,7 +584,7 @@
if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
len = (len - 1) * sizeof(struct ext4_extent_idx);
len = len < 0 ? 0 : len;
- ext_debug("insert new index %d after: %d. "
+ ext_debug("insert new index %d after: %llu. "
"move %d from 0x%p to 0x%p\n",
logical, ptr, len,
(curp->p_idx + 1), (curp->p_idx + 2));
@@ -564,7 +595,7 @@
/* insert before */
len = len * sizeof(struct ext4_extent_idx);
len = len < 0 ? 0 : len;
- ext_debug("insert new index %d before: %d. "
+ ext_debug("insert new index %d before: %llu. "
"move %d from 0x%p to 0x%p\n",
logical, ptr, len,
curp->p_idx, (curp->p_idx + 1));
@@ -686,7 +717,7 @@
ext_debug("move %d:%llu:%d in new leaf %llu\n",
le32_to_cpu(path[depth].p_ext->ee_block),
ext_pblock(path[depth].p_ext),
- le16_to_cpu(path[depth].p_ext->ee_len),
+ ext4_ext_get_actual_len(path[depth].p_ext),
newblock);
/*memmove(ex++, path[depth].p_ext++,
sizeof(struct ext4_extent));
@@ -764,7 +795,7 @@
BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
EXT_LAST_INDEX(path[i].p_hdr));
while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
- ext_debug("%d: move %d:%d in new index %llu\n", i,
+ ext_debug("%d: move %d:%llu in new index %llu\n", i,
le32_to_cpu(path[i].p_idx->ei_block),
idx_pblock(path[i].p_idx),
newblock);
@@ -893,8 +924,13 @@
curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
curp->p_hdr->eh_entries = cpu_to_le16(1);
curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
- /* FIXME: it works, but actually path[0] can be index */
- curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
+
+ if (path[0].p_hdr->eh_depth)
+ curp->p_idx->ei_block =
+ EXT_FIRST_INDEX(path[0].p_hdr)->ei_block;
+ else
+ curp->p_idx->ei_block =
+ EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
ext4_idx_store_pblock(curp->p_idx, newblock);
neh = ext_inode_hdr(inode);
@@ -1106,7 +1142,24 @@
ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
struct ext4_extent *ex2)
{
- if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
+ unsigned short ext1_ee_len, ext2_ee_len, max_len;
+
+ /*
+ * Make sure that either both extents are uninitialized, or
+ * both are _not_.
+ */
+ if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))
+ return 0;
+
+ if (ext4_ext_is_uninitialized(ex1))
+ max_len = EXT_UNINIT_MAX_LEN;
+ else
+ max_len = EXT_INIT_MAX_LEN;
+
+ ext1_ee_len = ext4_ext_get_actual_len(ex1);
+ ext2_ee_len = ext4_ext_get_actual_len(ex2);
+
+ if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=
le32_to_cpu(ex2->ee_block))
return 0;
@@ -1115,19 +1168,66 @@
* as an RO_COMPAT feature, refuse to merge to extents if
* this can result in the top bit of ee_len being set.
*/
- if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
+ if (ext1_ee_len + ext2_ee_len > max_len)
return 0;
#ifdef AGGRESSIVE_TEST
if (le16_to_cpu(ex1->ee_len) >= 4)
return 0;
#endif
- if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
+ if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))
return 1;
return 0;
}
/*
+ * This function tries to merge the "ex" extent to the next extent in the tree.
+ * It always tries to merge towards right. If you want to merge towards
+ * left, pass "ex - 1" as argument instead of "ex".
+ * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
+ * 1 if they got merged.
+ */
+int ext4_ext_try_to_merge(struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *ex)
+{
+ struct ext4_extent_header *eh;
+ unsigned int depth, len;
+ int merge_done = 0;
+ int uninitialized = 0;
+
+ depth = ext_depth(inode);
+ BUG_ON(path[depth].p_hdr == NULL);
+ eh = path[depth].p_hdr;
+
+ while (ex < EXT_LAST_EXTENT(eh)) {
+ if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
+ break;
+ /* merge with next extent! */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ + ext4_ext_get_actual_len(ex + 1));
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
+
+ if (ex + 1 < EXT_LAST_EXTENT(eh)) {
+ len = (EXT_LAST_EXTENT(eh) - ex - 1)
+ * sizeof(struct ext4_extent);
+ memmove(ex + 1, ex + 2, len);
+ }
+ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
+ merge_done = 1;
+ WARN_ON(eh->eh_entries == 0);
+ if (!eh->eh_entries)
+ ext4_error(inode->i_sb, "ext4_ext_try_to_merge",
+ "inode#%lu, eh->eh_entries = 0!", inode->i_ino);
+ }
+
+ return merge_done;
+}
+
+/*
* check if a portion of the "newext" extent overlaps with an
* existing extent.
*
@@ -1144,7 +1244,7 @@
unsigned int ret = 0;
b1 = le32_to_cpu(newext->ee_block);
- len1 = le16_to_cpu(newext->ee_len);
+ len1 = ext4_ext_get_actual_len(newext);
depth = ext_depth(inode);
if (!path[depth].p_ext)
goto out;
@@ -1191,8 +1291,9 @@
struct ext4_extent *nearex; /* nearest extent */
struct ext4_ext_path *npath = NULL;
int depth, len, err, next;
+ unsigned uninitialized = 0;
- BUG_ON(newext->ee_len == 0);
+ BUG_ON(ext4_ext_get_actual_len(newext) == 0);
depth = ext_depth(inode);
ex = path[depth].p_ext;
BUG_ON(path[depth].p_hdr == NULL);
@@ -1200,14 +1301,24 @@
/* try to insert block into found extent and return */
if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
ext_debug("append %d block to %d:%d (from %llu)\n",
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
le32_to_cpu(ex->ee_block),
- le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ ext4_ext_get_actual_len(ex), ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
return err;
- ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
- + le16_to_cpu(newext->ee_len));
+
+ /*
+ * ext4_can_extents_be_merged should have checked that either
+ * both extents are uninitialized, or both aren't. Thus we
+ * need to check only one of them here.
+ */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ + ext4_ext_get_actual_len(newext));
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
eh = path[depth].p_hdr;
nearex = ex;
goto merge;
@@ -1263,7 +1374,7 @@
ext_debug("first extent in the leaf: %d:%llu:%d\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len));
+ ext4_ext_get_actual_len(newext));
path[depth].p_ext = EXT_FIRST_EXTENT(eh);
} else if (le32_to_cpu(newext->ee_block)
> le32_to_cpu(nearex->ee_block)) {
@@ -1276,7 +1387,7 @@
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
memmove(nearex + 2, nearex + 1, len);
}
@@ -1289,7 +1400,7 @@
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
memmove(nearex + 1, nearex, len);
path[depth].p_ext = nearex;
@@ -1304,20 +1415,7 @@
merge:
/* try to merge extents to the right */
- while (nearex < EXT_LAST_EXTENT(eh)) {
- if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
- break;
- /* merge with next extent! */
- nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
- + le16_to_cpu(nearex[1].ee_len));
- if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
- len = (EXT_LAST_EXTENT(eh) - nearex - 1)
- * sizeof(struct ext4_extent);
- memmove(nearex + 1, nearex + 2, len);
- }
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
- BUG_ON(eh->eh_entries == 0);
- }
+ ext4_ext_try_to_merge(inode, path, nearex);
/* try to merge extents to the left */
@@ -1379,8 +1477,8 @@
end = le32_to_cpu(ex->ee_block);
if (block + num < end)
end = block + num;
- } else if (block >=
- le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
+ } else if (block >= le32_to_cpu(ex->ee_block)
+ + ext4_ext_get_actual_len(ex)) {
/* need to allocate space after found extent */
start = block;
end = block + num;
@@ -1392,7 +1490,8 @@
* by found extent
*/
start = block;
- end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
+ end = le32_to_cpu(ex->ee_block)
+ + ext4_ext_get_actual_len(ex);
if (block + num < end)
end = block + num;
exists = 1;
@@ -1408,7 +1507,7 @@
cbex.ec_type = EXT4_EXT_CACHE_GAP;
} else {
cbex.ec_block = le32_to_cpu(ex->ee_block);
- cbex.ec_len = le16_to_cpu(ex->ee_len);
+ cbex.ec_len = ext4_ext_get_actual_len(ex);
cbex.ec_start = ext_pblock(ex);
cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
}
@@ -1481,15 +1580,15 @@
ext_debug("cache gap(before): %lu [%lu:%lu]",
(unsigned long) block,
(unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len));
+ (unsigned long) ext4_ext_get_actual_len(ex));
} else if (block >= le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len)) {
+ + ext4_ext_get_actual_len(ex)) {
lblock = le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len);
+ + ext4_ext_get_actual_len(ex);
len = ext4_ext_next_allocated_block(path);
ext_debug("cache gap(after): [%lu:%lu] %lu",
(unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len),
+ (unsigned long) ext4_ext_get_actual_len(ex),
(unsigned long) block);
BUG_ON(len == lblock);
len = len - lblock;
@@ -1619,12 +1718,12 @@
unsigned long from, unsigned long to)
{
struct buffer_head *bh;
+ unsigned short ee_len = ext4_ext_get_actual_len(ex);
int i;
#ifdef EXTENTS_STATS
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- unsigned short ee_len = le16_to_cpu(ex->ee_len);
spin_lock(&sbi->s_ext_stats_lock);
sbi->s_ext_blocks += ee_len;
sbi->s_ext_extents++;
@@ -1638,12 +1737,12 @@
}
#endif
if (from >= le32_to_cpu(ex->ee_block)
- && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ && to == le32_to_cpu(ex->ee_block) + ee_len - 1) {
/* tail removal */
unsigned long num;
ext4_fsblk_t start;
- num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
- start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
+ num = le32_to_cpu(ex->ee_block) + ee_len - from;
+ start = ext_pblock(ex) + ee_len - num;
ext_debug("free last %lu blocks starting %llu\n", num, start);
for (i = 0; i < num; i++) {
bh = sb_find_get_block(inode->i_sb, start + i);
@@ -1651,12 +1750,12 @@
}
ext4_free_blocks(handle, inode, start, num);
} else if (from == le32_to_cpu(ex->ee_block)
- && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
printk("strange request: removal %lu-%lu from %u:%u\n",
- from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ from, to, le32_to_cpu(ex->ee_block), ee_len);
} else {
printk("strange request: removal(2) %lu-%lu from %u:%u\n",
- from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ from, to, le32_to_cpu(ex->ee_block), ee_len);
}
return 0;
}
@@ -1671,21 +1770,23 @@
unsigned a, b, block, num;
unsigned long ex_ee_block;
unsigned short ex_ee_len;
+ unsigned uninitialized = 0;
struct ext4_extent *ex;
+ /* the header must be checked already in ext4_ext_remove_space() */
ext_debug("truncate since %lu in leaf\n", start);
if (!path[depth].p_hdr)
path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
eh = path[depth].p_hdr;
BUG_ON(eh == NULL);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
/* find where to start removing */
ex = EXT_LAST_EXTENT(eh);
ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = le16_to_cpu(ex->ee_len);
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex_ee_len = ext4_ext_get_actual_len(ex);
while (ex >= EXT_FIRST_EXTENT(eh) &&
ex_ee_block + ex_ee_len > start) {
@@ -1753,6 +1854,12 @@
ex->ee_block = cpu_to_le32(block);
ex->ee_len = cpu_to_le16(num);
+ /*
+ * Do not mark uninitialized if all the blocks in the
+ * extent have been removed.
+ */
+ if (uninitialized && num)
+ ext4_ext_mark_uninitialized(ex);
err = ext4_ext_dirty(handle, inode, path + depth);
if (err)
@@ -1762,7 +1869,7 @@
ext_pblock(ex));
ex--;
ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = le16_to_cpu(ex->ee_len);
+ ex_ee_len = ext4_ext_get_actual_len(ex);
}
if (correct_index && eh->eh_entries)
@@ -1825,7 +1932,7 @@
return -ENOMEM;
}
path[0].p_hdr = ext_inode_hdr(inode);
- if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
+ if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
err = -EIO;
goto out;
}
@@ -1846,17 +1953,8 @@
if (!path[i].p_hdr) {
ext_debug("initialize header\n");
path[i].p_hdr = ext_block_hdr(path[i].p_bh);
- if (ext4_ext_check_header(__FUNCTION__, inode,
- path[i].p_hdr)) {
- err = -EIO;
- goto out;
- }
}
- BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
- > le16_to_cpu(path[i].p_hdr->eh_max));
- BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
-
if (!path[i].p_idx) {
/* this level hasn't been touched yet */
path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
@@ -1873,17 +1971,27 @@
i, EXT_FIRST_INDEX(path[i].p_hdr),
path[i].p_idx);
if (ext4_ext_more_to_rm(path + i)) {
+ struct buffer_head *bh;
/* go to the next level */
ext_debug("move to level %d (block %llu)\n",
i + 1, idx_pblock(path[i].p_idx));
memset(path + i + 1, 0, sizeof(*path));
- path[i+1].p_bh =
- sb_bread(sb, idx_pblock(path[i].p_idx));
- if (!path[i+1].p_bh) {
+ bh = sb_bread(sb, idx_pblock(path[i].p_idx));
+ if (!bh) {
/* should we reset i_size? */
err = -EIO;
break;
}
+ if (WARN_ON(i + 1 > depth)) {
+ err = -EIO;
+ break;
+ }
+ if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+ depth - i - 1)) {
+ err = -EIO;
+ break;
+ }
+ path[i + 1].p_bh = bh;
/* save actual number of indexes since this
* number is changed at the next iteration */
@@ -1977,15 +2085,158 @@
#endif
}
+/*
+ * This function is called by ext4_ext_get_blocks() if someone tries to write
+ * to an uninitialized extent. It may result in splitting the uninitialized
+ * extent into multiple extents (upto three - one initialized and two
+ * uninitialized).
+ * There are three possibilities:
+ * a> There is no split required: Entire extent should be initialized
+ * b> Splits in two extents: Write is happening at either end of the extent
+ * c> Splits in three extents: Somone is writing in middle of the extent
+ */
+int ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_fsblk_t iblock,
+ unsigned long max_blocks)
+{
+ struct ext4_extent *ex, newex;
+ struct ext4_extent *ex1 = NULL;
+ struct ext4_extent *ex2 = NULL;
+ struct ext4_extent *ex3 = NULL;
+ struct ext4_extent_header *eh;
+ unsigned int allocated, ee_block, ee_len, depth;
+ ext4_fsblk_t newblock;
+ int err = 0;
+ int ret = 0;
+
+ depth = ext_depth(inode);
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+ ee_block = le32_to_cpu(ex->ee_block);
+ ee_len = ext4_ext_get_actual_len(ex);
+ allocated = ee_len - (iblock - ee_block);
+ newblock = iblock - ee_block + ext_pblock(ex);
+ ex2 = ex;
+
+ /* ex1: ee_block to iblock - 1 : uninitialized */
+ if (iblock > ee_block) {
+ ex1 = ex;
+ ex1->ee_len = cpu_to_le16(iblock - ee_block);
+ ext4_ext_mark_uninitialized(ex1);
+ ex2 = &newex;
+ }
+ /*
+ * for sanity, update the length of the ex2 extent before
+ * we insert ex3, if ex1 is NULL. This is to avoid temporary
+ * overlap of blocks.
+ */
+ if (!ex1 && allocated > max_blocks)
+ ex2->ee_len = cpu_to_le16(max_blocks);
+ /* ex3: to ee_block + ee_len : uninitialised */
+ if (allocated > max_blocks) {
+ unsigned int newdepth;
+ ex3 = &newex;
+ ex3->ee_block = cpu_to_le32(iblock + max_blocks);
+ ext4_ext_store_pblock(ex3, newblock + max_blocks);
+ ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+ ext4_ext_mark_uninitialized(ex3);
+ err = ext4_ext_insert_extent(handle, inode, path, ex3);
+ if (err)
+ goto out;
+ /*
+ * The depth, and hence eh & ex might change
+ * as part of the insert above.
+ */
+ newdepth = ext_depth(inode);
+ if (newdepth != depth) {
+ depth = newdepth;
+ path = ext4_ext_find_extent(inode, iblock, NULL);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ path = NULL;
+ goto out;
+ }
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+ if (ex2 != &newex)
+ ex2 = ex;
+ }
+ allocated = max_blocks;
+ }
+ /*
+ * If there was a change of depth as part of the
+ * insertion of ex3 above, we need to update the length
+ * of the ex1 extent again here
+ */
+ if (ex1 && ex1 != ex) {
+ ex1 = ex;
+ ex1->ee_len = cpu_to_le16(iblock - ee_block);
+ ext4_ext_mark_uninitialized(ex1);
+ ex2 = &newex;
+ }
+ /* ex2: iblock to iblock + maxblocks-1 : initialised */
+ ex2->ee_block = cpu_to_le32(iblock);
+ ex2->ee_start = cpu_to_le32(newblock);
+ ext4_ext_store_pblock(ex2, newblock);
+ ex2->ee_len = cpu_to_le16(allocated);
+ if (ex2 != ex)
+ goto insert;
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+ /*
+ * New (initialized) extent starts from the first block
+ * in the current extent. i.e., ex2 == ex
+ * We have to see if it can be merged with the extent
+ * on the left.
+ */
+ if (ex2 > EXT_FIRST_EXTENT(eh)) {
+ /*
+ * To merge left, pass "ex2 - 1" to try_to_merge(),
+ * since it merges towards right _only_.
+ */
+ ret = ext4_ext_try_to_merge(inode, path, ex2 - 1);
+ if (ret) {
+ err = ext4_ext_correct_indexes(handle, inode, path);
+ if (err)
+ goto out;
+ depth = ext_depth(inode);
+ ex2--;
+ }
+ }
+ /*
+ * Try to Merge towards right. This might be required
+ * only when the whole extent is being written to.
+ * i.e. ex2 == ex and ex3 == NULL.
+ */
+ if (!ex3) {
+ ret = ext4_ext_try_to_merge(inode, path, ex2);
+ if (ret) {
+ err = ext4_ext_correct_indexes(handle, inode, path);
+ if (err)
+ goto out;
+ }
+ }
+ /* Mark modified extent as dirty */
+ err = ext4_ext_dirty(handle, inode, path + depth);
+ goto out;
+insert:
+ err = ext4_ext_insert_extent(handle, inode, path, &newex);
+out:
+ return err ? err : allocated;
+}
+
int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t iblock,
unsigned long max_blocks, struct buffer_head *bh_result,
int create, int extend_disksize)
{
struct ext4_ext_path *path = NULL;
+ struct ext4_extent_header *eh;
struct ext4_extent newex, *ex;
ext4_fsblk_t goal, newblock;
- int err = 0, depth;
+ int err = 0, depth, ret;
unsigned long allocated = 0;
__clear_bit(BH_New, &bh_result->b_state);
@@ -1998,8 +2249,10 @@
if (goal) {
if (goal == EXT4_EXT_CACHE_GAP) {
if (!create) {
- /* block isn't allocated yet and
- * user doesn't want to allocate it */
+ /*
+ * block isn't allocated yet and
+ * user doesn't want to allocate it
+ */
goto out2;
}
/* we should allocate requested block */
@@ -2033,21 +2286,19 @@
* this is why assert can't be put in ext4_ext_find_extent()
*/
BUG_ON(path[depth].p_ext == NULL && depth != 0);
+ eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (ex) {
unsigned long ee_block = le32_to_cpu(ex->ee_block);
ext4_fsblk_t ee_start = ext_pblock(ex);
- unsigned short ee_len = le16_to_cpu(ex->ee_len);
+ unsigned short ee_len;
/*
- * Allow future support for preallocated extents to be added
- * as an RO_COMPAT feature:
* Uninitialized extents are treated as holes, except that
- * we avoid (fail) allocating new blocks during a write.
+ * we split out initialized portions during a write.
*/
- if (ee_len > EXT_MAX_LEN)
- goto out2;
+ ee_len = ext4_ext_get_actual_len(ex);
/* if found extent covers block, simply return it */
if (iblock >= ee_block && iblock < ee_block + ee_len) {
newblock = iblock - ee_block + ee_start;
@@ -2055,9 +2306,27 @@
allocated = ee_len - (iblock - ee_block);
ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
ee_block, ee_len, newblock);
- ext4_ext_put_in_cache(inode, ee_block, ee_len,
- ee_start, EXT4_EXT_CACHE_EXTENT);
- goto out;
+
+ /* Do not put uninitialized extent in the cache */
+ if (!ext4_ext_is_uninitialized(ex)) {
+ ext4_ext_put_in_cache(inode, ee_block,
+ ee_len, ee_start,
+ EXT4_EXT_CACHE_EXTENT);
+ goto out;
+ }
+ if (create == EXT4_CREATE_UNINITIALIZED_EXT)
+ goto out;
+ if (!create)
+ goto out2;
+
+ ret = ext4_ext_convert_to_initialized(handle, inode,
+ path, iblock,
+ max_blocks);
+ if (ret <= 0)
+ goto out2;
+ else
+ allocated = ret;
+ goto outnew;
}
}
@@ -2066,8 +2335,10 @@
* we couldn't try to create block if create flag is zero
*/
if (!create) {
- /* put just found gap into cache to speed up
- * subsequent requests */
+ /*
+ * put just found gap into cache to speed up
+ * subsequent requests
+ */
ext4_ext_put_gap_in_cache(inode, path, iblock);
goto out2;
}
@@ -2081,6 +2352,19 @@
/* allocate new block */
goal = ext4_ext_find_goal(inode, path, iblock);
+ /*
+ * See if request is beyond maximum number of blocks we can have in
+ * a single extent. For an initialized extent this limit is
+ * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+ * EXT_UNINIT_MAX_LEN.
+ */
+ if (max_blocks > EXT_INIT_MAX_LEN &&
+ create != EXT4_CREATE_UNINITIALIZED_EXT)
+ max_blocks = EXT_INIT_MAX_LEN;
+ else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+ create == EXT4_CREATE_UNINITIALIZED_EXT)
+ max_blocks = EXT_UNINIT_MAX_LEN;
+
/* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
newex.ee_block = cpu_to_le32(iblock);
newex.ee_len = cpu_to_le16(max_blocks);
@@ -2098,6 +2382,8 @@
/* try to insert new extent into found leaf and return */
ext4_ext_store_pblock(&newex, newblock);
newex.ee_len = cpu_to_le16(allocated);
+ if (create == EXT4_CREATE_UNINITIALIZED_EXT) /* Mark uninitialized */
+ ext4_ext_mark_uninitialized(&newex);
err = ext4_ext_insert_extent(handle, inode, path, &newex);
if (err) {
/* free data blocks we just allocated */
@@ -2111,10 +2397,13 @@
/* previous routine could use block we allocated */
newblock = ext_pblock(&newex);
+outnew:
__set_bit(BH_New, &bh_result->b_state);
- ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
- EXT4_EXT_CACHE_EXTENT);
+ /* Cache only when it is _not_ an uninitialized extent */
+ if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+ ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+ EXT4_EXT_CACHE_EXTENT);
out:
if (allocated > max_blocks)
allocated = max_blocks;
@@ -2178,7 +2467,8 @@
err = ext4_ext_remove_space(inode, last_block);
/* In a multi-transaction truncate, we only make the final
- * transaction synchronous. */
+ * transaction synchronous.
+ */
if (IS_SYNC(inode))
handle->h_sync = 1;
@@ -2217,3 +2507,127 @@
return needed;
}
+
+/*
+ * preallocate space for a file. This implements ext4's fallocate inode
+ * operation, which gets called from sys_fallocate system call.
+ * For block-mapped files, posix_fallocate should fall back to the method
+ * of writing zeroes to the required new blocks (the same behavior which is
+ * expected for file systems which do not support fallocate() system call).
+ */
+long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
+{
+ handle_t *handle;
+ ext4_fsblk_t block, max_blocks;
+ ext4_fsblk_t nblocks = 0;
+ int ret = 0;
+ int ret2 = 0;
+ int retries = 0;
+ struct buffer_head map_bh;
+ unsigned int credits, blkbits = inode->i_blkbits;
+
+ /*
+ * currently supporting (pre)allocate mode for extent-based
+ * files _only_
+ */
+ if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+ return -EOPNOTSUPP;
+
+ /* preallocation to directories is currently not supported */
+ if (S_ISDIR(inode->i_mode))
+ return -ENODEV;
+
+ block = offset >> blkbits;
+ max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
+ - block;
+
+ /*
+ * credits to insert 1 extent into extent tree + buffers to be able to
+ * modify 1 super block, 1 block bitmap and 1 group descriptor.
+ */
+ credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
+retry:
+ while (ret >= 0 && ret < max_blocks) {
+ block = block + ret;
+ max_blocks = max_blocks - ret;
+ handle = ext4_journal_start(inode, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ break;
+ }
+
+ ret = ext4_ext_get_blocks(handle, inode, block,
+ max_blocks, &map_bh,
+ EXT4_CREATE_UNINITIALIZED_EXT, 0);
+ WARN_ON(!ret);
+ if (!ret) {
+ ext4_error(inode->i_sb, "ext4_fallocate",
+ "ext4_ext_get_blocks returned 0! inode#%lu"
+ ", block=%llu, max_blocks=%llu",
+ inode->i_ino, block, max_blocks);
+ ret = -EIO;
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ break;
+ }
+ if (ret > 0) {
+ /* check wrap through sign-bit/zero here */
+ if ((block + ret) < 0 || (block + ret) < block) {
+ ret = -EIO;
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ break;
+ }
+ if (buffer_new(&map_bh) && ((block + ret) >
+ (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
+ >> blkbits)))
+ nblocks = nblocks + ret;
+ }
+
+ /* Update ctime if new blocks get allocated */
+ if (nblocks) {
+ struct timespec now;
+
+ now = current_fs_time(inode->i_sb);
+ if (!timespec_equal(&inode->i_ctime, &now))
+ inode->i_ctime = now;
+ }
+
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ if (ret2)
+ break;
+ }
+
+ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+
+ /*
+ * Time to update the file size.
+ * Update only when preallocation was requested beyond the file size.
+ */
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ (offset + len) > i_size_read(inode)) {
+ if (ret > 0) {
+ /*
+ * if no error, we assume preallocation succeeded
+ * completely
+ */
+ mutex_lock(&inode->i_mutex);
+ i_size_write(inode, offset + len);
+ EXT4_I(inode)->i_disksize = i_size_read(inode);
+ mutex_unlock(&inode->i_mutex);
+ } else if (ret < 0 && nblocks) {
+ /* Handle partial allocation scenario */
+ loff_t newsize;
+
+ mutex_lock(&inode->i_mutex);
+ newsize = (nblocks << blkbits) + i_size_read(inode);
+ i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
+ EXT4_I(inode)->i_disksize = i_size_read(inode);
+ mutex_unlock(&inode->i_mutex);
+ }
+ }
+
+ return ret > 0 ? ret2 : ret;
+}
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index d4c8186..1a81cd6 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -134,5 +134,6 @@
.removexattr = generic_removexattr,
#endif
.permission = ext4_permission,
+ .fallocate = ext4_fallocate,
};
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index c88b439..427f830 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -563,7 +563,8 @@
inode->i_ino = ino;
/* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
+ ext4_current_time(inode);
memset(ei->i_data, 0, sizeof(ei->i_data));
ei->i_dir_start_lookup = 0;
@@ -595,9 +596,8 @@
spin_unlock(&sbi->s_next_gen_lock);
ei->i_state = EXT4_STATE_NEW;
- ei->i_extra_isize =
- (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
- sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
+
+ ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
ret = inode;
if(DQUOT_ALLOC_INODE(inode)) {
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8416fa2..de26c25 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -726,7 +726,7 @@
/* We are done with atomic stuff, now do the rest of housekeeping */
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
/* had we spliced it onto indirect block? */
@@ -1766,7 +1766,6 @@
struct inode *inode = mapping->host;
struct buffer_head *bh;
int err = 0;
- void *kaddr;
blocksize = inode->i_sb->s_blocksize;
length = blocksize - (offset & (blocksize - 1));
@@ -1778,10 +1777,7 @@
*/
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
ext4_should_writeback_data(inode) && PageUptodate(page)) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
set_page_dirty(page);
goto unlock;
}
@@ -1834,10 +1830,7 @@
goto unlock;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
BUFFER_TRACE(bh, "zeroed end of block");
@@ -2375,7 +2368,7 @@
ext4_discard_reservation(inode);
mutex_unlock(&ei->truncate_mutex);
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
/*
@@ -2583,6 +2576,25 @@
inode->i_flags |= S_DIRSYNC;
}
+/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
+void ext4_get_inode_flags(struct ext4_inode_info *ei)
+{
+ unsigned int flags = ei->vfs_inode.i_flags;
+
+ ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
+ EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL);
+ if (flags & S_SYNC)
+ ei->i_flags |= EXT4_SYNC_FL;
+ if (flags & S_APPEND)
+ ei->i_flags |= EXT4_APPEND_FL;
+ if (flags & S_IMMUTABLE)
+ ei->i_flags |= EXT4_IMMUTABLE_FL;
+ if (flags & S_NOATIME)
+ ei->i_flags |= EXT4_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ ei->i_flags |= EXT4_DIRSYNC_FL;
+}
+
void ext4_read_inode(struct inode * inode)
{
struct ext4_iloc iloc;
@@ -2610,10 +2622,6 @@
}
inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
- inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
ei->i_state = 0;
ei->i_dir_start_lookup = 0;
@@ -2691,6 +2699,11 @@
} else
ei->i_extra_isize = 0;
+ EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
+ EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
+ EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
+ EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
+
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
@@ -2744,6 +2757,7 @@
if (ei->i_state & EXT4_STATE_NEW)
memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
+ ext4_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
if(!(test_opt(inode->i_sb, NO_UID32))) {
raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
@@ -2771,9 +2785,12 @@
}
raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
raw_inode->i_size = cpu_to_le32(ei->i_disksize);
- raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
- raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
- raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+
+ EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
+ EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
+ EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
+ EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
+
raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
raw_inode->i_flags = cpu_to_le32(ei->i_flags);
@@ -3082,6 +3099,39 @@
}
/*
+ * Expand an inode by new_extra_isize bytes.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
+ struct ext4_iloc iloc, handle_t *handle)
+{
+ struct ext4_inode *raw_inode;
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *entry;
+
+ if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+ return 0;
+
+ raw_inode = ext4_raw_inode(&iloc);
+
+ header = IHDR(inode, raw_inode);
+ entry = IFIRST(header);
+
+ /* No extended attributes present */
+ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
+ header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
+ memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
+ new_extra_isize);
+ EXT4_I(inode)->i_extra_isize = new_extra_isize;
+ return 0;
+ }
+
+ /* try to expand with EAs present */
+ return ext4_expand_extra_isize_ea(inode, new_extra_isize,
+ raw_inode, handle);
+}
+
+/*
* What we do here is to mark the in-core inode as clean with respect to inode
* dirtiness (it may still be data-dirty).
* This means that the in-core inode may be reaped by prune_icache
@@ -3105,10 +3155,38 @@
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
{
struct ext4_iloc iloc;
- int err;
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ static unsigned int mnt_count;
+ int err, ret;
might_sleep();
err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
+ !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
+ /*
+ * We need extra buffer credits since we may write into EA block
+ * with this same handle. If journal_extend fails, then it will
+ * only result in a minor loss of functionality for that inode.
+ * If this is felt to be critical, then e2fsck should be run to
+ * force a large enough s_min_extra_isize.
+ */
+ if ((jbd2_journal_extend(handle,
+ EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
+ ret = ext4_expand_extra_isize(inode,
+ sbi->s_want_extra_isize,
+ iloc, handle);
+ if (ret) {
+ EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+ if (mnt_count != sbi->s_es->s_mnt_count) {
+ ext4_warning(inode->i_sb, __FUNCTION__,
+ "Unable to expand inode %lu. Delete"
+ " some EAs or run e2fsck.",
+ inode->i_ino);
+ mnt_count = sbi->s_es->s_mnt_count;
+ }
+ }
+ }
+ }
if (!err)
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
return err;
@@ -3197,7 +3275,7 @@
*/
journal = EXT4_JOURNAL(inode);
- if (is_journal_aborted(journal) || IS_RDONLY(inode))
+ if (is_journal_aborted(journal))
return -EROFS;
jbd2_journal_lock_updates(journal);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 7b4aa45..c04c7cc 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -28,6 +28,7 @@
switch (cmd) {
case EXT4_IOC_GETFLAGS:
+ ext4_get_inode_flags(ei);
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT4_IOC_SETFLAGS: {
@@ -96,7 +97,7 @@
ei->i_flags = flags;
ext4_set_inode_flags(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
flags_err:
@@ -133,14 +134,14 @@
return PTR_ERR(handle);
err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err == 0) {
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
inode->i_generation = generation;
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
}
ext4_journal_stop(handle);
return err;
}
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
case EXT4_IOC_WAIT_FOR_READONLY:
/*
* This is racy - by the time we're woken up and running,
@@ -282,7 +283,7 @@
case EXT4_IOC32_SETVERSION_OLD:
cmd = EXT4_IOC_SETVERSION_OLD;
break;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
case EXT4_IOC32_WAIT_FOR_READONLY:
cmd = EXT4_IOC_WAIT_FOR_READONLY;
break;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2de339d..da22497 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1295,7 +1295,7 @@
* happen is that the times are slightly out of date
* and/or different from the directory change time.
*/
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
ext4_update_dx_flag(dir);
dir->i_version++;
ext4_mark_inode_dirty(handle, dir);
@@ -1629,6 +1629,35 @@
return -ENOENT;
}
+/*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+ */
+static void ext4_inc_count(handle_t *handle, struct inode *inode)
+{
+ inc_nlink(inode);
+ if (is_dx(inode) && inode->i_nlink > 1) {
+ /* limit is 16-bit i_links_count */
+ if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
+ inode->i_nlink = 1;
+ EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
+ }
+ }
+}
+
+/*
+ * If a directory had nlink == 1, then we should let it be 1. This indicates
+ * directory has >EXT4_LINK_MAX subdirs.
+ */
+static void ext4_dec_count(handle_t *handle, struct inode *inode)
+{
+ drop_nlink(inode);
+ if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
+ inc_nlink(inode);
+}
+
+
static int ext4_add_nondir(handle_t *handle,
struct dentry *dentry, struct inode *inode)
{
@@ -1725,7 +1754,7 @@
struct ext4_dir_entry_2 * de;
int err, retries = 0;
- if (dir->i_nlink >= EXT4_LINK_MAX)
+ if (EXT4_DIR_LINK_MAX(dir))
return -EMLINK;
retry:
@@ -1748,7 +1777,7 @@
inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
dir_block = ext4_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
- drop_nlink(inode); /* is this nlink == 0? */
+ ext4_dec_count(handle, inode); /* is this nlink == 0? */
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -1780,7 +1809,7 @@
iput (inode);
goto out_stop;
}
- inc_nlink(dir);
+ ext4_inc_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
@@ -2045,9 +2074,9 @@
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_rmdir;
- if (inode->i_nlink != 2)
+ if (!EXT4_DIR_LINK_EMPTY(inode))
ext4_warning (inode->i_sb, "ext4_rmdir",
- "empty directory has nlink!=2 (%d)",
+ "empty directory has too many links (%d)",
inode->i_nlink);
inode->i_version++;
clear_nlink(inode);
@@ -2056,9 +2085,9 @@
* recovery. */
inode->i_size = 0;
ext4_orphan_add(handle, inode);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
- drop_nlink(dir);
+ ext4_dec_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
@@ -2106,13 +2135,13 @@
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_unlink;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
- drop_nlink(inode);
+ ext4_dec_count(handle, inode);
if (!inode->i_nlink)
ext4_orphan_add(handle, inode);
- inode->i_ctime = dir->i_ctime;
+ inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
retval = 0;
@@ -2159,7 +2188,7 @@
err = __page_symlink(inode, symname, l,
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
- drop_nlink(inode);
+ ext4_dec_count(handle, inode);
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -2185,8 +2214,9 @@
struct inode *inode = old_dentry->d_inode;
int err, retries = 0;
- if (inode->i_nlink >= EXT4_LINK_MAX)
+ if (EXT4_DIR_LINK_MAX(inode))
return -EMLINK;
+
/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
@@ -2203,8 +2233,8 @@
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
- inode->i_ctime = CURRENT_TIME_SEC;
- inc_nlink(inode);
+ inode->i_ctime = ext4_current_time(inode);
+ ext4_inc_count(handle, inode);
atomic_inc(&inode->i_count);
err = ext4_add_nondir(handle, dentry, inode);
@@ -2305,7 +2335,7 @@
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = CURRENT_TIME_SEC;
+ old_inode->i_ctime = ext4_current_time(old_inode);
ext4_mark_inode_dirty(handle, old_inode);
/*
@@ -2337,10 +2367,10 @@
}
if (new_inode) {
- drop_nlink(new_inode);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_dec_count(handle, new_inode);
+ new_inode->i_ctime = ext4_current_time(new_inode);
}
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
ext4_update_dx_flag(old_dir);
if (dir_bh) {
BUFFER_TRACE(dir_bh, "get_write_access");
@@ -2348,11 +2378,13 @@
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
ext4_journal_dirty_metadata(handle, dir_bh);
- drop_nlink(old_dir);
+ ext4_dec_count(handle, old_dir);
if (new_inode) {
- drop_nlink(new_inode);
+ /* checked empty_dir above, can't have another parent,
+ * ext3_dec_count() won't work for many-linked dirs */
+ new_inode->i_nlink = 0;
} else {
- inc_nlink(new_dir);
+ ext4_inc_count(handle, new_dir);
ext4_update_dx_flag(new_dir);
ext4_mark_inode_dirty(handle, new_dir);
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b806e68..6dcbb28 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -36,6 +36,7 @@
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/seq_file.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -734,7 +735,7 @@
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
- Opt_grpquota, Opt_extents,
+ Opt_grpquota, Opt_extents, Opt_noextents,
};
static match_table_t tokens = {
@@ -785,6 +786,7 @@
{Opt_usrquota, "usrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_extents, "extents"},
+ {Opt_noextents, "noextents"},
{Opt_err, NULL},
{Opt_resize, "resize"},
};
@@ -1120,6 +1122,9 @@
case Opt_extents:
set_opt (sbi->s_mount_opt, EXTENTS);
break;
+ case Opt_noextents:
+ clear_opt (sbi->s_mount_opt, EXTENTS);
+ break;
default:
printk (KERN_ERR
"EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1551,6 +1556,12 @@
set_opt(sbi->s_mount_opt, RESERVATION);
+ /*
+ * turn on extents feature by default in ext4 filesystem
+ * User -o noextents to turn it off
+ */
+ set_opt(sbi->s_mount_opt, EXTENTS);
+
if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
NULL, 0))
goto failed_mount;
@@ -1634,13 +1645,15 @@
sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
- (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+ (!is_power_of_2(sbi->s_inode_size)) ||
(sbi->s_inode_size > blocksize)) {
printk (KERN_ERR
"EXT4-fs: unsupported inode size: %d\n",
sbi->s_inode_size);
goto failed_mount;
}
+ if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+ sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
}
sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
le32_to_cpu(es->s_log_frag_size);
@@ -1803,6 +1816,13 @@
goto failed_mount3;
}
+ if (ext4_blocks_count(es) > 0xffffffffULL &&
+ !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
+ JBD2_FEATURE_INCOMPAT_64BIT)) {
+ printk(KERN_ERR "ext4: Failed to set 64-bit journal feature\n");
+ goto failed_mount4;
+ }
+
/* We have now updated the journal if required, so we can
* validate the data journaling mode. */
switch (test_opt(sb, DATA_FLAGS)) {
@@ -1857,6 +1877,32 @@
}
ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+
+ /* determine the minimum size of new large inodes, if present */
+ if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+ sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+ if (sbi->s_want_extra_isize <
+ le16_to_cpu(es->s_want_extra_isize))
+ sbi->s_want_extra_isize =
+ le16_to_cpu(es->s_want_extra_isize);
+ if (sbi->s_want_extra_isize <
+ le16_to_cpu(es->s_min_extra_isize))
+ sbi->s_want_extra_isize =
+ le16_to_cpu(es->s_min_extra_isize);
+ }
+ }
+ /* Check if enough inode space is available */
+ if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
+ sbi->s_inode_size) {
+ sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ printk(KERN_INFO "EXT4-fs: required extra inode space not"
+ "available.\n");
+ }
+
/*
* akpm: core read_super() calls in here with the superblock locked.
* That deadlocks, because orphan cleanup needs to lock the superblock
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e832e96..b10d68f 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -66,13 +66,6 @@
#define BFIRST(bh) ENTRY(BHDR(bh)+1)
#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
-#define IHDR(inode, raw_inode) \
- ((struct ext4_xattr_ibody_header *) \
- ((void *)raw_inode + \
- EXT4_GOOD_OLD_INODE_SIZE + \
- EXT4_I(inode)->i_extra_isize))
-#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
-
#ifdef EXT4_XATTR_DEBUG
# define ea_idebug(inode, f...) do { \
printk(KERN_DEBUG "inode %s:%lu: ", \
@@ -508,6 +501,24 @@
return;
}
+/*
+ * Find the available free space for EAs. This also returns the total number of
+ * bytes used by EA entries.
+ */
+static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
+ size_t *min_offs, void *base, int *total)
+{
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ *total += EXT4_XATTR_LEN(last->e_name_len);
+ if (!last->e_value_block && last->e_value_size) {
+ size_t offs = le16_to_cpu(last->e_value_offs);
+ if (offs < *min_offs)
+ *min_offs = offs;
+ }
+ }
+ return (*min_offs - ((void *)last - base) - sizeof(__u32));
+}
+
struct ext4_xattr_info {
int name_index;
const char *name;
@@ -1013,7 +1024,9 @@
}
if (!error) {
ext4_xattr_update_super_block(handle, inode->i_sb);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
+ if (!value)
+ EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
/*
* The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1067,6 +1080,253 @@
}
/*
+ * Shift the EA entries in the inode to create space for the increased
+ * i_extra_isize.
+ */
+static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
+ int value_offs_shift, void *to,
+ void *from, size_t n, int blocksize)
+{
+ struct ext4_xattr_entry *last = entry;
+ int new_offs;
+
+ /* Adjust the value offsets of the entries */
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ if (!last->e_value_block && last->e_value_size) {
+ new_offs = le16_to_cpu(last->e_value_offs) +
+ value_offs_shift;
+ BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
+ > blocksize);
+ last->e_value_offs = cpu_to_le16(new_offs);
+ }
+ }
+ /* Shift the entries by n bytes */
+ memmove(to, from, n);
+}
+
+/*
+ * Expand an inode by new_extra_isize bytes when EAs are present.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *entry, *last, *first;
+ struct buffer_head *bh = NULL;
+ struct ext4_xattr_ibody_find *is = NULL;
+ struct ext4_xattr_block_find *bs = NULL;
+ char *buffer = NULL, *b_entry_name = NULL;
+ size_t min_offs, free;
+ int total_ino, total_blk;
+ void *base, *start, *end;
+ int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+ int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize;
+
+ down_write(&EXT4_I(inode)->xattr_sem);
+retry:
+ if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return 0;
+ }
+
+ header = IHDR(inode, raw_inode);
+ entry = IFIRST(header);
+
+ /*
+ * Check if enough free space is available in the inode to shift the
+ * entries ahead by new_extra_isize.
+ */
+
+ base = start = entry;
+ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+ min_offs = end - base;
+ last = entry;
+ total_ino = sizeof(struct ext4_xattr_ibody_header);
+
+ free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
+ if (free >= new_extra_isize) {
+ entry = IFIRST(header);
+ ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
+ - new_extra_isize, (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
+ (void *)header, total_ino,
+ inode->i_sb->s_blocksize);
+ EXT4_I(inode)->i_extra_isize = new_extra_isize;
+ error = 0;
+ goto cleanup;
+ }
+
+ /*
+ * Enough free space isn't available in the inode, check if
+ * EA block can hold new_extra_isize bytes.
+ */
+ if (EXT4_I(inode)->i_file_acl) {
+ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ if (!bh)
+ goto cleanup;
+ if (ext4_xattr_check_block(bh)) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+ }
+ base = BHDR(bh);
+ first = BFIRST(bh);
+ end = bh->b_data + bh->b_size;
+ min_offs = end - base;
+ free = ext4_xattr_free_space(first, &min_offs, base,
+ &total_blk);
+ if (free < new_extra_isize) {
+ if (!tried_min_extra_isize && s_min_extra_isize) {
+ tried_min_extra_isize++;
+ new_extra_isize = s_min_extra_isize;
+ brelse(bh);
+ goto retry;
+ }
+ error = -1;
+ goto cleanup;
+ }
+ } else {
+ free = inode->i_sb->s_blocksize;
+ }
+
+ while (new_extra_isize > 0) {
+ size_t offs, size, entry_size;
+ struct ext4_xattr_entry *small_entry = NULL;
+ struct ext4_xattr_info i = {
+ .value = NULL,
+ .value_len = 0,
+ };
+ unsigned int total_size; /* EA entry size + value size */
+ unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
+ unsigned int min_total_size = ~0U;
+
+ is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
+ bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
+ if (!is || !bs) {
+ error = -ENOMEM;
+ goto cleanup;
+ }
+
+ is->s.not_found = -ENODATA;
+ bs->s.not_found = -ENODATA;
+ is->iloc.bh = NULL;
+ bs->bh = NULL;
+
+ last = IFIRST(header);
+ /* Find the entry best suited to be pushed into EA block */
+ entry = NULL;
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ total_size =
+ EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
+ EXT4_XATTR_LEN(last->e_name_len);
+ if (total_size <= free && total_size < min_total_size) {
+ if (total_size < new_extra_isize) {
+ small_entry = last;
+ } else {
+ entry = last;
+ min_total_size = total_size;
+ }
+ }
+ }
+
+ if (entry == NULL) {
+ if (small_entry) {
+ entry = small_entry;
+ } else {
+ if (!tried_min_extra_isize &&
+ s_min_extra_isize) {
+ tried_min_extra_isize++;
+ new_extra_isize = s_min_extra_isize;
+ goto retry;
+ }
+ error = -1;
+ goto cleanup;
+ }
+ }
+ offs = le16_to_cpu(entry->e_value_offs);
+ size = le32_to_cpu(entry->e_value_size);
+ entry_size = EXT4_XATTR_LEN(entry->e_name_len);
+ i.name_index = entry->e_name_index,
+ buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
+ b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
+ if (!buffer || !b_entry_name) {
+ error = -ENOMEM;
+ goto cleanup;
+ }
+ /* Save the entry name and the entry value */
+ memcpy(buffer, (void *)IFIRST(header) + offs,
+ EXT4_XATTR_SIZE(size));
+ memcpy(b_entry_name, entry->e_name, entry->e_name_len);
+ b_entry_name[entry->e_name_len] = '\0';
+ i.name = b_entry_name;
+
+ error = ext4_get_inode_loc(inode, &is->iloc);
+ if (error)
+ goto cleanup;
+
+ error = ext4_xattr_ibody_find(inode, &i, is);
+ if (error)
+ goto cleanup;
+
+ /* Remove the chosen entry from the inode */
+ error = ext4_xattr_ibody_set(handle, inode, &i, is);
+
+ entry = IFIRST(header);
+ if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
+ shift_bytes = new_extra_isize;
+ else
+ shift_bytes = entry_size + size;
+ /* Adjust the offsets and shift the remaining entries ahead */
+ ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
+ shift_bytes, (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
+ (void *)header, total_ino - entry_size,
+ inode->i_sb->s_blocksize);
+
+ extra_isize += shift_bytes;
+ new_extra_isize -= shift_bytes;
+ EXT4_I(inode)->i_extra_isize = extra_isize;
+
+ i.name = b_entry_name;
+ i.value = buffer;
+ i.value_len = cpu_to_le32(size);
+ error = ext4_xattr_block_find(inode, &i, bs);
+ if (error)
+ goto cleanup;
+
+ /* Add entry which was removed from the inode into the block */
+ error = ext4_xattr_block_set(handle, inode, &i, bs);
+ if (error)
+ goto cleanup;
+ kfree(b_entry_name);
+ kfree(buffer);
+ brelse(is->iloc.bh);
+ kfree(is);
+ kfree(bs);
+ }
+ brelse(bh);
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return 0;
+
+cleanup:
+ kfree(b_entry_name);
+ kfree(buffer);
+ if (is)
+ brelse(is->iloc.bh);
+ kfree(is);
+ kfree(bs);
+ brelse(bh);
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return error;
+}
+
+
+
+/*
* ext4_xattr_delete_inode()
*
* Free extended attribute resources associated with this inode. This
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 79432b3..d7f5d6a 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -56,6 +56,13 @@
#define EXT4_XATTR_SIZE(size) \
(((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+#define IHDR(inode, raw_inode) \
+ ((struct ext4_xattr_ibody_header *) \
+ ((void *)raw_inode + \
+ EXT4_GOOD_OLD_INODE_SIZE + \
+ EXT4_I(inode)->i_extra_isize))
+#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+
# ifdef CONFIG_EXT4DEV_FS_XATTR
extern struct xattr_handler ext4_xattr_user_handler;
@@ -74,6 +81,9 @@
extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
extern void ext4_xattr_put_super(struct super_block *);
+extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle);
+
extern int init_ext4_xattr(void);
extern void exit_ext4_xattr(void);
@@ -129,6 +139,13 @@
{
}
+static inline int
+ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle)
+{
+ return -EOPNOTSUPP;
+}
+
#define ext4_xattr_handlers NULL
# endif /* CONFIG_EXT4DEV_FS_XATTR */
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 78d63b8..f290cb7 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -35,6 +35,7 @@
#include <linux/kthread.h>
#include <linux/poison.h>
#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -528,7 +529,7 @@
{
int err = 0;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
spin_lock(&journal->j_state_lock);
if (!tid_geq(journal->j_commit_request, tid)) {
printk(KERN_EMERG
@@ -1709,7 +1710,7 @@
* Journal_head storage management
*/
static struct kmem_cache *jbd2_journal_head_cache;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
static atomic_t nr_journal_heads = ATOMIC_INIT(0);
#endif
@@ -1747,7 +1748,7 @@
struct journal_head *ret;
static unsigned long last_warning;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
atomic_inc(&nr_journal_heads);
#endif
ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
@@ -1768,7 +1769,7 @@
static void journal_free_journal_head(struct journal_head *jh)
{
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
atomic_dec(&nr_journal_heads);
memset(jh, JBD_POISON_FREE, sizeof(*jh));
#endif
@@ -1951,63 +1952,49 @@
}
/*
- * /proc tunables
+ * debugfs tunables
*/
-#if defined(CONFIG_JBD_DEBUG)
-int jbd2_journal_enable_debug;
+#if defined(CONFIG_JBD2_DEBUG)
+u8 jbd2_journal_enable_debug;
EXPORT_SYMBOL(jbd2_journal_enable_debug);
#endif
-#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
+#if defined(CONFIG_JBD2_DEBUG) && defined(CONFIG_DEBUG_FS)
-static struct proc_dir_entry *proc_jbd_debug;
+#define JBD2_DEBUG_NAME "jbd2-debug"
-static int read_jbd_debug(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+struct dentry *jbd2_debugfs_dir, *jbd2_debug;
+
+static void __init jbd2_create_debugfs_entry(void)
{
- int ret;
-
- ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
- *eof = 1;
- return ret;
+ jbd2_debugfs_dir = debugfs_create_dir("jbd2", NULL);
+ if (jbd2_debugfs_dir)
+ jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME, S_IRUGO,
+ jbd2_debugfs_dir,
+ &jbd2_journal_enable_debug);
}
-static int write_jbd_debug(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static void __exit jbd2_remove_debugfs_entry(void)
{
- char buf[32];
-
- if (count > ARRAY_SIZE(buf) - 1)
- count = ARRAY_SIZE(buf) - 1;
- if (copy_from_user(buf, buffer, count))
- return -EFAULT;
- buf[ARRAY_SIZE(buf) - 1] = '\0';
- jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
- return count;
-}
-
-#define JBD_PROC_NAME "sys/fs/jbd2-debug"
-
-static void __init create_jbd_proc_entry(void)
-{
- proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
- if (proc_jbd_debug) {
- /* Why is this so hard? */
- proc_jbd_debug->read_proc = read_jbd_debug;
- proc_jbd_debug->write_proc = write_jbd_debug;
- }
-}
-
-static void __exit jbd2_remove_jbd_proc_entry(void)
-{
- if (proc_jbd_debug)
- remove_proc_entry(JBD_PROC_NAME, NULL);
+ if (jbd2_debug)
+ debugfs_remove(jbd2_debug);
+ if (jbd2_debugfs_dir)
+ debugfs_remove(jbd2_debugfs_dir);
}
#else
-#define create_jbd_proc_entry() do {} while (0)
-#define jbd2_remove_jbd_proc_entry() do {} while (0)
+static void __init jbd2_create_debugfs_entry(void)
+{
+ do {
+ } while (0);
+}
+
+static void __exit jbd2_remove_debugfs_entry(void)
+{
+ do {
+ } while (0);
+}
#endif
@@ -2067,18 +2054,18 @@
ret = journal_init_caches();
if (ret != 0)
jbd2_journal_destroy_caches();
- create_jbd_proc_entry();
+ jbd2_create_debugfs_entry();
return ret;
}
static void __exit journal_exit(void)
{
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
int n = atomic_read(&nr_journal_heads);
if (n)
printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
#endif
- jbd2_remove_jbd_proc_entry();
+ jbd2_remove_debugfs_entry();
jbd2_journal_destroy_caches();
}
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 395c92a..e7730a0 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -295,7 +295,7 @@
printk(KERN_ERR "JBD: error %d scanning journal\n", err);
++journal->j_transaction_sequence;
} else {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
#endif
jbd_debug(0,
diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
index 352eb4a..c4c3617 100644
--- a/fs/ocfs2/heartbeat.c
+++ b/fs/ocfs2/heartbeat.c
@@ -209,7 +209,7 @@
envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[2] = NULL;
- ret = call_usermodehelper(argv[0], argv, envp, 1);
+ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
if (ret < 0)
mlog_errno(ret);
}
diff --git a/fs/open.c b/fs/open.c
index be6a457..a6b054e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -26,6 +26,7 @@
#include <linux/syscalls.h>
#include <linux/rcupdate.h>
#include <linux/audit.h>
+#include <linux/falloc.h>
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
@@ -352,6 +353,64 @@
}
#endif
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+ struct file *file;
+ struct inode *inode;
+ long ret = -EINVAL;
+
+ if (offset < 0 || len <= 0)
+ goto out;
+
+ /* Return error if mode is not supported */
+ ret = -EOPNOTSUPP;
+ if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
+ goto out;
+
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (!(file->f_mode & FMODE_WRITE))
+ goto out_fput;
+ /*
+ * Revalidate the write permissions, in case security policy has
+ * changed since the files were opened.
+ */
+ ret = security_file_permission(file, MAY_WRITE);
+ if (ret)
+ goto out_fput;
+
+ inode = file->f_path.dentry->d_inode;
+
+ ret = -ESPIPE;
+ if (S_ISFIFO(inode->i_mode))
+ goto out_fput;
+
+ ret = -ENODEV;
+ /*
+ * Let individual file system decide if it supports preallocation
+ * for directories or not.
+ */
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ goto out_fput;
+
+ ret = -EFBIG;
+ /* Check for wrap through zero too */
+ if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
+ goto out_fput;
+
+ if (inode->i_op && inode->i_op->fallocate)
+ ret = inode->i_op->fallocate(inode, mode, offset, len);
+ else
+ ret = -ENOSYS;
+
+out_fput:
+ fput(file);
+out:
+ return ret;
+}
+
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index 9e15ce0..36f3106 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -41,6 +41,7 @@
extern void fixup_irqs(cpumask_t map);
#endif
+unsigned int do_IRQ(struct pt_regs *regs);
void init_IRQ(void);
void __init native_init_IRQ(void);
diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
index 7f161e7..a90c7a6 100644
--- a/include/asm-i386/mach-default/irq_vectors_limits.h
+++ b/include/asm-i386/mach-default/irq_vectors_limits.h
@@ -1,7 +1,7 @@
#ifndef _ASM_IRQ_VECTORS_LIMITS_H
#define _ASM_IRQ_VECTORS_LIMITS_H
-#ifdef CONFIG_X86_IO_APIC
+#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
# define NR_IRQ_VECTORS NR_IRQS
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index 8198d1c..7eb0b0b 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -32,6 +32,8 @@
#endif
}
+void leave_mm(unsigned long cpu);
+
static inline void switch_mm(struct mm_struct *prev,
struct mm_struct *next,
struct task_struct *tsk)
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index 7f846a7..7df88be 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -52,6 +52,8 @@
/* Basic arch-specific setup */
void (*arch_setup)(void);
char *(*memory_setup)(void);
+ void (*post_allocator_init)(void);
+
void (*init_IRQ)(void);
void (*time_init)(void);
@@ -116,7 +118,7 @@
u64 (*read_tsc)(void);
u64 (*read_pmc)(void);
- u64 (*get_scheduled_cycles)(void);
+ unsigned long long (*sched_clock)(void);
unsigned long (*get_cpu_khz)(void);
/* Segment descriptor handling */
@@ -173,7 +175,7 @@
unsigned long va);
/* Hooks for allocating/releasing pagetable pages */
- void (*alloc_pt)(u32 pfn);
+ void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
void (*alloc_pd)(u32 pfn);
void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
void (*release_pt)(u32 pfn);
@@ -260,6 +262,7 @@
unsigned paravirt_patch_insns(void *site, unsigned len,
const char *start, const char *end);
+int paravirt_disable_iospace(void);
/*
* This generates an indirect call based on the operation type number.
@@ -563,7 +566,10 @@
#define rdtscll(val) (val = paravirt_read_tsc())
-#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
+static inline unsigned long long paravirt_sched_clock(void)
+{
+ return PVOP_CALL0(unsigned long long, sched_clock);
+}
#define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
@@ -669,6 +675,12 @@
}
#endif
+static inline void paravirt_post_allocator_init(void)
+{
+ if (paravirt_ops.post_allocator_init)
+ (*paravirt_ops.post_allocator_init)();
+}
+
static inline void paravirt_pagetable_setup_start(pgd_t *base)
{
if (paravirt_ops.pagetable_setup_start)
@@ -725,9 +737,9 @@
PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
}
-static inline void paravirt_alloc_pt(unsigned pfn)
+static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
{
- PVOP_VCALL1(alloc_pt, pfn);
+ PVOP_VCALL2(alloc_pt, mm, pfn);
}
static inline void paravirt_release_pt(unsigned pfn)
{
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
index d07b7af..f2fc33c 100644
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -7,7 +7,7 @@
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
-#define paravirt_alloc_pt(pfn) do { } while (0)
+#define paravirt_alloc_pt(mm, pfn) do { } while (0)
#define paravirt_alloc_pd(pfn) do { } while (0)
#define paravirt_alloc_pd(pfn) do { } while (0)
#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
@@ -17,13 +17,13 @@
#define pmd_populate_kernel(mm, pmd, pte) \
do { \
- paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT); \
+ paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT); \
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \
} while (0)
#define pmd_populate(mm, pmd, pte) \
do { \
- paravirt_alloc_pt(page_to_pfn(pte)); \
+ paravirt_alloc_pt(mm, page_to_pfn(pte)); \
set_pmd(pmd, __pmd(_PAGE_TABLE + \
((unsigned long long)page_to_pfn(pte) << \
(unsigned long long) PAGE_SHIFT))); \
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index 0d5bff9..7862fe8 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -81,6 +81,10 @@
extern unsigned long init_pg_tables_end;
+#ifndef CONFIG_PARAVIRT
+#define paravirt_post_allocator_init() do {} while (0)
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 0c71327..1f73bde 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -43,9 +43,12 @@
#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
+extern void set_cpu_sibling_map(int cpu);
+
#ifdef CONFIG_HOTPLUG_CPU
extern void cpu_exit_clear(void);
extern void cpu_uninit(void);
+extern void remove_siblinginfo(int cpu);
#endif
struct smp_ops
@@ -129,6 +132,8 @@
extern void __cpu_die(unsigned int cpu);
extern unsigned int num_processors;
+void __cpuinit smp_store_cpu_info(int id);
+
#endif /* !__ASSEMBLY__ */
#else /* CONFIG_SMP */
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index 153770e..51a713e 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -15,8 +15,38 @@
extern int recalibrate_cpu_khz(void);
#ifndef CONFIG_PARAVIRT
-#define get_scheduled_cycles(val) rdtscll(val)
#define calculate_cpu_khz() native_calculate_cpu_khz()
#endif
+/* Accellerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ * basic equation:
+ * ns = cycles / (freq / ns_per_sec)
+ * ns = cycles * (ns_per_sec / freq)
+ * ns = cycles * (10^9 / (cpu_khz * 10^3))
+ * ns = cycles * (10^6 / cpu_khz)
+ *
+ * Then we use scaling math (suggested by george@mvista.com) to get:
+ * ns = cycles * (10^6 * SC / cpu_khz) / SC
+ * ns = cycles * cyc2ns_scale / SC
+ *
+ * And since SC is a constant power of two, we can convert the div
+ * into a shift.
+ *
+ * We can use khz divisor instead of mhz to keep a better percision, since
+ * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ * (mathieu.desnoyers@polymtl.ca)
+ *
+ * -johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+extern unsigned long cyc2ns_scale __read_mostly;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+ return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+
#endif
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index e84ace1..9b15545 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -329,10 +329,11 @@
#define __NR_signalfd 321
#define __NR_timerfd 322
#define __NR_eventfd 323
+#define __NR_fallocate 324
#ifdef __KERNEL__
-#define NR_syscalls 324
+#define NR_syscalls 325
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/vmi_time.h b/include/asm-i386/vmi_time.h
index 213930b..4781881 100644
--- a/include/asm-i386/vmi_time.h
+++ b/include/asm-i386/vmi_time.h
@@ -49,7 +49,7 @@
extern void __init vmi_time_init(void);
extern unsigned long vmi_get_wallclock(void);
extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_get_sched_cycles(void);
+extern unsigned long long vmi_sched_clock(void);
extern unsigned long vmi_cpu_khz(void);
#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/xen/hypercall.h b/include/asm-i386/xen/hypercall.h
new file mode 100644
index 0000000..bc0ee7d
--- /dev/null
+++ b/include/asm-i386/xen/hypercall.h
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/physdev.h>
+
+extern struct { char _entry[32]; } hypercall_page[];
+
+#define _hypercall0(type, name) \
+({ \
+ long __res; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res) \
+ : [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "1" ((long)(a1)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+static inline int
+HYPERVISOR_set_trap_table(struct trap_info *table)
+{
+ return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(struct mmu_update *req, int count,
+ int *success_count, domid_t domid)
+{
+ return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(struct mmuext_op *op, int count,
+ int *success_count, domid_t domid)
+{
+ return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
+{
+ return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
+{
+ return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(unsigned long event_selector,
+ unsigned long event_address,
+ unsigned long failsafe_selector,
+ unsigned long failsafe_address)
+{
+ return _hypercall4(int, set_callbacks,
+ event_selector, event_address,
+ failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(int set)
+{
+ return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op(int cmd, unsigned long arg)
+{
+ return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline long
+HYPERVISOR_set_timer_op(u64 timeout)
+{
+ unsigned long timeout_hi = (unsigned long)(timeout>>32);
+ unsigned long timeout_lo = (unsigned long)timeout;
+ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+ return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(int reg)
+{
+ return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(u64 ma, u64 desc)
+{
+ return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+
+static inline int
+HYPERVISOR_memory_op(unsigned int cmd, void *arg)
+{
+ return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+ return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
+ unsigned long flags)
+{
+ unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+ pte_hi = new_val.pte_high;
+#endif
+ return _hypercall4(int, update_va_mapping, va,
+ new_val.pte_low, pte_hi, flags);
+}
+
+static inline int
+HYPERVISOR_event_channel_op(int cmd, void *arg)
+{
+ int rc = _hypercall2(int, event_channel_op, cmd, arg);
+ if (unlikely(rc == -ENOSYS)) {
+ struct evtchn_op op;
+ op.cmd = cmd;
+ memcpy(&op.u, arg, sizeof(op.u));
+ rc = _hypercall1(int, event_channel_op_compat, &op);
+ memcpy(arg, &op.u, sizeof(op.u));
+ }
+ return rc;
+}
+
+static inline int
+HYPERVISOR_xen_version(int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(int cmd, int count, char *str)
+{
+ return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(int cmd, void *arg)
+{
+ int rc = _hypercall2(int, physdev_op, cmd, arg);
+ if (unlikely(rc == -ENOSYS)) {
+ struct physdev_op op;
+ op.cmd = cmd;
+ memcpy(&op.u, arg, sizeof(op.u));
+ rc = _hypercall1(int, physdev_op_compat, &op);
+ memcpy(arg, &op.u, sizeof(op.u));
+ }
+ return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+{
+ return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val,
+ unsigned long flags, domid_t domid)
+{
+ unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+ pte_hi = new_val.pte_high;
+#endif
+ return _hypercall5(int, update_va_mapping_otherdomain, va,
+ new_val.pte_low, pte_hi, flags, domid);
+}
+
+static inline int
+HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
+{
+ return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
+{
+ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(unsigned long srec)
+{
+ return _hypercall3(int, sched_op, SCHEDOP_shutdown,
+ SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
+{
+ return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+ pte_t new_val, unsigned long flags)
+{
+ mcl->op = __HYPERVISOR_update_va_mapping;
+ mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = new_val.pte_high;
+#else
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = 0;
+#endif
+ mcl->args[3] = flags;
+}
+
+static inline void
+MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
+ void *uop, unsigned int count)
+{
+ mcl->op = __HYPERVISOR_grant_table_op;
+ mcl->args[0] = cmd;
+ mcl->args[1] = (unsigned long)uop;
+ mcl->args[2] = count;
+}
+
+static inline void
+MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
+ pte_t new_val, unsigned long flags,
+ domid_t domid)
+{
+ mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = new_val.pte_high;
+#else
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = 0;
+#endif
+ mcl->args[3] = flags;
+ mcl->args[4] = domid;
+}
+
+static inline void
+MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
+ struct desc_struct desc)
+{
+ mcl->op = __HYPERVISOR_update_descriptor;
+ mcl->args[0] = maddr;
+ mcl->args[1] = maddr >> 32;
+ mcl->args[2] = desc.a;
+ mcl->args[3] = desc.b;
+}
+
+static inline void
+MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
+{
+ mcl->op = __HYPERVISOR_memory_op;
+ mcl->args[0] = cmd;
+ mcl->args[1] = (unsigned long)arg;
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+ int count, int *success_count, domid_t domid)
+{
+ mcl->op = __HYPERVISOR_mmu_update;
+ mcl->args[0] = (unsigned long)req;
+ mcl->args[1] = count;
+ mcl->args[2] = (unsigned long)success_count;
+ mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
+ int *success_count, domid_t domid)
+{
+ mcl->op = __HYPERVISOR_mmuext_op;
+ mcl->args[0] = (unsigned long)op;
+ mcl->args[1] = count;
+ mcl->args[2] = (unsigned long)success_count;
+ mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
+{
+ mcl->op = __HYPERVISOR_set_gdt;
+ mcl->args[0] = (unsigned long)frames;
+ mcl->args[1] = entries;
+}
+
+static inline void
+MULTI_stack_switch(struct multicall_entry *mcl,
+ unsigned long ss, unsigned long esp)
+{
+ mcl->op = __HYPERVISOR_stack_switch;
+ mcl->args[0] = ss;
+ mcl->args[1] = esp;
+}
+
+#endif /* __HYPERCALL_H__ */
diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-i386/xen/hypervisor.h
new file mode 100644
index 0000000..8e15dd2
--- /dev/null
+++ b/include/asm-i386/xen/hypervisor.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * hypervisor.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERVISOR_H__
+#define __HYPERVISOR_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/desc.h>
+#if defined(__i386__)
+# ifdef CONFIG_X86_PAE
+# include <asm-generic/pgtable-nopud.h>
+# else
+# include <asm-generic/pgtable-nopmd.h>
+# endif
+#endif
+#include <asm/xen/hypercall.h>
+
+/* arch/i386/kernel/setup.c */
+extern struct shared_info *HYPERVISOR_shared_info;
+extern struct start_info *xen_start_info;
+#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
+
+/* arch/i386/mach-xen/evtchn.c */
+/* Force a proper event-channel callback from Xen. */
+extern void force_evtchn_callback(void);
+
+/* Turn jiffies into Xen system time. */
+u64 jiffies_to_st(unsigned long jiffies);
+
+
+#define MULTI_UVMFLAGS_INDEX 3
+#define MULTI_UVMDOMID_INDEX 4
+
+#define is_running_on_xen() (xen_start_info ? 1 : 0)
+
+#endif /* __HYPERVISOR_H__ */
diff --git a/include/asm-i386/xen/interface.h b/include/asm-i386/xen/interface.h
new file mode 100644
index 0000000..165c396
--- /dev/null
+++ b/include/asm-i386/xen/interface.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * arch-x86_32.h
+ *
+ * Guest OS interface to x86 32-bit Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_32_H__
+#define __XEN_PUBLIC_ARCH_X86_32_H__
+
+#ifdef __XEN__
+#define __DEFINE_GUEST_HANDLE(name, type) \
+ typedef struct { type *p; } __guest_handle_ ## name
+#else
+#define __DEFINE_GUEST_HANDLE(name, type) \
+ typedef type * __guest_handle_ ## name
+#endif
+
+#define DEFINE_GUEST_HANDLE_STRUCT(name) \
+ __DEFINE_GUEST_HANDLE(name, struct name)
+#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
+#define GUEST_HANDLE(name) __guest_handle_ ## name
+
+#ifndef __ASSEMBLY__
+/* Guest handles for primitive C types. */
+__DEFINE_GUEST_HANDLE(uchar, unsigned char);
+__DEFINE_GUEST_HANDLE(uint, unsigned int);
+__DEFINE_GUEST_HANDLE(ulong, unsigned long);
+DEFINE_GUEST_HANDLE(char);
+DEFINE_GUEST_HANDLE(int);
+DEFINE_GUEST_HANDLE(long);
+DEFINE_GUEST_HANDLE(void);
+#endif
+
+/*
+ * SEGMENT DESCRIPTOR TABLES
+ */
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ */
+#define FIRST_RESERVED_GDT_PAGE 14
+#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
+
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
+
+#define FLAT_KERNEL_CS FLAT_RING1_CS
+#define FLAT_KERNEL_DS FLAT_RING1_DS
+#define FLAT_KERNEL_SS FLAT_RING1_SS
+#define FLAT_USER_CS FLAT_RING3_CS
+#define FLAT_USER_DS FLAT_RING3_DS
+#define FLAT_USER_SS FLAT_RING3_SS
+
+/* And the trap vector is... */
+#define TRAP_INSTR "int $0x82"
+
+/*
+ * Virtual addresses beyond this are not modifiable by guest OSes. The
+ * machine->physical mapping table starts at this address, read-only.
+ */
+#ifdef CONFIG_X86_PAE
+#define __HYPERVISOR_VIRT_START 0xF5800000
+#else
+#define __HYPERVISOR_VIRT_START 0xFC000000
+#endif
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
+#endif
+
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#endif
+
+/* Maximum number of virtual CPUs in multi-processor guests. */
+#define MAX_VIRT_CPUS 32
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table()
+ */
+#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
+#define TI_GET_IF(_ti) ((_ti)->flags & 4)
+#define TI_SET_DPL(_ti, _dpl) ((_ti)->flags |= (_dpl))
+#define TI_SET_IF(_ti, _if) ((_ti)->flags |= ((!!(_if))<<2))
+
+struct trap_info {
+ uint8_t vector; /* exception vector */
+ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
+ uint16_t cs; /* code selector */
+ unsigned long address; /* code offset */
+};
+DEFINE_GUEST_HANDLE_STRUCT(trap_info);
+
+struct cpu_user_regs {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint16_t error_code; /* private */
+ uint16_t entry_vector; /* private */
+ uint32_t eip;
+ uint16_t cs;
+ uint8_t saved_upcall_mask;
+ uint8_t _pad0;
+ uint32_t eflags; /* eflags.IF == !saved_upcall_mask */
+ uint32_t esp;
+ uint16_t ss, _pad1;
+ uint16_t es, _pad2;
+ uint16_t ds, _pad3;
+ uint16_t fs, _pad4;
+ uint16_t gs, _pad5;
+};
+DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
+
+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
+
+/*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+ */
+struct vcpu_guest_context {
+ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
+ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
+#define VGCF_I387_VALID (1<<0)
+#define VGCF_HVM_GUEST (1<<1)
+#define VGCF_IN_KERNEL (1<<2)
+ unsigned long flags; /* VGCF_* flags */
+ struct cpu_user_regs user_regs; /* User-level CPU registers */
+ struct trap_info trap_ctxt[256]; /* Virtual IDT */
+ unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
+ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
+ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
+ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
+ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
+ unsigned long event_callback_cs; /* CS:EIP of event callback */
+ unsigned long event_callback_eip;
+ unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
+ unsigned long failsafe_callback_eip;
+ unsigned long vm_assist; /* VMASST_TYPE_* bitmap */
+};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context);
+
+struct arch_shared_info {
+ unsigned long max_pfn; /* max pfn that appears in table */
+ /* Frame containing list of mfns containing list of mfns containing p2m. */
+ unsigned long pfn_to_mfn_frame_list_list;
+ unsigned long nmi_reason;
+};
+
+struct arch_vcpu_info {
+ unsigned long cr2;
+ unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
+};
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Prefix forces emulation of some non-trapping instructions.
+ * Currently only CPUID.
+ */
+#ifdef __ASSEMBLY__
+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
+#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
+#else
+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
+#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
+#endif
+
+#endif
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 1cc3f9c..cc6d872 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -308,6 +308,7 @@
SYSCALL_SPU(getcpu)
COMPAT_SYS(epoll_pwait)
COMPAT_SYS_SPU(utimensat)
+COMPAT_SYS(fallocate)
COMPAT_SYS_SPU(signalfd)
COMPAT_SYS_SPU(timerfd)
SYSCALL_SPU(eventfd)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index f71c606..97d82b6 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -331,10 +331,11 @@
#define __NR_timerfd 306
#define __NR_eventfd 307
#define __NR_sync_file_range2 308
+#define __NR_fallocate 309
#ifdef __KERNEL__
-#define __NR_syscalls 309
+#define __NR_syscalls 310
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index ad595b6..9565a89 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -14,11 +14,6 @@
#define __SLOW_DOWN_IO do { } while (0)
#define SLOW_DOWN_IO do { } while (0)
-extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
-#define virt_to_bus virt_to_bus_not_defined_use_pci_map
-extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
-#define bus_to_virt bus_to_virt_not_defined_use_pci_map
-
/* BIO layer definitions. */
extern unsigned long kern_base, kern_size;
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
diff --git a/include/asm-sparc64/mdesc.h b/include/asm-sparc64/mdesc.h
index e97c431..1acc727 100644
--- a/include/asm-sparc64/mdesc.h
+++ b/include/asm-sparc64/mdesc.h
@@ -61,6 +61,16 @@
extern void mdesc_update(void);
+struct mdesc_notifier_client {
+ void (*add)(struct mdesc_handle *handle, u64 node);
+ void (*remove)(struct mdesc_handle *handle, u64 node);
+
+ const char *node_name;
+ struct mdesc_notifier_client *next;
+};
+
+extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
+
extern void mdesc_fill_in_cpu_data(cpumask_t mask);
extern void sun4v_mdesc_init(void);
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
index 83c9642..c0a8d4e 100644
--- a/include/asm-sparc64/vio.h
+++ b/include/asm-sparc64/vio.h
@@ -264,7 +264,7 @@
((dr->prod - dr->cons) & (ring_size - 1)));
}
-#define VIO_MAX_TYPE_LEN 64
+#define VIO_MAX_TYPE_LEN 32
#define VIO_MAX_COMPAT_LEN 64
struct vio_dev {
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 8696f8a..fc4e73f 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -630,6 +630,8 @@
__SYSCALL(__NR_timerfd, sys_timerfd)
#define __NR_eventfd 284
__SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_fallocate 285
+__SYSCALL(__NR_fallocate, sys_fallocate)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h
index 9a1e067..e831759 100644
--- a/include/linux/elfnote.h
+++ b/include/linux/elfnote.h
@@ -38,17 +38,25 @@
* e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
* ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
*/
-#define ELFNOTE(name, type, desctype, descdata) \
-.pushsection .note.name, "",@note ; \
- .align 4 ; \
+#define ELFNOTE_START(name, type, flags) \
+.pushsection .note.name, flags,@note ; \
+ .balign 4 ; \
.long 2f - 1f /* namesz */ ; \
- .long 4f - 3f /* descsz */ ; \
+ .long 4484f - 3f /* descsz */ ; \
.long type ; \
1:.asciz #name ; \
-2:.align 4 ; \
-3:desctype descdata ; \
-4:.align 4 ; \
+2:.balign 4 ; \
+3:
+
+#define ELFNOTE_END \
+4484:.balign 4 ; \
.popsection ;
+
+#define ELFNOTE(name, type, desc) \
+ ELFNOTE_START(name, type, "") \
+ desc ; \
+ ELFNOTE_END
+
#else /* !__ASSEMBLER__ */
#include <linux/elf.h>
/*
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index de1f9f7..cdee7aa 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -71,7 +71,7 @@
/*
* Maximal count of links to a file
*/
-#define EXT4_LINK_MAX 32000
+#define EXT4_LINK_MAX 65000
/*
* Macro-instructions used to manage several block sizes
@@ -102,6 +102,7 @@
EXT4_GOOD_OLD_FIRST_INO : \
(s)->s_first_ino)
#endif
+#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
/*
* Macro-instructions used to manage fragments
@@ -201,6 +202,7 @@
#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */
#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */
#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */
+#define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */
/* Used to pass group descriptor data when online resize is done */
struct ext4_new_group_input {
@@ -225,6 +227,11 @@
__u32 free_blocks_count;
};
+/*
+ * Following is used by preallocation code to tell get_blocks() that we
+ * want uninitialzed extents.
+ */
+#define EXT4_CREATE_UNINITIALIZED_EXT 2
/*
* ioctl commands
@@ -237,7 +244,7 @@
#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
#endif
#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
@@ -253,7 +260,7 @@
#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
#endif
#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
@@ -282,7 +289,7 @@
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
- __le32 i_ctime; /* Creation time */
+ __le32 i_ctime; /* Inode Change time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
@@ -331,10 +338,85 @@
} osd2; /* OS dependent 2 */
__le16 i_extra_isize;
__le16 i_pad1;
+ __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
+ __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
+ __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
+ __le32 i_crtime; /* File Creation time */
+ __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
};
#define i_size_high i_dir_acl
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
+
+/*
+ * Extended fields will fit into an inode if the filesystem was formatted
+ * with large inodes (-I 256 or larger) and there are not currently any EAs
+ * consuming all of the available space. For new inodes we always reserve
+ * enough space for the kernel's known extended fields, but for inodes
+ * created with an old kernel this might not have been the case. None of
+ * the extended inode fields is critical for correct filesystem operation.
+ * This macro checks if a certain field fits in the inode. Note that
+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
+ */
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) \
+ ((offsetof(typeof(*ext4_inode), field) + \
+ sizeof((ext4_inode)->field)) \
+ <= (EXT4_GOOD_OLD_INODE_SIZE + \
+ (einode)->i_extra_isize)) \
+
+static inline __le32 ext4_encode_extra_time(struct timespec *time)
+{
+ return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
+ time->tv_sec >> 32 : 0) |
+ ((time->tv_nsec << 2) & EXT4_NSEC_MASK));
+}
+
+static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+{
+ if (sizeof(time->tv_sec) > 4)
+ time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
+ << 32;
+ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 2;
+}
+
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(inode)->xtime); \
+} while (0)
+
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(einode)->xtime); \
+} while (0)
+
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
+ ext4_decode_extra_time(&(inode)->xtime, \
+ raw_inode->xtime ## _extra); \
+} while (0)
+
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (einode)->xtime.tv_sec = \
+ (signed)le32_to_cpu((raw_inode)->xtime); \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ ext4_decode_extra_time(&(einode)->xtime, \
+ raw_inode->xtime ## _extra); \
+} while (0)
+
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
@@ -533,6 +615,13 @@
return container_of(inode, struct ext4_inode_info, vfs_inode);
}
+static inline struct timespec ext4_current_time(struct inode *inode)
+{
+ return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
+ current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
+}
+
+
static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
{
return ino == EXT4_ROOT_INO ||
@@ -603,6 +692,8 @@
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
@@ -620,6 +711,8 @@
EXT4_FEATURE_INCOMPAT_64BIT)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
/*
@@ -862,6 +955,7 @@
extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
extern void ext4_truncate (struct inode *);
extern void ext4_set_inode_flags(struct inode *);
+extern void ext4_get_inode_flags(struct ext4_inode_info *);
extern void ext4_set_aops(struct inode *inode);
extern int ext4_writepage_trans_blocks(struct inode *);
extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
@@ -983,6 +1077,8 @@
extern void ext4_ext_truncate(struct inode *, struct page *);
extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *);
+extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
+ loff_t len);
static inline int
ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h
index acfe5974..81406f3 100644
--- a/include/linux/ext4_fs_extents.h
+++ b/include/linux/ext4_fs_extents.h
@@ -141,7 +141,25 @@
#define EXT_MAX_BLOCK 0xffffffff
-#define EXT_MAX_LEN ((1UL << 15) - 1)
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN (1UL << 15)
+#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1)
#define EXT_FIRST_EXTENT(__hdr__) \
@@ -188,8 +206,31 @@
EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
}
+static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
+{
+ /* We can not have an uninitialized extent of zero length! */
+ BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
+ ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
+{
+ /* Extent with ee_len of 0x8000 is treated as an initialized extent */
+ return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
+{
+ return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
+ le16_to_cpu(ext->ee_len) :
+ (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
+}
+
extern int ext4_extent_tree_init(handle_t *, struct inode *);
extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
+extern int ext4_ext_try_to_merge(struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *);
extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
index 9de4944..1a511e99 100644
--- a/include/linux/ext4_fs_i.h
+++ b/include/linux/ext4_fs_i.h
@@ -153,6 +153,11 @@
unsigned long i_ext_generation;
struct ext4_ext_cache i_cached_extent;
+ /*
+ * File creation time. Its function is same as that of
+ * struct timespec i_{a,c,m}time in the generic inode.
+ */
+ struct timespec i_crtime;
};
#endif /* _LINUX_EXT4_FS_I */
diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h
index 2347557..1b2ffee 100644
--- a/include/linux/ext4_fs_sb.h
+++ b/include/linux/ext4_fs_sb.h
@@ -73,7 +73,7 @@
struct list_head s_orphan;
unsigned long s_commit_interval;
struct block_device *journal_bdev;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
#endif
@@ -81,6 +81,7 @@
char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
int s_jquota_fmt; /* Format of quota to use */
#endif
+ unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
#ifdef EXTENTS_STATS
/* ext4 extents stats */
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
new file mode 100644
index 0000000..8e912ab
--- /dev/null
+++ b/include/linux/falloc.h
@@ -0,0 +1,6 @@
+#ifndef _FALLOC_H_
+#define _FALLOC_H_
+
+#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */
+
+#endif /* _FALLOC_H_ */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 98205f6..0b806c5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1147,6 +1147,8 @@
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
+ long (*fallocate)(struct inode *inode, int mode, loff_t offset,
+ loff_t len);
};
struct seq_file;
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 0e0fedd..260d6d7 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -50,14 +50,14 @@
*/
#define JBD_DEFAULT_MAX_COMMIT_AGE 5
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
/*
* Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
* consistency checks. By default we don't do this unless
- * CONFIG_JBD_DEBUG is on.
+ * CONFIG_JBD2_DEBUG is on.
*/
#define JBD_EXPENSIVE_CHECKING
-extern int jbd2_journal_enable_debug;
+extern u8 jbd2_journal_enable_debug;
#define jbd_debug(n, f, a...) \
do { \
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 10f505c..5dc1384 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -36,13 +36,57 @@
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
struct key;
-extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
- struct key *session_keyring, int wait);
+struct file;
+struct subprocess_info;
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+ char **argv, char **envp);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+ struct key *session_keyring);
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+ struct file **filp);
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+ void (*cleanup)(char **argv, char **envp));
+
+enum umh_wait {
+ UMH_NO_WAIT = -1, /* don't wait at all */
+ UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
+ UMH_WAIT_PROC = 1, /* wait for the process to complete */
+};
+
+/* Actually execute the sub-process */
+int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+
+/* Free the subprocess_info. This is only needed if you're not going
+ to call call_usermodehelper_exec */
+void call_usermodehelper_freeinfo(struct subprocess_info *info);
static inline int
-call_usermodehelper(char *path, char **argv, char **envp, int wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
{
- return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+ struct subprocess_info *info;
+
+ info = call_usermodehelper_setup(path, argv, envp);
+ if (info == NULL)
+ return -ENOMEM;
+ return call_usermodehelper_exec(info, wait);
+}
+
+static inline int
+call_usermodehelper_keys(char *path, char **argv, char **envp,
+ struct key *session_keyring, enum umh_wait wait)
+{
+ struct subprocess_info *info;
+
+ info = call_usermodehelper_setup(path, argv, envp);
+ if (info == NULL)
+ return -ENOMEM;
+
+ call_usermodehelper_setkeys(info, session_keyring);
+ return call_usermodehelper_exec(info, wait);
}
extern void usermodehelper_init(void);
diff --git a/include/linux/major.h b/include/linux/major.h
index 7e7c909..0cb9805 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -158,6 +158,8 @@
#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */
#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */
+#define XENVBD_MAJOR 202 /* Xen virtual block device */
+
#define MSR_MAJOR 202
#define CPUID_MAJOR 203
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index da7a13c..9820ca1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1098,10 +1098,8 @@
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
extern int dev_mc_sync(struct net_device *to, struct net_device *from);
extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
-extern void dev_mc_discard(struct net_device *dev);
extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
-extern void __dev_addr_discard(struct dev_addr_list **list);
extern void dev_set_promiscuity(struct net_device *dev, int inc);
extern void dev_set_allmulti(struct net_device *dev, int inc);
extern void netdev_state_change(struct net_device *dev);
diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h
index 34ab0fb..a92fefc 100644
--- a/include/linux/netfilter_ipv4/ipt_iprange.h
+++ b/include/linux/netfilter_ipv4/ipt_iprange.h
@@ -1,6 +1,8 @@
#ifndef _IPT_IPRANGE_H
#define _IPT_IPRANGE_H
+#include <linux/types.h>
+
#define IPRANGE_SRC 0x01 /* Match source IP address */
#define IPRANGE_DST 0x02 /* Match destination IP address */
#define IPRANGE_SRC_INV 0x10 /* Negate the condition */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index ae2d79f..731cd2a 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -92,6 +92,7 @@
/* PG_owner_priv_1 users should have descriptive aliases */
#define PG_checked PG_owner_priv_1 /* Used by some filesystems */
+#define PG_pinned PG_owner_priv_1 /* Xen pinned pagetable */
#if (BITS_PER_LONG > 32)
/*
@@ -170,6 +171,10 @@
#define SetPageChecked(page) set_bit(PG_checked, &(page)->flags)
#define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags)
+#define PagePinned(page) test_bit(PG_pinned, &(page)->flags)
+#define SetPagePinned(page) set_bit(PG_pinned, &(page)->flags)
+#define ClearPagePinned(page) clear_bit(PG_pinned, &(page)->flags)
+
#define PageReserved(page) test_bit(PG_reserved, &(page)->flags)
#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags)
#define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags)
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 1dd1c70..85ea63f 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -67,6 +67,11 @@
void ctrl_alt_del(void);
+#define POWEROFF_CMD_PATH_LEN 256
+extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
+
+extern int orderly_poweroff(bool force);
+
/*
* Emergency restart, callable from an interrupt handler.
*/
diff --git a/include/linux/string.h b/include/linux/string.h
index 7f2eb6a..836062b 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -105,8 +105,12 @@
#endif
extern char *kstrdup(const char *s, gfp_t gfp);
+extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
+extern void argv_free(char **argv);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 83d0ec1..7a8b1e3 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -610,6 +610,7 @@
asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
const struct itimerspec __user *utmr);
asmlinkage long sys_eventfd(unsigned int count);
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 132b260..c2b10ca 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -70,6 +70,10 @@
struct page ***pages);
extern void unmap_kernel_range(unsigned long addr, unsigned long size);
+/* Allocate/destroy a 'vmalloc' VM area. */
+extern struct vm_struct *alloc_vm_area(size_t size);
+extern void free_vm_area(struct vm_struct *area);
+
/*
* Internals. Dont't use..
*/
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index d3f4f5a..6770324 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -114,7 +114,7 @@
struct mutex lock;
unsigned char __iomem *mem; /* pointer to mapped IO memory */
- int revision; /* chip revision; needed for bug-workarounds*/
+ u32 revision; /* chip revision; needed for bug-workarounds*/
/* pci-device & irq stuff*/
char name[32];
@@ -157,8 +157,8 @@
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt);
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 6dcf3c4..160381c 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -23,8 +23,6 @@
#define _TUNER_H
#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/tuner-types.h>
extern int tuner_debug;
@@ -124,6 +122,7 @@
#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */
#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */
#define TUNER_TDA9887 74 /* This tuner should be used only internally */
+#define TUNER_TEA5761 75 /* Only FM Radio Tuner */
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
@@ -182,74 +181,6 @@
int (*tuner_callback) (void *dev, int command,int arg);
};
-struct tuner {
- /* device */
- struct i2c_client i2c;
-
- unsigned int type; /* chip type */
-
- unsigned int mode;
- unsigned int mode_mask; /* Combination of allowable modes */
-
- unsigned int tv_freq; /* keep track of the current settings */
- unsigned int radio_freq;
- u16 last_div;
- unsigned int audmode;
- v4l2_std_id std;
-
- int using_v4l2;
-
- /* used by tda9887 */
- unsigned int tda9887_config;
- unsigned char tda9887_data[4];
-
- /* used by MT2032 */
- unsigned int xogc;
- unsigned int radio_if2;
-
- /* used by tda8290 */
- unsigned char tda8290_easy_mode;
- unsigned char tda827x_lpsel;
- unsigned char tda827x_addr;
- unsigned char tda827x_ver;
- unsigned int sgIF;
-
- unsigned int config;
- int (*tuner_callback) (void *dev, int command,int arg);
-
- /* function ptrs */
- void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
- void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
- int (*has_signal)(struct i2c_client *c);
- int (*is_stereo)(struct i2c_client *c);
- int (*get_afc)(struct i2c_client *c);
- void (*tuner_status)(struct i2c_client *c);
- void (*standby)(struct i2c_client *c);
-};
-
-extern unsigned const int tuner_count;
-
-extern int microtune_init(struct i2c_client *c);
-extern int xc3028_init(struct i2c_client *c);
-extern int tda8290_init(struct i2c_client *c);
-extern int tda8290_probe(struct i2c_client *c);
-extern int tea5767_tuner_init(struct i2c_client *c);
-extern int default_tuner_init(struct i2c_client *c);
-extern int tea5767_autodetection(struct i2c_client *c);
-extern int tda9887_tuner_init(struct i2c_client *c);
-
-#define tuner_warn(fmt, arg...) do {\
- printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
- printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
- extern int tuner_debug; \
- if (tuner_debug) \
- printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
#endif /* __KERNEL__ */
#endif /* _TUNER_H */
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h
index fa479c7..74efa77 100644
--- a/include/mtd/ubi-header.h
+++ b/include/mtd/ubi-header.h
@@ -74,42 +74,13 @@
UBI_COMPAT_REJECT = 5
};
-/*
- * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
- * data structures.
- */
-typedef struct {
- uint16_t int16;
-} __attribute__ ((packed)) ubi16_t;
-
-typedef struct {
- uint32_t int32;
-} __attribute__ ((packed)) ubi32_t;
-
-typedef struct {
- uint64_t int64;
-} __attribute__ ((packed)) ubi64_t;
-
-/*
- * In this implementation of UBI uses the big-endian format for on-flash
- * integers. The below are the corresponding conversion macros.
- */
-#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
-#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
-
-#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
-#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
-
-#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
-#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
-
/* Sizes of UBI headers */
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
/* Sizes of UBI headers without the ending CRC */
-#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t))
-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
/**
* struct ubi_ec_hdr - UBI erase counter header.
@@ -137,14 +108,14 @@
* eraseblocks.
*/
struct ubi_ec_hdr {
- ubi32_t magic;
- uint8_t version;
- uint8_t padding1[3];
- ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
- ubi32_t vid_hdr_offset;
- ubi32_t data_offset;
- uint8_t padding2[36];
- ubi32_t hdr_crc;
+ __be32 magic;
+ __u8 version;
+ __u8 padding1[3];
+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */
+ __be32 vid_hdr_offset;
+ __be32 data_offset;
+ __u8 padding2[36];
+ __be32 hdr_crc;
} __attribute__ ((packed));
/**
@@ -262,22 +233,22 @@
* software (say, cramfs) on top of the UBI volume.
*/
struct ubi_vid_hdr {
- ubi32_t magic;
- uint8_t version;
- uint8_t vol_type;
- uint8_t copy_flag;
- uint8_t compat;
- ubi32_t vol_id;
- ubi32_t lnum;
- ubi32_t leb_ver; /* obsolete, to be removed, don't use */
- ubi32_t data_size;
- ubi32_t used_ebs;
- ubi32_t data_pad;
- ubi32_t data_crc;
- uint8_t padding1[4];
- ubi64_t sqnum;
- uint8_t padding2[12];
- ubi32_t hdr_crc;
+ __be32 magic;
+ __u8 version;
+ __u8 vol_type;
+ __u8 copy_flag;
+ __u8 compat;
+ __be32 vol_id;
+ __be32 lnum;
+ __be32 leb_ver; /* obsolete, to be removed, don't use */
+ __be32 data_size;
+ __be32 used_ebs;
+ __be32 data_pad;
+ __be32 data_crc;
+ __u8 padding1[4];
+ __be64 sqnum;
+ __u8 padding2[12];
+ __be32 hdr_crc;
} __attribute__ ((packed));
/* Internal UBI volumes count */
@@ -306,7 +277,7 @@
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
/* Size of the volume table record without the ending CRC */
-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
/**
* struct ubi_vtbl_record - a record in the volume table.
@@ -346,15 +317,15 @@
* Empty records contain all zeroes and the CRC checksum of those zeroes.
*/
struct ubi_vtbl_record {
- ubi32_t reserved_pebs;
- ubi32_t alignment;
- ubi32_t data_pad;
- uint8_t vol_type;
- uint8_t upd_marker;
- ubi16_t name_len;
- uint8_t name[UBI_VOL_NAME_MAX+1];
- uint8_t padding2[24];
- ubi32_t crc;
+ __be32 reserved_pebs;
+ __be32 alignment;
+ __be32 data_pad;
+ __u8 vol_type;
+ __u8 upd_marker;
+ __be16 name_len;
+ __u8 name[UBI_VOL_NAME_MAX+1];
+ __u8 padding2[24];
+ __be32 crc;
} __attribute__ ((packed));
#endif /* !__UBI_HEADER_H__ */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a8af9ae..8b404b1 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -652,8 +652,7 @@
/* lower bound for congestion window (optional) */
u32 (*min_cwnd)(const struct sock *sk);
/* do new cwnd calculation (required) */
- void (*cong_avoid)(struct sock *sk, u32 ack,
- u32 rtt, u32 in_flight, int good_ack);
+ void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight, int good_ack);
/* call before changing ca_state (optional) */
void (*set_state)(struct sock *sk, u8 new_state);
/* call when cwnd event occurs (optional) */
@@ -684,8 +683,7 @@
extern struct tcp_congestion_ops tcp_init_congestion_ops;
extern u32 tcp_reno_ssthresh(struct sock *sk);
-extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack,
- u32 rtt, u32 in_flight, int flag);
+extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag);
extern u32 tcp_reno_min_cwnd(const struct sock *sk);
extern struct tcp_congestion_ops tcp_reno;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index ae959e9..a5f80bf 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -585,7 +585,6 @@
struct xfrm_dst
{
union {
- struct xfrm_dst *next;
struct dst_entry dst;
struct rtable rt;
struct rt6_info rt6;
diff --git a/include/xen/events.h b/include/xen/events.h
new file mode 100644
index 0000000..2bde54d
--- /dev/null
+++ b/include/xen/events.h
@@ -0,0 +1,48 @@
+#ifndef _XEN_EVENTS_H
+#define _XEN_EVENTS_H
+
+#include <linux/interrupt.h>
+
+#include <xen/interface/event_channel.h>
+#include <asm/xen/hypercall.h>
+
+enum ipi_vector {
+ XEN_RESCHEDULE_VECTOR,
+ XEN_CALL_FUNCTION_VECTOR,
+
+ XEN_NR_IPIS,
+};
+
+int bind_evtchn_to_irq(unsigned int evtchn);
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+ void *dev_id);
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+ void *dev_id);
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id);
+
+/*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
+ * Automatically closes the underlying event channel (even for bindings
+ * made with bind_evtchn_to_irqhandler()).
+ */
+void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
+
+static inline void notify_remote_via_evtchn(int port)
+{
+ struct evtchn_send send = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+extern void notify_remote_via_irq(int irq);
+#endif /* _XEN_EVENTS_H */
diff --git a/include/xen/features.h b/include/xen/features.h
new file mode 100644
index 0000000..27292d4
--- /dev/null
+++ b/include/xen/features.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * features.h
+ *
+ * Query the features reported by Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_FEATURES_H__
+#define __XEN_FEATURES_H__
+
+#include <xen/interface/features.h>
+
+void xen_setup_features(void);
+
+extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
+
+static inline int xen_feature(int flag)
+{
+ return xen_features[flag];
+}
+
+#endif /* __ASM_XEN_FEATURES_H__ */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
new file mode 100644
index 0000000..761c834
--- /dev/null
+++ b/include/xen/grant_table.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Two sets of functionality:
+ * 1. Granting foreign access to our memory reservation.
+ * 2. Accessing others' memory reservations via grant references.
+ * (i.e., mechanisms for both sender and recipient of grant references)
+ *
+ * Copyright (c) 2004-2005, K A Fraser
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __ASM_GNTTAB_H__
+#define __ASM_GNTTAB_H__
+
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/grant_table.h>
+
+/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
+#define NR_GRANT_FRAMES 4
+
+struct gnttab_free_callback {
+ struct gnttab_free_callback *next;
+ void (*fn)(void *);
+ void *arg;
+ u16 count;
+};
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly);
+
+/*
+ * End access through the given grant reference, iff the grant entry is no
+ * longer in use. Return 1 if the grant entry was freed, 0 if it is still in
+ * use.
+ */
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
+
+/*
+ * Eventually end access through the given grant reference, and once that
+ * access has been ended, free the given page too. Access will be ended
+ * immediately iff the grant entry is not in use, otherwise it will happen
+ * some time later. page may be 0, in which case no freeing will occur.
+ */
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+ unsigned long page);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
+
+int gnttab_query_foreign_access(grant_ref_t ref);
+
+/*
+ * operations on reserved batches of grant references
+ */
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
+
+void gnttab_free_grant_reference(grant_ref_t ref);
+
+void gnttab_free_grant_references(grant_ref_t head);
+
+int gnttab_empty_grant_references(const grant_ref_t *pprivate_head);
+
+int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count);
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
+
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
+ unsigned long pfn);
+
+#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
+
+#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h
new file mode 100644
index 0000000..21c0ecf
--- /dev/null
+++ b/include/xen/hvc-console.h
@@ -0,0 +1,6 @@
+#ifndef XEN_HVC_CONSOLE_H
+#define XEN_HVC_CONSOLE_H
+
+extern struct console xenboot_console;
+
+#endif /* XEN_HVC_CONSOLE_H */
diff --git a/include/xen/interface/elfnote.h b/include/xen/interface/elfnote.h
new file mode 100644
index 0000000..a64d3df
--- /dev/null
+++ b/include/xen/interface/elfnote.h
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * elfnote.h
+ *
+ * Definitions used for the Xen ELF notes.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
+ */
+
+#ifndef __XEN_PUBLIC_ELFNOTE_H__
+#define __XEN_PUBLIC_ELFNOTE_H__
+
+/*
+ * The notes should live in a SHT_NOTE segment and have "Xen" in the
+ * name field.
+ *
+ * Numeric types are either 4 or 8 bytes depending on the content of
+ * the desc field.
+ *
+ * LEGACY indicated the fields in the legacy __xen_guest string which
+ * this a note type replaces.
+ */
+
+/*
+ * NAME=VALUE pair (string).
+ *
+ * LEGACY: FEATURES and PAE
+ */
+#define XEN_ELFNOTE_INFO 0
+
+/*
+ * The virtual address of the entry point (numeric).
+ *
+ * LEGACY: VIRT_ENTRY
+ */
+#define XEN_ELFNOTE_ENTRY 1
+
+/* The virtual address of the hypercall transfer page (numeric).
+ *
+ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
+ * number not a virtual address)
+ */
+#define XEN_ELFNOTE_HYPERCALL_PAGE 2
+
+/* The virtual address where the kernel image should be mapped (numeric).
+ *
+ * Defaults to 0.
+ *
+ * LEGACY: VIRT_BASE
+ */
+#define XEN_ELFNOTE_VIRT_BASE 3
+
+/*
+ * The offset of the ELF paddr field from the acutal required
+ * psuedo-physical address (numeric).
+ *
+ * This is used to maintain backwards compatibility with older kernels
+ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
+ * if not present.
+ *
+ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
+ */
+#define XEN_ELFNOTE_PADDR_OFFSET 4
+
+/*
+ * The version of Xen that we work with (string).
+ *
+ * LEGACY: XEN_VER
+ */
+#define XEN_ELFNOTE_XEN_VERSION 5
+
+/*
+ * The name of the guest operating system (string).
+ *
+ * LEGACY: GUEST_OS
+ */
+#define XEN_ELFNOTE_GUEST_OS 6
+
+/*
+ * The version of the guest operating system (string).
+ *
+ * LEGACY: GUEST_VER
+ */
+#define XEN_ELFNOTE_GUEST_VERSION 7
+
+/*
+ * The loader type (string).
+ *
+ * LEGACY: LOADER
+ */
+#define XEN_ELFNOTE_LOADER 8
+
+/*
+ * The kernel supports PAE (x86/32 only, string = "yes" or "no").
+ *
+ * LEGACY: PAE (n.b. The legacy interface included a provision to
+ * indicate 'extended-cr3' support allowing L3 page tables to be
+ * placed above 4G. It is assumed that any kernel new enough to use
+ * these ELF notes will include this and therefore "yes" here is
+ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
+ */
+#define XEN_ELFNOTE_PAE_MODE 9
+
+/*
+ * The features supported/required by this kernel (string).
+ *
+ * The string must consist of a list of feature names (as given in
+ * features.h, without the "XENFEAT_" prefix) separated by '|'
+ * characters. If a feature is required for the kernel to function
+ * then the feature name must be preceded by a '!' character.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_FEATURES 10
+
+/*
+ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
+ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
+ * of this string as a boolean flag rather than requiring "yes" or
+ * "no".
+ */
+#define XEN_ELFNOTE_BSD_SYMTAB 11
+
+#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/event_channel.h b/include/xen/interface/event_channel.h
new file mode 100644
index 0000000..919b5bd
--- /dev/null
+++ b/include/xen/interface/event_channel.h
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * event_channel.h
+ *
+ * Event channels between domains.
+ *
+ * Copyright (c) 2003-2004, K A Fraser.
+ */
+
+#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
+#define __XEN_PUBLIC_EVENT_CHANNEL_H__
+
+typedef uint32_t evtchn_port_t;
+DEFINE_GUEST_HANDLE(evtchn_port_t);
+
+/*
+ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
+ * accepting interdomain bindings from domain <remote_dom>. A fresh port
+ * is allocated in <dom> and returned as <port>.
+ * NOTES:
+ * 1. If the caller is unprivileged then <dom> must be DOMID_SELF.
+ * 2. <rdom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_alloc_unbound 6
+struct evtchn_alloc_unbound {
+ /* IN parameters */
+ domid_t dom, remote_dom;
+ /* OUT parameters */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
+ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
+ * a port that is unbound and marked as accepting bindings from the calling
+ * domain. A fresh port is allocated in the calling domain and returned as
+ * <local_port>.
+ * NOTES:
+ * 2. <remote_dom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_bind_interdomain 0
+struct evtchn_bind_interdomain {
+ /* IN parameters. */
+ domid_t remote_dom;
+ evtchn_port_t remote_port;
+ /* OUT parameters. */
+ evtchn_port_t local_port;
+};
+
+/*
+ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
+ * vcpu.
+ * NOTES:
+ * 1. A virtual IRQ may be bound to at most one event channel per vcpu.
+ * 2. The allocated event channel is bound to the specified vcpu. The binding
+ * may not be changed.
+ */
+#define EVTCHNOP_bind_virq 1
+struct evtchn_bind_virq {
+ /* IN parameters. */
+ uint32_t virq;
+ uint32_t vcpu;
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>.
+ * NOTES:
+ * 1. A physical IRQ may be bound to at most one event channel per domain.
+ * 2. Only a sufficiently-privileged domain may bind to a physical IRQ.
+ */
+#define EVTCHNOP_bind_pirq 2
+struct evtchn_bind_pirq {
+ /* IN parameters. */
+ uint32_t pirq;
+#define BIND_PIRQ__WILL_SHARE 1
+ uint32_t flags; /* BIND_PIRQ__* */
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ * NOTES:
+ * 1. The allocated event channel is bound to the specified vcpu. The binding
+ * may not be changed.
+ */
+#define EVTCHNOP_bind_ipi 7
+struct evtchn_bind_ipi {
+ uint32_t vcpu;
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
+ * interdomain then the remote end is placed in the unbound state
+ * (EVTCHNSTAT_unbound), awaiting a new connection.
+ */
+#define EVTCHNOP_close 3
+struct evtchn_close {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_send: Send an event to the remote end of the channel whose local
+ * endpoint is <port>.
+ */
+#define EVTCHNOP_send 4
+struct evtchn_send {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_status: Get the current status of the communication channel which
+ * has an endpoint at <dom, port>.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may obtain the status of an event
+ * channel for which <dom> is not DOMID_SELF.
+ */
+#define EVTCHNOP_status 5
+struct evtchn_status {
+ /* IN parameters */
+ domid_t dom;
+ evtchn_port_t port;
+ /* OUT parameters */
+#define EVTCHNSTAT_closed 0 /* Channel is not in use. */
+#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/
+#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
+#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
+#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
+ uint32_t status;
+ uint32_t vcpu; /* VCPU to which this channel is bound. */
+ union {
+ struct {
+ domid_t dom;
+ } unbound; /* EVTCHNSTAT_unbound */
+ struct {
+ domid_t dom;
+ evtchn_port_t port;
+ } interdomain; /* EVTCHNSTAT_interdomain */
+ uint32_t pirq; /* EVTCHNSTAT_pirq */
+ uint32_t virq; /* EVTCHNSTAT_virq */
+ } u;
+};
+
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ * the binding. This binding cannot be changed.
+ * 2. All other channels notify vcpu0 by default. This default is set when
+ * the channel is allocated (a port that is freed and subsequently reused
+ * has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu 8
+struct evtchn_bind_vcpu {
+ /* IN parameters. */
+ evtchn_port_t port;
+ uint32_t vcpu;
+};
+
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask 9
+struct evtchn_unmask {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+struct evtchn_op {
+ uint32_t cmd; /* EVTCHNOP_* */
+ union {
+ struct evtchn_alloc_unbound alloc_unbound;
+ struct evtchn_bind_interdomain bind_interdomain;
+ struct evtchn_bind_virq bind_virq;
+ struct evtchn_bind_pirq bind_pirq;
+ struct evtchn_bind_ipi bind_ipi;
+ struct evtchn_close close;
+ struct evtchn_send send;
+ struct evtchn_status status;
+ struct evtchn_bind_vcpu bind_vcpu;
+ struct evtchn_unmask unmask;
+ } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(evtchn_op);
+
+#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
new file mode 100644
index 0000000..d73228d
--- /dev/null
+++ b/include/xen/interface/features.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * features.h
+ *
+ * Feature flags, reported by XENVER_get_features.
+ *
+ * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_FEATURES_H__
+#define __XEN_PUBLIC_FEATURES_H__
+
+/*
+ * If set, the guest does not need to write-protect its pagetables, and can
+ * update them via direct writes.
+ */
+#define XENFEAT_writable_page_tables 0
+
+/*
+ * If set, the guest does not need to write-protect its segment descriptor
+ * tables, and can update them via direct writes.
+ */
+#define XENFEAT_writable_descriptor_tables 1
+
+/*
+ * If set, translation between the guest's 'pseudo-physical' address space
+ * and the host's machine address space are handled by the hypervisor. In this
+ * mode the guest does not need to perform phys-to/from-machine translations
+ * when performing page table operations.
+ */
+#define XENFEAT_auto_translated_physmap 2
+
+/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
+#define XENFEAT_supervisor_mode_kernel 3
+
+/*
+ * If set, the guest does not need to allocate x86 PAE page directories
+ * below 4GB. This flag is usually implied by auto_translated_physmap.
+ */
+#define XENFEAT_pae_pgdir_above_4gb 4
+
+#define XENFEAT_NR_SUBMAPS 1
+
+#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
new file mode 100644
index 0000000..2190498
--- /dev/null
+++ b/include/xen/interface/grant_table.h
@@ -0,0 +1,375 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Interface for granting foreign access to page frames, and receiving
+ * page-ownership transfers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
+#define __XEN_PUBLIC_GRANT_TABLE_H__
+
+
+/***********************************
+ * GRANT TABLE REPRESENTATION
+ */
+
+/* Some rough guidelines on accessing and updating grant-table entries
+ * in a concurrency-safe manner. For more information, Linux contains a
+ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
+ *
+ * NB. WMB is a no-op on current-generation x86 processors. However, a
+ * compiler barrier will still be required.
+ *
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ *
+ * Invalidating an unused GTF_permit_access entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & (GTF_reading|GTF_writing)).
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *
+ * Invalidating an in-use GTF_permit_access entry:
+ * This cannot be done directly. Request assistance from the domain controller
+ * which can set a timeout on the use of a grant entry and take necessary
+ * action. (NB. This is not yet implemented!).
+ *
+ * Invalidating an unused GTF_accept_transfer entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & GTF_transfer_committed). [*]
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ * [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
+ * The guest must /not/ modify the grant entry until the address of the
+ * transferred frame is written. It is safe for the guest to spin waiting
+ * for this to occur (detect by observing GTF_transfer_completed in
+ * ent->flags).
+ *
+ * Invalidating a committed GTF_accept_transfer entry:
+ * 1. Wait for (ent->flags & GTF_transfer_completed).
+ *
+ * Changing a GTF_permit_access from writable to read-only:
+ * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
+ *
+ * Changing a GTF_permit_access from read-only to writable:
+ * Use SMP-safe bit-setting instruction.
+ */
+
+/*
+ * A grant table comprises a packed array of grant entries in one or more
+ * page frames shared between Xen and a guest.
+ * [XEN]: This field is written by Xen and read by the sharing guest.
+ * [GST]: This field is written by the guest and read by Xen.
+ */
+struct grant_entry {
+ /* GTF_xxx: various type and flag information. [XEN,GST] */
+ uint16_t flags;
+ /* The domain being granted foreign privileges. [GST] */
+ domid_t domid;
+ /*
+ * GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
+ * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
+ */
+ uint32_t frame;
+};
+
+/*
+ * Type of grant entry.
+ * GTF_invalid: This grant entry grants no privileges.
+ * GTF_permit_access: Allow @domid to map/access @frame.
+ * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ * to this guest. Xen writes the page number to @frame.
+ */
+#define GTF_invalid (0U<<0)
+#define GTF_permit_access (1U<<0)
+#define GTF_accept_transfer (2U<<0)
+#define GTF_type_mask (3U<<0)
+
+/*
+ * Subflags for GTF_permit_access.
+ * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ */
+#define _GTF_readonly (2)
+#define GTF_readonly (1U<<_GTF_readonly)
+#define _GTF_reading (3)
+#define GTF_reading (1U<<_GTF_reading)
+#define _GTF_writing (4)
+#define GTF_writing (1U<<_GTF_writing)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ * GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ * to transferring ownership of a page frame. When a guest sees this flag
+ * it must /not/ modify the grant entry until GTF_transfer_completed is
+ * set by Xen.
+ * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ * after reading GTF_transfer_committed. Xen will always write the frame
+ * address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed (2)
+#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
+#define _GTF_transfer_completed (3)
+#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
+
+
+/***********************************
+ * GRANT TABLE QUERIES AND USES
+ */
+
+/*
+ * Reference to a grant entry in a specified domain's grant table.
+ */
+typedef uint32_t grant_ref_t;
+
+/*
+ * Handle to track a mapping created via a grant reference.
+ */
+typedef uint32_t grant_handle_t;
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <handle>
+ * is a negative status code.
+ * NOTES:
+ * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ * via which I/O devices may access the granted frame.
+ * 2. If GNTMAP_host_map is specified then a mapping will be added at
+ * either a host virtual address in the current address space, or at
+ * a PTE at the specified machine address. The type of mapping to
+ * perform is selected through the GNTMAP_contains_pte flag, and the
+ * address is specified in <host_addr>.
+ * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ * host mapping is destroyed by other means then it is *NOT* guaranteed
+ * to be accounted to the correct grant reference!
+ */
+#define GNTTABOP_map_grant_ref 0
+struct gnttab_map_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint32_t flags; /* GNTMAP_* */
+ grant_ref_t ref;
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+ grant_handle_t handle;
+ uint64_t dev_bus_addr;
+};
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ * 1. The call may fail in an undefined manner if either mapping is not
+ * tracked by <handle>.
+ * 3. After executing a batch of unmaps, it is guaranteed that no stale
+ * mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_grant_ref 1
+struct gnttab_unmap_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint64_t dev_bus_addr;
+ grant_handle_t handle;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ * 3. Xen may not support more than a single grant-table page per domain.
+ */
+#define GNTTABOP_setup_table 2
+struct gnttab_setup_table {
+ /* IN parameters. */
+ domid_t dom;
+ uint32_t nr_frames;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+ ulong *frame_list;
+};
+
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+#define GNTTABOP_dump_table 3
+struct gnttab_dump_table {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
+ * foreign domain has previously registered its interest in the transfer via
+ * <domid, ref>.
+ *
+ * Note that, even if the transfer fails, the specified page no longer belongs
+ * to the calling domain *unless* the error is GNTST_bad_page.
+ */
+#define GNTTABOP_transfer 4
+struct gnttab_transfer {
+ /* IN parameters. */
+ unsigned long mfn;
+ domid_t domid;
+ grant_ref_t ref;
+ /* OUT parameters. */
+ int16_t status;
+};
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref (0)
+#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref (1)
+#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
+
+#define GNTTABOP_copy 5
+struct gnttab_copy {
+ /* IN parameters. */
+ struct {
+ union {
+ grant_ref_t ref;
+ unsigned long gmfn;
+ } u;
+ domid_t domid;
+ uint16_t offset;
+ } source, dest;
+ uint16_t len;
+ uint16_t flags; /* GNTCOPY_* */
+ /* OUT parameters. */
+ int16_t status;
+};
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_query_size 6
+struct gnttab_query_size {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ uint32_t nr_frames;
+ uint32_t max_nr_frames;
+ int16_t status; /* GNTST_* */
+};
+
+
+/*
+ * Bitfield values for update_pin_status.flags.
+ */
+ /* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map (0)
+#define GNTMAP_device_map (1<<_GNTMAP_device_map)
+ /* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map (1)
+#define GNTMAP_host_map (1<<_GNTMAP_host_map)
+ /* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly (2)
+#define GNTMAP_readonly (1<<_GNTMAP_readonly)
+ /*
+ * GNTMAP_host_map subflag:
+ * 0 => The host mapping is usable only by the guest OS.
+ * 1 => The host mapping is usable by guest OS + current application.
+ */
+#define _GNTMAP_application_map (3)
+#define GNTMAP_application_map (1<<_GNTMAP_application_map)
+
+ /*
+ * GNTMAP_contains_pte subflag:
+ * 0 => This map request contains a host virtual address.
+ * 1 => This map request contains the machine addess of the PTE to update.
+ */
+#define _GNTMAP_contains_pte (4)
+#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte)
+
+/*
+ * Values for error status returns. All errors are -ve.
+ */
+#define GNTST_okay (0) /* Normal return. */
+#define GNTST_general_error (-1) /* General undefined error. */
+#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */
+#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */
+#define GNTST_bad_page (-9) /* Specified page was invalid for op. */
+#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */
+
+#define GNTTABOP_error_msgs { \
+ "okay", \
+ "undefined error", \
+ "unrecognised domain id", \
+ "invalid grant reference", \
+ "invalid mapping handle", \
+ "invalid virtual address", \
+ "invalid device address", \
+ "no spare translation slot in the I/O MMU", \
+ "permission denied", \
+ "bad page", \
+ "copy arguments cross page boundary" \
+}
+
+#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
new file mode 100644
index 0000000..c2d1fa4
--- /dev/null
+++ b/include/xen/interface/io/blkif.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * blkif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_BLKIF_H__
+#define __XEN_PUBLIC_IO_BLKIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Front->back notifications: When enqueuing a new request, sending a
+ * notification can be made conditional on req_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Backends must set
+ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()).
+ *
+ * Back->front notifications: When enqueuing a new response, sending a
+ * notification can be made conditional on rsp_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Frontends must set
+ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()).
+ */
+
+typedef uint16_t blkif_vdev_t;
+typedef uint64_t blkif_sector_t;
+
+/*
+ * REQUEST CODES.
+ */
+#define BLKIF_OP_READ 0
+#define BLKIF_OP_WRITE 1
+/*
+ * Recognised only if "feature-barrier" is present in backend xenbus info.
+ * The "feature_barrier" node contains a boolean indicating whether barrier
+ * requests are likely to succeed or fail. Either way, a barrier request
+ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by
+ * the underlying block-device hardware. The boolean simply indicates whether
+ * or not it is worthwhile for the frontend to attempt barrier requests.
+ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not*
+ * create the "feature-barrier" node!
+ */
+#define BLKIF_OP_WRITE_BARRIER 2
+
+/*
+ * Maximum scatter/gather segments per request.
+ * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
+ * NB. This could be 12 if the ring indexes weren't stored in the same page.
+ */
+#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
+
+struct blkif_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t id; /* private guest value, echoed in resp */
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment {
+ grant_ref_t gref; /* reference to I/O buffer frame */
+ /* @first_sect: first sector in frame to transfer (inclusive). */
+ /* @last_sect: last sector in frame to transfer (inclusive). */
+ uint8_t first_sect, last_sect;
+ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+struct blkif_response {
+ uint64_t id; /* copied from request */
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+
+/*
+ * STATUS RETURN CODES.
+ */
+ /* Operation not supported (only happens on barrier writes). */
+#define BLKIF_RSP_EOPNOTSUPP -2
+ /* Operation failed for some unspecified reason (-EIO). */
+#define BLKIF_RSP_ERROR -1
+ /* Operation completed successfully. */
+#define BLKIF_RSP_OKAY 0
+
+/*
+ * Generate blkif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
+
+#define VDISK_CDROM 0x1
+#define VDISK_REMOVABLE 0x2
+#define VDISK_READONLY 0x4
+
+#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
new file mode 100644
index 0000000..e563de7
--- /dev/null
+++ b/include/xen/interface/io/console.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+ char in[1024];
+ char out[2048];
+ XENCONS_RING_IDX in_cons, in_prod;
+ XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
new file mode 100644
index 0000000..518481c
--- /dev/null
+++ b/include/xen/interface/io/netif.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * netif.h
+ *
+ * Unified network-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_NETIF_H__
+#define __XEN_PUBLIC_IO_NETIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Notifications after enqueuing any type of message should be conditional on
+ * the appropriate req_event or rsp_event field in the shared ring.
+ * If the client sends notification for rx requests then it should specify
+ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume
+ * that it cannot safely queue packets (as it may not be kicked to send them).
+ */
+
+/*
+ * This is the 'wire' format for packets:
+ * Request 1: netif_tx_request -- NETTXF_* (any flags)
+ * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info)
+ * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE)
+ * Request 4: netif_tx_request -- NETTXF_more_data
+ * Request 5: netif_tx_request -- NETTXF_more_data
+ * ...
+ * Request N: netif_tx_request -- 0
+ */
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETTXF_csum_blank (0)
+#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank)
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETTXF_data_validated (1)
+#define NETTXF_data_validated (1U<<_NETTXF_data_validated)
+
+/* Packet continues in the next request descriptor. */
+#define _NETTXF_more_data (2)
+#define NETTXF_more_data (1U<<_NETTXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETTXF_extra_info (3)
+#define NETTXF_extra_info (1U<<_NETTXF_extra_info)
+
+struct xen_netif_tx_request {
+ grant_ref_t gref; /* Reference to buffer page */
+ uint16_t offset; /* Offset within buffer page */
+ uint16_t flags; /* NETTXF_* */
+ uint16_t id; /* Echoed in response message. */
+ uint16_t size; /* Packet size in bytes. */
+};
+
+/* Types of netif_extra_info descriptors. */
+#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
+#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
+#define XEN_NETIF_EXTRA_TYPE_MAX (2)
+
+/* netif_extra_info flags. */
+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+
+/* GSO types - only TCPv4 currently supported. */
+#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
+
+/*
+ * This structure needs to fit within both netif_tx_request and
+ * netif_rx_response for compatibility.
+ */
+struct xen_netif_extra_info {
+ uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */
+ uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
+
+ union {
+ struct {
+ /*
+ * Maximum payload size of each segment. For
+ * example, for TCP this is just the path MSS.
+ */
+ uint16_t size;
+
+ /*
+ * GSO type. This determines the protocol of
+ * the packet and any extra features required
+ * to segment the packet properly.
+ */
+ uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
+
+ /* Future expansion. */
+ uint8_t pad;
+
+ /*
+ * GSO features. This specifies any extra GSO
+ * features required to process this packet,
+ * such as ECN support for TCPv4.
+ */
+ uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
+ } gso;
+
+ uint16_t pad[3];
+ } u;
+};
+
+struct xen_netif_tx_response {
+ uint16_t id;
+ int16_t status; /* NETIF_RSP_* */
+};
+
+struct xen_netif_rx_request {
+ uint16_t id; /* Echoed in response message. */
+ grant_ref_t gref; /* Reference to incoming granted frame */
+};
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETRXF_data_validated (0)
+#define NETRXF_data_validated (1U<<_NETRXF_data_validated)
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETRXF_csum_blank (1)
+#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank)
+
+/* Packet continues in the next request descriptor. */
+#define _NETRXF_more_data (2)
+#define NETRXF_more_data (1U<<_NETRXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETRXF_extra_info (3)
+#define NETRXF_extra_info (1U<<_NETRXF_extra_info)
+
+struct xen_netif_rx_response {
+ uint16_t id;
+ uint16_t offset; /* Offset in page of start of received packet */
+ uint16_t flags; /* NETRXF_* */
+ int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+};
+
+/*
+ * Generate netif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(xen_netif_tx,
+ struct xen_netif_tx_request,
+ struct xen_netif_tx_response);
+DEFINE_RING_TYPES(xen_netif_rx,
+ struct xen_netif_rx_request,
+ struct xen_netif_rx_response);
+
+#define NETIF_RSP_DROPPED -2
+#define NETIF_RSP_ERROR -1
+#define NETIF_RSP_OKAY 0
+/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
+#define NETIF_RSP_NULL 1
+
+#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
new file mode 100644
index 0000000..e8cbf43
--- /dev/null
+++ b/include/xen/interface/io/ring.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * ring.h
+ *
+ * Shared producer-consumer ring macros.
+ *
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* Round a 32-bit unsigned constant down to the nearest power of two. */
+#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1))
+#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x))
+#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x))
+#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x))
+#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
+
+/*
+ * Calculate size of a shared ring, given the total available space for the
+ * ring and indexes (_sz), and the name tag of the request/response structure.
+ * A ring contains as many entries as will fit, rounded down to the nearest
+ * power of two (so we can mask with (size-1) to loop around).
+ */
+#define __RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say struct request, and struct response already defined.
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ * DEFINE_RING_TYPES(mytag, struct request, struct response);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ * struct mytag_sring - The shared ring.
+ * struct mytag_front_ring - The 'front' half of the ring.
+ * struct mytag_back_ring - The 'back' half of the ring.
+ *
+ * To initialize a ring in your code you need to know the location and size
+ * of the shared memory area (PAGE_SIZE, for instance). To initialise
+ * the front half:
+ *
+ * struct mytag_front_ring front_ring;
+ * SHARED_RING_INIT((struct mytag_sring *)shared_page);
+ * FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page,
+ * PAGE_SIZE);
+ *
+ * Initializing the back follows similarly (note that only the front
+ * initializes the shared ring):
+ *
+ * struct mytag_back_ring back_ring;
+ * BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page,
+ * PAGE_SIZE);
+ */
+
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \
+ \
+/* Shared ring entry */ \
+union __name##_sring_entry { \
+ __req_t req; \
+ __rsp_t rsp; \
+}; \
+ \
+/* Shared ring page */ \
+struct __name##_sring { \
+ RING_IDX req_prod, req_event; \
+ RING_IDX rsp_prod, rsp_event; \
+ uint8_t pad[48]; \
+ union __name##_sring_entry ring[1]; /* variable-length */ \
+}; \
+ \
+/* "Front" end's private variables */ \
+struct __name##_front_ring { \
+ RING_IDX req_prod_pvt; \
+ RING_IDX rsp_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* "Back" end's private variables */ \
+struct __name##_back_ring { \
+ RING_IDX rsp_prod_pvt; \
+ RING_IDX req_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+};
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than RING_SIZE()-1
+ * outstanding requests.
+ */
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_s) do { \
+ (_s)->req_prod = (_s)->rsp_prod = 0; \
+ (_s)->req_event = (_s)->rsp_event = 1; \
+ memset((_s)->pad, 0, sizeof((_s)->pad)); \
+} while(0)
+
+#define FRONT_RING_INIT(_r, _s, __size) do { \
+ (_r)->req_prod_pvt = 0; \
+ (_r)->rsp_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+#define BACK_RING_INIT(_r, _s, __size) do { \
+ (_r)->rsp_prod_pvt = 0; \
+ (_r)->req_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_r, _s, __size) do { \
+ (_r)->sring = (_s); \
+ (_r)->req_prod_pvt = (_s)->req_prod; \
+ (_r)->rsp_cons = (_s)->rsp_prod; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+} while (0)
+
+#define BACK_RING_ATTACH(_r, _s, __size) do { \
+ (_r)->sring = (_s); \
+ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \
+ (_r)->req_cons = (_s)->req_prod; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+} while (0)
+
+/* How big is this ring? */
+#define RING_SIZE(_r) \
+ ((_r)->nr_ents)
+
+/* Number of free requests (for use on front side only). */
+#define RING_FREE_REQUESTS(_r) \
+ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_r) \
+ (RING_FREE_REQUESTS(_r) == 0)
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
+ ((_r)->sring->rsp_prod - (_r)->rsp_cons)
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
+ ({ \
+ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
+ unsigned int rsp = RING_SIZE(_r) - \
+ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
+ req < rsp ? req : rsp; \
+ })
+
+/* Direct access to individual ring elements, by index. */
+#define RING_GET_REQUEST(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+
+#define RING_GET_RESPONSE(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
+/* Loop termination condition: Would the specified index overflow the ring? */
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \
+ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do { \
+ wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_r) do { \
+ wmb(); /* front sees responses /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
+} while (0)
+
+/*
+ * Notification hold-off (req_event and rsp_event):
+ *
+ * When queueing requests or responses on a shared ring, it may not always be
+ * necessary to notify the remote end. For example, if requests are in flight
+ * in a backend, the front may be able to queue further requests without
+ * notifying the back (if the back checks for new requests when it queues
+ * responses).
+ *
+ * When enqueuing requests or responses:
+ *
+ * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
+ * is a boolean return value. True indicates that the receiver requires an
+ * asynchronous notification.
+ *
+ * After dequeuing requests or responses (before sleeping the connection):
+ *
+ * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
+ * The second argument is a boolean return value. True indicates that there
+ * are pending messages on the ring (i.e., the connection should not be put
+ * to sleep).
+ *
+ * These macros will set the req_event/rsp_event field to trigger a
+ * notification on the very next message that is enqueued. If you want to
+ * create batches of work (i.e., only receive a notification after several
+ * messages have been enqueued) then you will need to create a customised
+ * version of the FINAL_CHECK macro in your own code, which sets the event
+ * field appropriately.
+ */
+
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->req_prod; \
+ RING_IDX __new = (_r)->req_prod_pvt; \
+ wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = __new; \
+ mb(); /* back sees new requests /before/ we check req_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->rsp_prod; \
+ RING_IDX __new = (_r)->rsp_prod_pvt; \
+ wmb(); /* front sees responses /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = __new; \
+ mb(); /* front sees new responses /before/ we check rsp_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->req_event = (_r)->req_cons + 1; \
+ mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \
+ mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+} while (0)
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
diff --git a/include/xen/interface/io/xenbus.h b/include/xen/interface/io/xenbus.h
new file mode 100644
index 0000000..46508c7
--- /dev/null
+++ b/include/xen/interface/io/xenbus.h
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * xenbus.h
+ *
+ * Xenbus protocol details.
+ *
+ * Copyright (C) 2005 XenSource Ltd.
+ */
+
+#ifndef _XEN_PUBLIC_IO_XENBUS_H
+#define _XEN_PUBLIC_IO_XENBUS_H
+
+/* The state of either end of the Xenbus, i.e. the current communication
+ status of initialisation across the bus. States here imply nothing about
+ the state of the connection between the driver and the kernel's device
+ layers. */
+enum xenbus_state
+{
+ XenbusStateUnknown = 0,
+ XenbusStateInitialising = 1,
+ XenbusStateInitWait = 2, /* Finished early
+ initialisation, but waiting
+ for information from the peer
+ or hotplug scripts. */
+ XenbusStateInitialised = 3, /* Initialised and waiting for a
+ connection from the peer. */
+ XenbusStateConnected = 4,
+ XenbusStateClosing = 5, /* The device is being closed
+ due to an error or an unplug
+ event. */
+ XenbusStateClosed = 6
+
+};
+
+#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
new file mode 100644
index 0000000..99fcffb
--- /dev/null
+++ b/include/xen/interface/io/xs_wire.h
@@ -0,0 +1,87 @@
+/*
+ * Details of the "wire" protocol between Xen Store Daemon and client
+ * library or guest kernel.
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ */
+
+#ifndef _XS_WIRE_H
+#define _XS_WIRE_H
+
+enum xsd_sockmsg_type
+{
+ XS_DEBUG,
+ XS_DIRECTORY,
+ XS_READ,
+ XS_GET_PERMS,
+ XS_WATCH,
+ XS_UNWATCH,
+ XS_TRANSACTION_START,
+ XS_TRANSACTION_END,
+ XS_INTRODUCE,
+ XS_RELEASE,
+ XS_GET_DOMAIN_PATH,
+ XS_WRITE,
+ XS_MKDIR,
+ XS_RM,
+ XS_SET_PERMS,
+ XS_WATCH_EVENT,
+ XS_ERROR,
+ XS_IS_DOMAIN_INTRODUCED
+};
+
+#define XS_WRITE_NONE "NONE"
+#define XS_WRITE_CREATE "CREATE"
+#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
+
+/* We hand errors as strings, for portability. */
+struct xsd_errors
+{
+ int errnum;
+ const char *errstring;
+};
+#define XSD_ERROR(x) { x, #x }
+static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
+ XSD_ERROR(EINVAL),
+ XSD_ERROR(EACCES),
+ XSD_ERROR(EEXIST),
+ XSD_ERROR(EISDIR),
+ XSD_ERROR(ENOENT),
+ XSD_ERROR(ENOMEM),
+ XSD_ERROR(ENOSPC),
+ XSD_ERROR(EIO),
+ XSD_ERROR(ENOTEMPTY),
+ XSD_ERROR(ENOSYS),
+ XSD_ERROR(EROFS),
+ XSD_ERROR(EBUSY),
+ XSD_ERROR(EAGAIN),
+ XSD_ERROR(EISCONN)
+};
+
+struct xsd_sockmsg
+{
+ uint32_t type; /* XS_??? */
+ uint32_t req_id;/* Request identifier, echoed in daemon's response. */
+ uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */
+ uint32_t len; /* Length of data following this. */
+
+ /* Generally followed by nul-terminated string(s). */
+};
+
+enum xs_watch_type
+{
+ XS_WATCH_PATH = 0,
+ XS_WATCH_TOKEN
+};
+
+/* Inter-domain shared memory communications. */
+#define XENSTORE_RING_SIZE 1024
+typedef uint32_t XENSTORE_RING_IDX;
+#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
+struct xenstore_domain_interface {
+ char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */
+ char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
+ XENSTORE_RING_IDX req_cons, req_prod;
+ XENSTORE_RING_IDX rsp_cons, rsp_prod;
+};
+
+#endif /* _XS_WIRE_H */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
new file mode 100644
index 0000000..af36ead
--- /dev/null
+++ b/include/xen/interface/memory.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ * memory.h
+ *
+ * Memory reservation and information.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_MEMORY_H__
+#define __XEN_PUBLIC_MEMORY_H__
+
+/*
+ * Increase or decrease the specified domain's memory reservation. Returns a
+ * -ve errcode on failure, or the # extents successfully allocated or freed.
+ * arg == addr of struct xen_memory_reservation.
+ */
+#define XENMEM_increase_reservation 0
+#define XENMEM_decrease_reservation 1
+#define XENMEM_populate_physmap 6
+struct xen_memory_reservation {
+
+ /*
+ * XENMEM_increase_reservation:
+ * OUT: MFN (*not* GMFN) bases of extents that were allocated
+ * XENMEM_decrease_reservation:
+ * IN: GMFN bases of extents to free
+ * XENMEM_populate_physmap:
+ * IN: GPFN bases of extents to populate with memory
+ * OUT: GMFN bases of extents that were allocated
+ * (NB. This command also updates the mach_to_phys translation table)
+ */
+ GUEST_HANDLE(ulong) extent_start;
+
+ /* Number of extents, and size/alignment of each (2^extent_order pages). */
+ unsigned long nr_extents;
+ unsigned int extent_order;
+
+ /*
+ * Maximum # bits addressable by the user of the allocated region (e.g.,
+ * I/O devices often have a 32-bit limitation even in 64-bit systems). If
+ * zero then the user has no addressing restriction.
+ * This field is not used by XENMEM_decrease_reservation.
+ */
+ unsigned int address_bits;
+
+ /*
+ * Domain whose reservation is being changed.
+ * Unprivileged domains can specify only DOMID_SELF.
+ */
+ domid_t domid;
+
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
+
+/*
+ * Returns the maximum machine frame number of mapped RAM in this system.
+ * This command always succeeds (it never returns an error code).
+ * arg == NULL.
+ */
+#define XENMEM_maximum_ram_page 2
+
+/*
+ * Returns the current or maximum memory reservation, in pages, of the
+ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure.
+ * arg == addr of domid_t.
+ */
+#define XENMEM_current_reservation 3
+#define XENMEM_maximum_reservation 4
+
+/*
+ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table do not implement
+ * this command.
+ * arg == addr of xen_machphys_mfn_list_t.
+ */
+#define XENMEM_machphys_mfn_list 5
+struct xen_machphys_mfn_list {
+ /*
+ * Size of the 'extent_start' array. Fewer entries will be filled if the
+ * machphys table is smaller than max_extents * 2MB.
+ */
+ unsigned int max_extents;
+
+ /*
+ * Pointer to buffer to fill with list of extent starts. If there are
+ * any large discontiguities in the machine address space, 2MB gaps in
+ * the machphys table will be represented by an MFN base of zero.
+ */
+ GUEST_HANDLE(ulong) extent_start;
+
+ /*
+ * Number of extents written to the above array. This will be smaller
+ * than 'max_extents' if the machphys table is smaller than max_e * 2MB.
+ */
+ unsigned int nr_extents;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
+
+/*
+ * Sets the GPFN at which a particular page appears in the specified guest's
+ * pseudophysical address space.
+ * arg == addr of xen_add_to_physmap_t.
+ */
+#define XENMEM_add_to_physmap 7
+struct xen_add_to_physmap {
+ /* Which domain to change the mapping for. */
+ domid_t domid;
+
+ /* Source mapping space. */
+#define XENMAPSPACE_shared_info 0 /* shared info page */
+#define XENMAPSPACE_grant_table 1 /* grant table page */
+ unsigned int space;
+
+ /* Index into source mapping space. */
+ unsigned long idx;
+
+ /* GPFN where the source mapping page should appear. */
+ unsigned long gpfn;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap);
+
+/*
+ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list 8
+struct xen_translate_gpfn_list {
+ /* Which domain to translate for? */
+ domid_t domid;
+
+ /* Length of list. */
+ unsigned long nr_gpfns;
+
+ /* List of GPFNs to translate. */
+ GUEST_HANDLE(ulong) gpfn_list;
+
+ /*
+ * Output list to contain MFN translations. May be the same as the input
+ * list (in which case each input GPFN is overwritten with the output MFN).
+ */
+ GUEST_HANDLE(ulong) mfn_list;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
+
+#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
new file mode 100644
index 0000000..cd69391
--- /dev/null
+++ b/include/xen/interface/physdev.h
@@ -0,0 +1,145 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_PUBLIC_PHYSDEV_H__
+#define __XEN_PUBLIC_PHYSDEV_H__
+
+/*
+ * Prototype for this hypercall is:
+ * int physdev_op(int cmd, void *args)
+ * @cmd == PHYSDEVOP_??? (physdev operation).
+ * @args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Notify end-of-interrupt (EOI) for the specified IRQ.
+ * @arg == pointer to physdev_eoi structure.
+ */
+#define PHYSDEVOP_eoi 12
+struct physdev_eoi {
+ /* IN */
+ uint32_t irq;
+};
+
+/*
+ * Query the status of an IRQ line.
+ * @arg == pointer to physdev_irq_status_query structure.
+ */
+#define PHYSDEVOP_irq_status_query 5
+struct physdev_irq_status_query {
+ /* IN */
+ uint32_t irq;
+ /* OUT */
+ uint32_t flags; /* XENIRQSTAT_* */
+};
+
+/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */
+#define _XENIRQSTAT_needs_eoi (0)
+#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi)
+
+/* IRQ shared by multiple guests? */
+#define _XENIRQSTAT_shared (1)
+#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared)
+
+/*
+ * Set the current VCPU's I/O privilege level.
+ * @arg == pointer to physdev_set_iopl structure.
+ */
+#define PHYSDEVOP_set_iopl 6
+struct physdev_set_iopl {
+ /* IN */
+ uint32_t iopl;
+};
+
+/*
+ * Set the current VCPU's I/O-port permissions bitmap.
+ * @arg == pointer to physdev_set_iobitmap structure.
+ */
+#define PHYSDEVOP_set_iobitmap 7
+struct physdev_set_iobitmap {
+ /* IN */
+ uint8_t * bitmap;
+ uint32_t nr_ports;
+};
+
+/*
+ * Read or write an IO-APIC register.
+ * @arg == pointer to physdev_apic structure.
+ */
+#define PHYSDEVOP_apic_read 8
+#define PHYSDEVOP_apic_write 9
+struct physdev_apic {
+ /* IN */
+ unsigned long apic_physbase;
+ uint32_t reg;
+ /* IN or OUT */
+ uint32_t value;
+};
+
+/*
+ * Allocate or free a physical upcall vector for the specified IRQ line.
+ * @arg == pointer to physdev_irq structure.
+ */
+#define PHYSDEVOP_alloc_irq_vector 10
+#define PHYSDEVOP_free_irq_vector 11
+struct physdev_irq {
+ /* IN */
+ uint32_t irq;
+ /* IN or OUT */
+ uint32_t vector;
+};
+
+/*
+ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
+ * hypercall since 0x00030202.
+ */
+struct physdev_op {
+ uint32_t cmd;
+ union {
+ struct physdev_irq_status_query irq_status_query;
+ struct physdev_set_iopl set_iopl;
+ struct physdev_set_iobitmap set_iobitmap;
+ struct physdev_apic apic_op;
+ struct physdev_irq irq_op;
+ } u;
+};
+
+/*
+ * Notify that some PIRQ-bound event channels have been unmasked.
+ * ** This command is obsolete since interface version 0x00030202 and is **
+ * ** unsupported by newer versions of Xen. **
+ */
+#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4
+
+/*
+ * These all-capitals physdev operation names are superceded by the new names
+ * (defined above) since interface version 0x00030202.
+ */
+#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query
+#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl
+#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap
+#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read
+#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write
+#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector
+#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector
+#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
+#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared
+
+#endif /* __XEN_PUBLIC_PHYSDEV_H__ */
diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h
new file mode 100644
index 0000000..5fec575
--- /dev/null
+++ b/include/xen/interface/sched.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * sched.h
+ *
+ * Scheduler state interactions
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_SCHED_H__
+#define __XEN_PUBLIC_SCHED_H__
+
+#include "event_channel.h"
+
+/*
+ * The prototype for this hypercall is:
+ * long sched_op_new(int cmd, void *arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == Operation-specific extra argument(s), as described below.
+ *
+ * **NOTE**:
+ * Versions of Xen prior to 3.0.2 provide only the following legacy version
+ * of this hypercall, supporting only the commands yield, block and shutdown:
+ * long sched_op(int cmd, unsigned long arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == 0 (SCHEDOP_yield and SCHEDOP_block)
+ * == SHUTDOWN_* code (SCHEDOP_shutdown)
+ */
+
+/*
+ * Voluntarily yield the CPU.
+ * @arg == NULL.
+ */
+#define SCHEDOP_yield 0
+
+/*
+ * Block execution of this VCPU until an event is received for processing.
+ * If called with event upcalls masked, this operation will atomically
+ * reenable event delivery and check for pending events before blocking the
+ * VCPU. This avoids a "wakeup waiting" race.
+ * @arg == NULL.
+ */
+#define SCHEDOP_block 1
+
+/*
+ * Halt execution of this domain (all VCPUs) and notify the system controller.
+ * @arg == pointer to sched_shutdown structure.
+ */
+#define SCHEDOP_shutdown 2
+struct sched_shutdown {
+ unsigned int reason; /* SHUTDOWN_* */
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_shutdown);
+
+/*
+ * Poll a set of event-channel ports. Return when one or more are pending. An
+ * optional timeout may be specified.
+ * @arg == pointer to sched_poll structure.
+ */
+#define SCHEDOP_poll 3
+struct sched_poll {
+ GUEST_HANDLE(evtchn_port_t) ports;
+ unsigned int nr_ports;
+ uint64_t timeout;
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
+
+/*
+ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
+ * software to determine the appropriate action. For the most part, Xen does
+ * not care about the shutdown code.
+ */
+#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
+#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
+#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
+
+#endif /* __XEN_PUBLIC_SCHED_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
new file mode 100644
index 0000000..ff61ea3
--- /dev/null
+++ b/include/xen/interface/vcpu.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * vcpu.h
+ *
+ * VCPU initialisation, query, and hotplug.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VCPU_H__
+#define __XEN_PUBLIC_VCPU_H__
+
+/*
+ * Prototype for this hypercall is:
+ * int vcpu_op(int cmd, int vcpuid, void *extra_args)
+ * @cmd == VCPUOP_??? (VCPU operation).
+ * @vcpuid == VCPU to operate on.
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Initialise a VCPU. Each VCPU can be initialised only once. A
+ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up.
+ *
+ * @extra_arg == pointer to vcpu_guest_context structure containing initial
+ * state for the VCPU.
+ */
+#define VCPUOP_initialise 0
+
+/*
+ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail
+ * if the VCPU has not been initialised (VCPUOP_initialise).
+ */
+#define VCPUOP_up 1
+
+/*
+ * Bring down a VCPU (i.e., make it non-runnable).
+ * There are a few caveats that callers should observe:
+ * 1. This operation may return, and VCPU_is_up may return false, before the
+ * VCPU stops running (i.e., the command is asynchronous). It is a good
+ * idea to ensure that the VCPU has entered a non-critical loop before
+ * bringing it down. Alternatively, this operation is guaranteed
+ * synchronous if invoked by the VCPU itself.
+ * 2. After a VCPU is initialised, there is currently no way to drop all its
+ * references to domain memory. Even a VCPU that is down still holds
+ * memory references via its pagetable base pointer and GDT. It is good
+ * practise to move a VCPU onto an 'idle' or default page table, LDT and
+ * GDT before bringing it down.
+ */
+#define VCPUOP_down 2
+
+/* Returns 1 if the given VCPU is up. */
+#define VCPUOP_is_up 3
+
+/*
+ * Return information about the state and running time of a VCPU.
+ * @extra_arg == pointer to vcpu_runstate_info structure.
+ */
+#define VCPUOP_get_runstate_info 4
+struct vcpu_runstate_info {
+ /* VCPU's current state (RUNSTATE_*). */
+ int state;
+ /* When was current state entered (system time, ns)? */
+ uint64_t state_entry_time;
+ /*
+ * Time spent in each RUNSTATE_* (ns). The sum of these times is
+ * guaranteed not to drift from system time.
+ */
+ uint64_t time[4];
+};
+
+/* VCPU is currently running on a physical CPU. */
+#define RUNSTATE_running 0
+
+/* VCPU is runnable, but not currently scheduled on any physical CPU. */
+#define RUNSTATE_runnable 1
+
+/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */
+#define RUNSTATE_blocked 2
+
+/*
+ * VCPU is not runnable, but it is not blocked.
+ * This is a 'catch all' state for things like hotplug and pauses by the
+ * system administrator (or for critical sections in the hypervisor).
+ * RUNSTATE_blocked dominates this state (it is the preferred state).
+ */
+#define RUNSTATE_offline 3
+
+/*
+ * Register a shared memory area from which the guest may obtain its own
+ * runstate information without needing to execute a hypercall.
+ * Notes:
+ * 1. The registered address may be virtual or physical, depending on the
+ * platform. The virtual address should be registered on x86 systems.
+ * 2. Only one shared area may be registered per VCPU. The shared area is
+ * updated by the hypervisor each time the VCPU is scheduled. Thus
+ * runstate.state will always be RUNSTATE_running and
+ * runstate.state_entry_time will indicate the system time at which the
+ * VCPU was last scheduled to run.
+ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure.
+ */
+#define VCPUOP_register_runstate_memory_area 5
+struct vcpu_register_runstate_memory_area {
+ union {
+ struct vcpu_runstate_info *v;
+ uint64_t p;
+ } addr;
+};
+
+/*
+ * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer
+ * which can be set via these commands. Periods smaller than one millisecond
+ * may not be supported.
+ */
+#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */
+#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */
+struct vcpu_set_periodic_timer {
+ uint64_t period_ns;
+};
+
+/*
+ * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot
+ * timer which can be set via these commands.
+ */
+#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */
+#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */
+struct vcpu_set_singleshot_timer {
+ uint64_t timeout_abs_ns;
+ uint32_t flags; /* VCPU_SSHOTTMR_??? */
+};
+
+/* Flags to VCPUOP_set_singleshot_timer. */
+ /* Require the timeout to be in the future (return -ETIME if it's passed). */
+#define _VCPU_SSHOTTMR_future (0)
+#define VCPU_SSHOTTMR_future (1U << _VCPU_SSHOTTMR_future)
+
+/*
+ * Register a memory location in the guest address space for the
+ * vcpu_info structure. This allows the guest to place the vcpu_info
+ * structure in a convenient place, such as in a per-cpu data area.
+ * The pointer need not be page aligned, but the structure must not
+ * cross a page boundary.
+ */
+#define VCPUOP_register_vcpu_info 10 /* arg == struct vcpu_info */
+struct vcpu_register_vcpu_info {
+ uint32_t mfn; /* mfn of page to place vcpu_info */
+ uint32_t offset; /* offset within page */
+};
+
+#endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/include/xen/interface/version.h b/include/xen/interface/version.h
new file mode 100644
index 0000000..453235e
--- /dev/null
+++ b/include/xen/interface/version.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * version.h
+ *
+ * Xen version, type, and compile information.
+ *
+ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VERSION_H__
+#define __XEN_PUBLIC_VERSION_H__
+
+/* NB. All ops return zero on success, except XENVER_version. */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version 0
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+struct xen_extraversion {
+ char extraversion[16];
+};
+#define XEN_EXTRAVERSION_LEN (sizeof(struct xen_extraversion))
+
+/* arg == xen_compile_info_t. */
+#define XENVER_compile_info 2
+struct xen_compile_info {
+ char compiler[64];
+ char compile_by[16];
+ char compile_domain[32];
+ char compile_date[32];
+};
+
+#define XENVER_capabilities 3
+struct xen_capabilities_info {
+ char info[1024];
+};
+#define XEN_CAPABILITIES_INFO_LEN (sizeof(struct xen_capabilities_info))
+
+#define XENVER_changeset 4
+struct xen_changeset_info {
+ char info[64];
+};
+#define XEN_CHANGESET_INFO_LEN (sizeof(struct xen_changeset_info))
+
+#define XENVER_platform_parameters 5
+struct xen_platform_parameters {
+ unsigned long virt_start;
+};
+
+#define XENVER_get_features 6
+struct xen_feature_info {
+ unsigned int submap_idx; /* IN: which 32-bit submap to return */
+ uint32_t submap; /* OUT: 32-bit submap */
+};
+
+/* Declares the features reported by XENVER_get_features. */
+#include "features.h"
+
+#endif /* __XEN_PUBLIC_VERSION_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
new file mode 100644
index 0000000..518a5bf
--- /dev/null
+++ b/include/xen/interface/xen.h
@@ -0,0 +1,447 @@
+/******************************************************************************
+ * xen.h
+ *
+ * Guest OS interface to Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_XEN_H__
+#define __XEN_PUBLIC_XEN_H__
+
+#include <asm/xen/interface.h>
+
+/*
+ * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
+ */
+
+/*
+ * x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5.
+ * EAX = return value
+ * (argument registers may be clobbered on return)
+ * x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6.
+ * RAX = return value
+ * (argument registers not clobbered on return; RCX, R11 are)
+ */
+#define __HYPERVISOR_set_trap_table 0
+#define __HYPERVISOR_mmu_update 1
+#define __HYPERVISOR_set_gdt 2
+#define __HYPERVISOR_stack_switch 3
+#define __HYPERVISOR_set_callbacks 4
+#define __HYPERVISOR_fpu_taskswitch 5
+#define __HYPERVISOR_sched_op 6
+#define __HYPERVISOR_dom0_op 7
+#define __HYPERVISOR_set_debugreg 8
+#define __HYPERVISOR_get_debugreg 9
+#define __HYPERVISOR_update_descriptor 10
+#define __HYPERVISOR_memory_op 12
+#define __HYPERVISOR_multicall 13
+#define __HYPERVISOR_update_va_mapping 14
+#define __HYPERVISOR_set_timer_op 15
+#define __HYPERVISOR_event_channel_op_compat 16
+#define __HYPERVISOR_xen_version 17
+#define __HYPERVISOR_console_io 18
+#define __HYPERVISOR_physdev_op_compat 19
+#define __HYPERVISOR_grant_table_op 20
+#define __HYPERVISOR_vm_assist 21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op 24
+#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op 26
+#define __HYPERVISOR_acm_op 27
+#define __HYPERVISOR_nmi_op 28
+#define __HYPERVISOR_sched_op_new 29
+#define __HYPERVISOR_callback_op 30
+#define __HYPERVISOR_xenoprof_op 31
+#define __HYPERVISOR_event_channel_op 32
+#define __HYPERVISOR_physdev_op 33
+#define __HYPERVISOR_hvm_op 34
+
+/*
+ * VIRTUAL INTERRUPTS
+ *
+ * Virtual interrupts that a guest OS may receive from Xen.
+ */
+#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */
+#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */
+#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */
+#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
+#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */
+#define NR_VIRQS 8
+
+/*
+ * MMU-UPDATE REQUESTS
+ *
+ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ * ptr[1:0] specifies the appropriate MMU_* command.
+ *
+ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
+ * Updates an entry in a page table. If updating an L1 table, and the new
+ * table entry is valid/present, the mapped frame must belong to the FD, if
+ * an FD has been specified. If attempting to map an I/O page then the
+ * caller assumes the privilege of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
+ * ptr[:2] -- Machine address of the page-table entry to modify.
+ * val -- Value to write.
+ *
+ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
+ * Updates an entry in the machine->pseudo-physical mapping table.
+ * ptr[:2] -- Machine address within the frame whose mapping to modify.
+ * The frame must belong to the FD, if one is specified.
+ * val -- Value to write into the mapping entry.
+ */
+#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
+#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
+
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ * The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ * when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ */
+#define MMUEXT_PIN_L1_TABLE 0
+#define MMUEXT_PIN_L2_TABLE 1
+#define MMUEXT_PIN_L3_TABLE 2
+#define MMUEXT_PIN_L4_TABLE 3
+#define MMUEXT_UNPIN_TABLE 4
+#define MMUEXT_NEW_BASEPTR 5
+#define MMUEXT_TLB_FLUSH_LOCAL 6
+#define MMUEXT_INVLPG_LOCAL 7
+#define MMUEXT_TLB_FLUSH_MULTI 8
+#define MMUEXT_INVLPG_MULTI 9
+#define MMUEXT_TLB_FLUSH_ALL 10
+#define MMUEXT_INVLPG_ALL 11
+#define MMUEXT_FLUSH_CACHE 12
+#define MMUEXT_SET_LDT 13
+#define MMUEXT_NEW_USER_BASEPTR 15
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+ unsigned int cmd;
+ union {
+ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
+ unsigned long mfn;
+ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+ unsigned long linear_addr;
+ } arg1;
+ union {
+ /* SET_LDT */
+ unsigned int nr_ents;
+ /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+ void *vcpumask;
+ } arg2;
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
+#endif
+
+/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
+/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */
+/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */
+#define UVMF_NONE (0UL<<0) /* No flushing at all. */
+#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */
+#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK (3UL<<0)
+#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */
+#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */
+
+/*
+ * Commands to HYPERVISOR_console_io().
+ */
+#define CONSOLEIO_write 0
+#define CONSOLEIO_read 1
+
+/*
+ * Commands to HYPERVISOR_vm_assist().
+ */
+#define VMASST_CMD_enable 0
+#define VMASST_CMD_disable 1
+#define VMASST_TYPE_4gb_segments 0
+#define VMASST_TYPE_4gb_segments_notify 1
+#define VMASST_TYPE_writable_pagetables 2
+#define VMASST_TYPE_pae_extended_cr3 3
+#define MAX_VMASST_TYPE 3
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF (0x7FF0U)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO (0x7FF1U)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN (0x7FF2U)
+
+/*
+ * Send an array of these to HYPERVISOR_mmu_update().
+ * NB. The fields are natural pointer/address size for this architecture.
+ */
+struct mmu_update {
+ uint64_t ptr; /* Machine address of PTE. */
+ uint64_t val; /* New contents of PTE. */
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmu_update);
+
+/*
+ * Send an array of these to HYPERVISOR_multicall().
+ * NB. The fields are natural register size for this architecture.
+ */
+struct multicall_entry {
+ unsigned long op;
+ long result;
+ unsigned long args[6];
+};
+DEFINE_GUEST_HANDLE_STRUCT(multicall_entry);
+
+/*
+ * Event channel endpoints per domain:
+ * 1024 if a long is 32 bits; 4096 if a long is 64 bits.
+ */
+#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
+
+struct vcpu_time_info {
+ /*
+ * Updates to the following values are preceded and followed
+ * by an increment of 'version'. The guest can therefore
+ * detect updates by looking for changes to 'version'. If the
+ * least-significant bit of the version number is set then an
+ * update is in progress and the guest must wait to read a
+ * consistent set of values. The correct way to interact with
+ * the version number is similar to Linux's seqlock: see the
+ * implementations of read_seqbegin/read_seqretry.
+ */
+ uint32_t version;
+ uint32_t pad0;
+ uint64_t tsc_timestamp; /* TSC at last update of time vals. */
+ uint64_t system_time; /* Time, in nanosecs, since boot. */
+ /*
+ * Current system time:
+ * system_time + ((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul
+ * CPU frequency (Hz):
+ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
+ */
+ uint32_t tsc_to_system_mul;
+ int8_t tsc_shift;
+ int8_t pad1[3];
+}; /* 32 bytes */
+
+struct vcpu_info {
+ /*
+ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+ * a pending notification for a particular VCPU. It is then cleared
+ * by the guest OS /before/ checking for pending work, thus avoiding
+ * a set-and-check race. Note that the mask is only accessed by Xen
+ * on the CPU that is currently hosting the VCPU. This means that the
+ * pending and mask flags can be updated by the guest without special
+ * synchronisation (i.e., no need for the x86 LOCK prefix).
+ * This may seem suboptimal because if the pending flag is set by
+ * a different CPU then an IPI may be scheduled even when the mask
+ * is set. However, note:
+ * 1. The task of 'interrupt holdoff' is covered by the per-event-
+ * channel mask bits. A 'noisy' event that is continually being
+ * triggered can be masked at source at this very precise
+ * granularity.
+ * 2. The main purpose of the per-VCPU mask is therefore to restrict
+ * reentrant execution: whether for concurrency control, or to
+ * prevent unbounded stack usage. Whatever the purpose, we expect
+ * that the mask will be asserted only for short periods at a time,
+ * and so the likelihood of a 'spurious' IPI is suitably small.
+ * The mask is read before making an event upcall to the guest: a
+ * non-zero mask therefore guarantees that the VCPU will not receive
+ * an upcall activation. The mask is cleared when the VCPU requests
+ * to block: this avoids wakeup-waiting races.
+ */
+ uint8_t evtchn_upcall_pending;
+ uint8_t evtchn_upcall_mask;
+ unsigned long evtchn_pending_sel;
+ struct arch_vcpu_info arch;
+ struct vcpu_time_info time;
+}; /* 64 bytes (x86) */
+
+/*
+ * Xen/kernel shared data -- pointer provided in start_info.
+ * NB. We expect that this struct is smaller than a page.
+ */
+struct shared_info {
+ struct vcpu_info vcpu_info[MAX_VIRT_CPUS];
+
+ /*
+ * A domain can create "event channels" on which it can send and receive
+ * asynchronous event notifications. There are three classes of event that
+ * are delivered by this mechanism:
+ * 1. Bi-directional inter- and intra-domain connections. Domains must
+ * arrange out-of-band to set up a connection (usually by allocating
+ * an unbound 'listener' port and avertising that via a storage service
+ * such as xenstore).
+ * 2. Physical interrupts. A domain with suitable hardware-access
+ * privileges can bind an event-channel port to a physical interrupt
+ * source.
+ * 3. Virtual interrupts ('events'). A domain can bind an event-channel
+ * port to a virtual interrupt source, such as the virtual-timer
+ * device or the emergency console.
+ *
+ * Event channels are addressed by a "port index". Each channel is
+ * associated with two bits of information:
+ * 1. PENDING -- notifies the domain that there is a pending notification
+ * to be processed. This bit is cleared by the guest.
+ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING
+ * will cause an asynchronous upcall to be scheduled. This bit is only
+ * updated by the guest. It is read-only within Xen. If a channel
+ * becomes pending while the channel is masked then the 'edge' is lost
+ * (i.e., when the channel is unmasked, the guest must manually handle
+ * pending notifications as no upcall will be scheduled by Xen).
+ *
+ * To expedite scanning of pending notifications, any 0->1 pending
+ * transition on an unmasked channel causes a corresponding bit in a
+ * per-vcpu selector word to be set. Each bit in the selector covers a
+ * 'C long' in the PENDING bitfield array.
+ */
+ unsigned long evtchn_pending[sizeof(unsigned long) * 8];
+ unsigned long evtchn_mask[sizeof(unsigned long) * 8];
+
+ /*
+ * Wallclock time: updated only by control software. Guests should base
+ * their gettimeofday() syscall on this wallclock-base value.
+ */
+ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
+ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
+ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
+
+ struct arch_shared_info arch;
+
+};
+
+/*
+ * Start-of-day memory layout for the initial domain (DOM0):
+ * 1. The domain is started within contiguous virtual-memory region.
+ * 2. The contiguous region begins and ends on an aligned 4MB boundary.
+ * 3. The region start corresponds to the load address of the OS image.
+ * If the load address is not 4MB aligned then the address is rounded down.
+ * 4. This the order of bootstrap elements in the initial virtual region:
+ * a. relocated kernel image
+ * b. initial ram disk [mod_start, mod_len]
+ * c. list of allocated page frames [mfn_list, nr_pages]
+ * d. start_info_t structure [register ESI (x86)]
+ * e. bootstrap page tables [pt_base, CR3 (x86)]
+ * f. bootstrap stack [register ESP (x86)]
+ * 5. Bootstrap elements are packed together, but each is 4kB-aligned.
+ * 6. The initial ram disk may be omitted.
+ * 7. The list of page frames forms a contiguous 'pseudo-physical' memory
+ * layout for the domain. In particular, the bootstrap virtual-memory
+ * region is a 1:1 mapping to the first section of the pseudo-physical map.
+ * 8. All bootstrap elements are mapped read-writable for the guest OS. The
+ * only exception is the bootstrap page table, which is mapped read-only.
+ * 9. There is guaranteed to be at least 512kB padding after the final
+ * bootstrap element. If necessary, the bootstrap virtual region is
+ * extended by an extra 4MB to ensure this.
+ */
+
+#define MAX_GUEST_CMDLINE 1024
+struct start_info {
+ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
+ char magic[32]; /* "xen-<version>-<platform>". */
+ unsigned long nr_pages; /* Total pages allocated to this domain. */
+ unsigned long shared_info; /* MACHINE address of shared info struct. */
+ uint32_t flags; /* SIF_xxx flags. */
+ unsigned long store_mfn; /* MACHINE page number of shared page. */
+ uint32_t store_evtchn; /* Event channel for store communication. */
+ union {
+ struct {
+ unsigned long mfn; /* MACHINE page number of console page. */
+ uint32_t evtchn; /* Event channel for console page. */
+ } domU;
+ struct {
+ uint32_t info_off; /* Offset of console_info struct. */
+ uint32_t info_size; /* Size of console_info struct from start.*/
+ } dom0;
+ } console;
+ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
+ unsigned long pt_base; /* VIRTUAL address of page directory. */
+ unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */
+ unsigned long mfn_list; /* VIRTUAL address of page-frame list. */
+ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */
+ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */
+ int8_t cmd_line[MAX_GUEST_CMDLINE];
+};
+
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
+#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
+
+typedef uint64_t cpumap_t;
+
+typedef uint8_t xen_domain_handle_t[16];
+
+/* Turn a plain number into a C unsigned long constant. */
+#define __mk_unsigned_long(x) x ## UL
+#define mk_unsigned_long(x) __mk_unsigned_long(x)
+
+#else /* __ASSEMBLY__ */
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define mk_unsigned_long(x) x
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_XEN_H__ */
diff --git a/include/xen/page.h b/include/xen/page.h
new file mode 100644
index 0000000..1df6c19
--- /dev/null
+++ b/include/xen/page.h
@@ -0,0 +1,179 @@
+#ifndef __XEN_PAGE_H
+#define __XEN_PAGE_H
+
+#include <linux/pfn.h>
+
+#include <asm/uaccess.h>
+
+#include <xen/features.h>
+
+#ifdef CONFIG_X86_PAE
+/* Xen machine address */
+typedef struct xmaddr {
+ unsigned long long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+ unsigned long long paddr;
+} xpaddr_t;
+#else
+/* Xen machine address */
+typedef struct xmaddr {
+ unsigned long maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+ unsigned long paddr;
+} xpaddr_t;
+#endif
+
+#define XMADDR(x) ((xmaddr_t) { .maddr = (x) })
+#define XPADDR(x) ((xpaddr_t) { .paddr = (x) })
+
+/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+#define INVALID_P2M_ENTRY (~0UL)
+#define FOREIGN_FRAME_BIT (1UL<<31)
+#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
+
+extern unsigned long *phys_to_machine_mapping;
+
+static inline unsigned long pfn_to_mfn(unsigned long pfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return pfn;
+
+ return phys_to_machine_mapping[(unsigned int)(pfn)] &
+ ~FOREIGN_FRAME_BIT;
+}
+
+static inline int phys_to_machine_mapping_valid(unsigned long pfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 1;
+
+ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
+}
+
+static inline unsigned long mfn_to_pfn(unsigned long mfn)
+{
+ unsigned long pfn;
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return mfn;
+
+#if 0
+ if (unlikely((mfn >> machine_to_phys_order) != 0))
+ return max_mapnr;
+#endif
+
+ pfn = 0;
+ /*
+ * The array access can fail (e.g., device space beyond end of RAM).
+ * In such cases it doesn't matter what we return (we return garbage),
+ * but we must handle the fault without crashing!
+ */
+ __get_user(pfn, &machine_to_phys_mapping[mfn]);
+
+ return pfn;
+}
+
+static inline xmaddr_t phys_to_machine(xpaddr_t phys)
+{
+ unsigned offset = phys.paddr & ~PAGE_MASK;
+ return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+}
+
+static inline xpaddr_t machine_to_phys(xmaddr_t machine)
+{
+ unsigned offset = machine.maddr & ~PAGE_MASK;
+ return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+}
+
+/*
+ * We detect special mappings in one of two ways:
+ * 1. If the MFN is an I/O page then Xen will set the m2p entry
+ * to be outside our maximum possible pseudophys range.
+ * 2. If the MFN belongs to a different domain then we will certainly
+ * not have MFN in our p2m table. Conversely, if the page is ours,
+ * then we'll have p2m(m2p(MFN))==MFN.
+ * If we detect a special mapping then it doesn't have a 'struct page'.
+ * We force !pfn_valid() by returning an out-of-range pointer.
+ *
+ * NB. These checks require that, for any MFN that is not in our reservation,
+ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
+ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
+ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
+ *
+ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
+ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
+ * require. In all the cases we care about, the FOREIGN_FRAME bit is
+ * masked (e.g., pfn_to_mfn()) so behaviour there is correct.
+ */
+static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
+{
+ extern unsigned long max_mapnr;
+ unsigned long pfn = mfn_to_pfn(mfn);
+ if ((pfn < max_mapnr)
+ && !xen_feature(XENFEAT_auto_translated_physmap)
+ && (phys_to_machine_mapping[pfn] != mfn))
+ return max_mapnr; /* force !pfn_valid() */
+ return pfn;
+}
+
+static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+ return;
+ }
+ phys_to_machine_mapping[pfn] = mfn;
+}
+
+/* VIRT <-> MACHINE conversion */
+#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
+#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
+#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+#ifdef CONFIG_X86_PAE
+#define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) | \
+ (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT)))
+
+static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
+{
+ pte_t pte;
+
+ pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) |
+ (pgprot_val(pgprot) >> 32);
+ pte.pte_high &= (__supported_pte_mask >> 32);
+ pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
+ pte.pte_low &= __supported_pte_mask;
+
+ return pte;
+}
+
+static inline unsigned long long pte_val_ma(pte_t x)
+{
+ return ((unsigned long long)x.pte_high << 32) | x.pte_low;
+}
+#define pmd_val_ma(v) ((v).pmd)
+#define pud_val_ma(v) ((v).pgd.pgd)
+#define __pte_ma(x) ((pte_t) { .pte_low = (x), .pte_high = (x)>>32 } )
+#define __pmd_ma(x) ((pmd_t) { (x) } )
+#else /* !X86_PAE */
+#define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
+#define mfn_pte(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_val_ma(x) ((x).pte_low)
+#define pmd_val_ma(v) ((v).pud.pgd.pgd)
+#define __pte_ma(x) ((pte_t) { (x) } )
+#endif /* CONFIG_X86_PAE */
+
+#define pgd_val_ma(x) ((x).pgd)
+
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address);
+void make_lowmem_page_readonly(void *vaddr);
+void make_lowmem_page_readwrite(void *vaddr);
+
+#endif /* __XEN_PAGE_H */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
new file mode 100644
index 0000000..6f7c290
--- /dev/null
+++ b/include/xen/xenbus.h
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * xenbus.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XEN_XENBUS_H
+#define _XEN_XENBUS_H
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/xenbus.h>
+#include <xen/interface/io/xs_wire.h>
+
+/* Register callback to watch this node. */
+struct xenbus_watch
+{
+ struct list_head list;
+
+ /* Path being watched. */
+ const char *node;
+
+ /* Callback (executed in a process context with no locks held). */
+ void (*callback)(struct xenbus_watch *,
+ const char **vec, unsigned int len);
+};
+
+
+/* A xenbus device. */
+struct xenbus_device {
+ const char *devicetype;
+ const char *nodename;
+ const char *otherend;
+ int otherend_id;
+ struct xenbus_watch otherend_watch;
+ struct device dev;
+ enum xenbus_state state;
+ struct completion down;
+};
+
+static inline struct xenbus_device *to_xenbus_device(struct device *dev)
+{
+ return container_of(dev, struct xenbus_device, dev);
+}
+
+struct xenbus_device_id
+{
+ /* .../device/<device_type>/<identifier> */
+ char devicetype[32]; /* General class of device. */
+};
+
+/* A xenbus driver. */
+struct xenbus_driver {
+ char *name;
+ struct module *owner;
+ const struct xenbus_device_id *ids;
+ int (*probe)(struct xenbus_device *dev,
+ const struct xenbus_device_id *id);
+ void (*otherend_changed)(struct xenbus_device *dev,
+ enum xenbus_state backend_state);
+ int (*remove)(struct xenbus_device *dev);
+ int (*suspend)(struct xenbus_device *dev);
+ int (*suspend_cancel)(struct xenbus_device *dev);
+ int (*resume)(struct xenbus_device *dev);
+ int (*uevent)(struct xenbus_device *, char **, int, char *, int);
+ struct device_driver driver;
+ int (*read_otherend_details)(struct xenbus_device *dev);
+};
+
+static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct xenbus_driver, driver);
+}
+
+int __must_check __xenbus_register_frontend(struct xenbus_driver *drv,
+ struct module *owner,
+ const char *mod_name);
+
+static inline int __must_check
+xenbus_register_frontend(struct xenbus_driver *drv)
+{
+ WARN_ON(drv->owner != THIS_MODULE);
+ return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
+ struct module *owner,
+ const char *mod_name);
+static inline int __must_check
+xenbus_register_backend(struct xenbus_driver *drv)
+{
+ WARN_ON(drv->owner != THIS_MODULE);
+ return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+void xenbus_unregister_driver(struct xenbus_driver *drv);
+
+struct xenbus_transaction
+{
+ u32 id;
+};
+
+/* Nil transaction ID. */
+#define XBT_NIL ((struct xenbus_transaction) { 0 })
+
+int __init xenbus_dev_init(void);
+
+char **xenbus_directory(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *num);
+void *xenbus_read(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *len);
+int xenbus_write(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *string);
+int xenbus_mkdir(struct xenbus_transaction t,
+ const char *dir, const char *node);
+int xenbus_exists(struct xenbus_transaction t,
+ const char *dir, const char *node);
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
+int xenbus_transaction_start(struct xenbus_transaction *t);
+int xenbus_transaction_end(struct xenbus_transaction t, int abort);
+
+/* Single read and scanf: returns -errno or num scanned if > 0. */
+int xenbus_scanf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+ __attribute__((format(scanf, 4, 5)));
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+ __attribute__((format(printf, 4, 5)));
+
+/* Generic read function: NULL-terminated triples of name,
+ * sprintf-style type string, and pointer. Returns 0 or errno.*/
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
+
+/* notifer routines for when the xenstore comes up */
+extern int xenstored_ready;
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
+int register_xenbus_watch(struct xenbus_watch *watch);
+void unregister_xenbus_watch(struct xenbus_watch *watch);
+void xs_suspend(void);
+void xs_resume(void);
+void xs_suspend_cancel(void);
+
+/* Used by xenbus_dev to borrow kernel's store connection. */
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
+
+struct work_struct;
+
+/* Prepare for domain suspend: then resume or cancel the suspend. */
+void xenbus_suspend(void);
+void xenbus_resume(void);
+void xenbus_probe(struct work_struct *);
+void xenbus_suspend_cancel(void);
+
+#define XENBUS_IS_ERR_READ(str) ({ \
+ if (!IS_ERR(str) && strlen(str) == 0) { \
+ kfree(str); \
+ str = ERR_PTR(-ERANGE); \
+ } \
+ IS_ERR(str); \
+})
+
+#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
+
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int));
+int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int),
+ const char *pathfmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
+int xenbus_map_ring_valloc(struct xenbus_device *dev,
+ int gnt_ref, void **vaddr);
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+ grant_handle_t *handle, void *vaddr);
+
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
+int xenbus_unmap_ring(struct xenbus_device *dev,
+ grant_handle_t handle, void *vaddr);
+
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+
+enum xenbus_state xenbus_read_driver_state(const char *path);
+
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...);
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...);
+
+const char *xenbus_strstate(enum xenbus_state state);
+int xenbus_dev_is_online(struct xenbus_device *dev);
+int xenbus_frontend_closed(struct xenbus_device *dev);
+
+#endif /* _XEN_XENBUS_H */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index b4796d8..57e6448 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -516,7 +516,7 @@
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[i] = NULL;
- call_usermodehelper(argv[0], argv, envp, 0);
+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
kfree(pathbuf);
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 4d32eb0..78d365c 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -119,9 +119,10 @@
char **argv;
char **envp;
struct key *ring;
- int wait;
+ enum umh_wait wait;
int retval;
struct file *stdin;
+ void (*cleanup)(char **argv, char **envp);
};
/*
@@ -180,6 +181,14 @@
do_exit(0);
}
+void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+ if (info->cleanup)
+ (*info->cleanup)(info->argv, info->envp);
+ kfree(info);
+}
+EXPORT_SYMBOL(call_usermodehelper_freeinfo);
+
/* Keventd can't block, but this (a child) can. */
static int wait_for_helper(void *data)
{
@@ -216,8 +225,8 @@
sub_info->retval = ret;
}
- if (sub_info->wait < 0)
- kfree(sub_info);
+ if (sub_info->wait == UMH_NO_WAIT)
+ call_usermodehelper_freeinfo(sub_info);
else
complete(sub_info->complete);
return 0;
@@ -229,102 +238,103 @@
struct subprocess_info *sub_info =
container_of(work, struct subprocess_info, work);
pid_t pid;
- int wait = sub_info->wait;
+ enum umh_wait wait = sub_info->wait;
/* CLONE_VFORK: wait until the usermode helper has execve'd
* successfully We need the data structures to stay around
* until that is done. */
- if (wait)
+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
pid = kernel_thread(wait_for_helper, sub_info,
CLONE_FS | CLONE_FILES | SIGCHLD);
else
pid = kernel_thread(____call_usermodehelper, sub_info,
CLONE_VFORK | SIGCHLD);
- if (wait < 0)
- return;
+ switch (wait) {
+ case UMH_NO_WAIT:
+ break;
- if (pid < 0) {
+ case UMH_WAIT_PROC:
+ if (pid > 0)
+ break;
sub_info->retval = pid;
+ /* FALLTHROUGH */
+
+ case UMH_WAIT_EXEC:
complete(sub_info->complete);
- } else if (!wait)
- complete(sub_info->complete);
+ }
}
/**
- * call_usermodehelper_keys - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
- * @session_keyring: session keyring for process (NULL for an empty keyring)
- * @wait: wait for the application to finish and return status.
- * when -1 don't wait at all, but you get no useful error back when
- * the program couldn't be exec'ed. This makes it safe to call
- * from interrupt context.
+ * call_usermodehelper_setup - prepare to call a usermode helper
+ * @path - path to usermode executable
+ * @argv - arg vector for process
+ * @envp - environment for process
*
- * Runs a user-space application. The application is started
- * asynchronously if wait is not set, and runs as a child of keventd.
- * (ie. it runs with full root capabilities).
- *
- * Must be called from process context. Returns a negative error code
- * if program was not execed successfully, or 0.
+ * Returns either NULL on allocation failure, or a subprocess_info
+ * structure. This should be passed to call_usermodehelper_exec to
+ * exec the process and free the structure.
*/
-int call_usermodehelper_keys(char *path, char **argv, char **envp,
- struct key *session_keyring, int wait)
+struct subprocess_info *call_usermodehelper_setup(char *path,
+ char **argv, char **envp)
{
- DECLARE_COMPLETION_ONSTACK(done);
struct subprocess_info *sub_info;
- int retval;
-
- if (!khelper_wq)
- return -EBUSY;
-
- if (path[0] == '\0')
- return 0;
-
sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC);
if (!sub_info)
- return -ENOMEM;
+ goto out;
INIT_WORK(&sub_info->work, __call_usermodehelper);
- sub_info->complete = &done;
sub_info->path = path;
sub_info->argv = argv;
sub_info->envp = envp;
- sub_info->ring = session_keyring;
- sub_info->wait = wait;
- queue_work(khelper_wq, &sub_info->work);
- if (wait < 0) /* task has freed sub_info */
- return 0;
- wait_for_completion(&done);
- retval = sub_info->retval;
- kfree(sub_info);
- return retval;
+ out:
+ return sub_info;
}
-EXPORT_SYMBOL(call_usermodehelper_keys);
+EXPORT_SYMBOL(call_usermodehelper_setup);
-int call_usermodehelper_pipe(char *path, char **argv, char **envp,
- struct file **filp)
+/**
+ * call_usermodehelper_setkeys - set the session keys for usermode helper
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @session_keyring: the session keyring for the process
+ */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+ struct key *session_keyring)
{
- DECLARE_COMPLETION(done);
- struct subprocess_info sub_info = {
- .work = __WORK_INITIALIZER(sub_info.work,
- __call_usermodehelper),
- .complete = &done,
- .path = path,
- .argv = argv,
- .envp = envp,
- .retval = 0,
- };
+ info->ring = session_keyring;
+}
+EXPORT_SYMBOL(call_usermodehelper_setkeys);
+
+/**
+ * call_usermodehelper_setcleanup - set a cleanup function
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @cleanup: a cleanup function
+ *
+ * The cleanup function is just befor ethe subprocess_info is about to
+ * be freed. This can be used for freeing the argv and envp. The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
+ */
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+ void (*cleanup)(char **argv, char **envp))
+{
+ info->cleanup = cleanup;
+}
+EXPORT_SYMBOL(call_usermodehelper_setcleanup);
+
+/**
+ * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
+ * @sub_info: a subprocess_info returned by call_usermodehelper_setup
+ * @filp: set to the write-end of a pipe
+ *
+ * This constructs a pipe, and sets the read end to be the stdin of the
+ * subprocess, and returns the write-end in *@filp.
+ */
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+ struct file **filp)
+{
struct file *f;
- if (!khelper_wq)
- return -EBUSY;
-
- if (path[0] == '\0')
- return 0;
-
f = create_write_pipe();
if (IS_ERR(f))
return PTR_ERR(f);
@@ -335,11 +345,85 @@
free_write_pipe(*filp);
return PTR_ERR(f);
}
- sub_info.stdin = f;
+ sub_info->stdin = f;
- queue_work(khelper_wq, &sub_info.work);
+ return 0;
+}
+EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+
+/**
+ * call_usermodehelper_exec - start a usermode application
+ * @sub_info: information about the subprocessa
+ * @wait: wait for the application to finish and return status.
+ * when -1 don't wait at all, but you get no useful error back when
+ * the program couldn't be exec'ed. This makes it safe to call
+ * from interrupt context.
+ *
+ * Runs a user-space application. The application is started
+ * asynchronously if wait is not set, and runs as a child of keventd.
+ * (ie. it runs with full root capabilities).
+ */
+int call_usermodehelper_exec(struct subprocess_info *sub_info,
+ enum umh_wait wait)
+{
+ DECLARE_COMPLETION_ONSTACK(done);
+ int retval;
+
+ if (sub_info->path[0] == '\0') {
+ retval = 0;
+ goto out;
+ }
+
+ if (!khelper_wq) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ sub_info->complete = &done;
+ sub_info->wait = wait;
+
+ queue_work(khelper_wq, &sub_info->work);
+ if (wait == UMH_NO_WAIT) /* task has freed sub_info */
+ return 0;
wait_for_completion(&done);
- return sub_info.retval;
+ retval = sub_info->retval;
+
+ out:
+ call_usermodehelper_freeinfo(sub_info);
+ return retval;
+}
+EXPORT_SYMBOL(call_usermodehelper_exec);
+
+/**
+ * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @filp: set to the write-end of a pipe
+ *
+ * This is a simple wrapper which executes a usermode-helper function
+ * with a pipe as stdin. It is implemented entirely in terms of
+ * lower-level call_usermodehelper_* functions.
+ */
+int call_usermodehelper_pipe(char *path, char **argv, char **envp,
+ struct file **filp)
+{
+ struct subprocess_info *sub_info;
+ int ret;
+
+ sub_info = call_usermodehelper_setup(path, argv, envp);
+ if (sub_info == NULL)
+ return -ENOMEM;
+
+ ret = call_usermodehelper_stdinpipe(sub_info, filp);
+ if (ret < 0)
+ goto out;
+
+ return call_usermodehelper_exec(sub_info, 1);
+
+ out:
+ call_usermodehelper_freeinfo(sub_info);
+ return ret;
}
EXPORT_SYMBOL(call_usermodehelper_pipe);
diff --git a/kernel/sys.c b/kernel/sys.c
index 4d141ae..18987c7 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2286,3 +2286,61 @@
}
return err ? -EFAULT : 0;
}
+
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+
+static void argv_cleanup(char **argv, char **envp)
+{
+ argv_free(argv);
+}
+
+/**
+ * orderly_poweroff - Trigger an orderly system poweroff
+ * @force: force poweroff if command execution fails
+ *
+ * This may be called from any context to trigger a system shutdown.
+ * If the orderly shutdown fails, it will force an immediate shutdown.
+ */
+int orderly_poweroff(bool force)
+{
+ int argc;
+ char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
+ static char *envp[] = {
+ "HOME=/",
+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
+ NULL
+ };
+ int ret = -ENOMEM;
+ struct subprocess_info *info;
+
+ if (argv == NULL) {
+ printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
+ __func__, poweroff_cmd);
+ goto out;
+ }
+
+ info = call_usermodehelper_setup(argv[0], argv, envp);
+ if (info == NULL) {
+ argv_free(argv);
+ goto out;
+ }
+
+ call_usermodehelper_setcleanup(info, argv_cleanup);
+
+ ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
+
+ out:
+ if (ret && force) {
+ printk(KERN_WARNING "Failed to start orderly shutdown: "
+ "forcing the issue\n");
+
+ /* I guess this should try to kick off some daemon to
+ sync and poweroff asap. Or not even bother syncing
+ if we're doing an emergency shutdown? */
+ emergency_sync();
+ kernel_power_off();
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(orderly_poweroff);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 7063ebc..44a1d69 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -46,6 +46,7 @@
#include <linux/syscalls.h>
#include <linux/nfs_fs.h>
#include <linux/acpi.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -705,6 +706,15 @@
.proc_handler = &proc_dointvec,
},
#endif
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "poweroff_cmd",
+ .data = &poweroff_cmd,
+ .maxlen = POWEROFF_CMD_PATH_LEN,
+ .mode = 0644,
+ .proc_handler = &proc_dostring,
+ .strategy = &sysctl_string,
+ },
{ .ctl_name = 0 }
};
diff --git a/lib/Makefile b/lib/Makefile
index da68b2c..6149663 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,7 +5,7 @@
lib-y := ctype.o string.o vsprintf.o cmdline.o \
rbtree.o radix-tree.o dump_stack.o \
idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \
- sha1.o irq_regs.o reciprocal_div.o
+ sha1.o irq_regs.o reciprocal_div.o argv_split.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/argv_split.c b/lib/argv_split.c
new file mode 100644
index 0000000..4096ed4
--- /dev/null
+++ b/lib/argv_split.c
@@ -0,0 +1,105 @@
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+static const char *skip_sep(const char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+
+ return cp;
+}
+
+static const char *skip_arg(const char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+
+ return cp;
+}
+
+static int count_argc(const char *str)
+{
+ int count = 0;
+
+ while (*str) {
+ str = skip_sep(str);
+ if (*str) {
+ count++;
+ str = skip_arg(str);
+ }
+ }
+
+ return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+ char **p;
+ for (p = argv; *p; p++)
+ kfree(*p);
+
+ kfree(argv);
+}
+EXPORT_SYMBOL(argv_free);
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @gfp: the GFP mask used to allocate memory
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str. This is performed by strictly splitting on white-space; no
+ * quote processing is performed. Multiple whitespace characters are
+ * considered to be a single argument separator. The returned array
+ * is always NULL-terminated. Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(gfp_t gfp, const char *str, int *argcp)
+{
+ int argc = count_argc(str);
+ char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
+ char **argvp;
+
+ if (argv == NULL)
+ goto out;
+
+ *argcp = argc;
+ argvp = argv;
+
+ while (*str) {
+ str = skip_sep(str);
+
+ if (*str) {
+ const char *p = str;
+ char *t;
+
+ str = skip_arg(str);
+
+ t = kstrndup(p, str-p, gfp);
+ if (t == NULL)
+ goto fail;
+ *argvp++ = t;
+ }
+ }
+ *argvp = NULL;
+
+ out:
+ return argv;
+
+ fail:
+ argv_free(argv);
+ return NULL;
+}
+EXPORT_SYMBOL(argv_split);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 12e311d..bd5ecbb 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -208,7 +208,7 @@
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
- call_usermodehelper (argv[0], argv, envp, 0);
+ call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
}
exit:
diff --git a/mm/util.c b/mm/util.c
index 78f3783..bf340d8 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -6,7 +6,6 @@
/**
* kstrdup - allocate space for and copy an existing string
- *
* @s: the string to duplicate
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
*/
@@ -27,6 +26,30 @@
EXPORT_SYMBOL(kstrdup);
/**
+ * kstrndup - allocate space for and copy an existing string
+ * @s: the string to duplicate
+ * @max: read at most @max chars from @s
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrndup(const char *s, size_t max, gfp_t gfp)
+{
+ size_t len;
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ len = strnlen(s, max);
+ buf = kmalloc_track_caller(len+1, gfp);
+ if (buf) {
+ memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+ return buf;
+}
+EXPORT_SYMBOL(kstrndup);
+
+/**
* kmemdup - duplicate region of memory
*
* @src: memory region to duplicate
@@ -80,7 +103,6 @@
/*
* strndup_user - duplicate an existing string from user space
- *
* @s: The string to duplicate
* @n: Maximum number of bytes to copy, including the trailing NUL.
*/
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 8e05a11..3130c34 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -767,3 +767,56 @@
void __attribute__((weak)) vmalloc_sync_all(void)
{
}
+
+
+static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
+{
+ /* apply_to_page_range() does all the hard work. */
+ return 0;
+}
+
+/**
+ * alloc_vm_area - allocate a range of kernel address space
+ * @size: size of the area
+ * @returns: NULL on failure, vm_struct on success
+ *
+ * This function reserves a range of kernel address space, and
+ * allocates pagetables to map that range. No actual mappings
+ * are created. If the kernel address space is not shared
+ * between processes, it syncs the pagetable across all
+ * processes.
+ */
+struct vm_struct *alloc_vm_area(size_t size)
+{
+ struct vm_struct *area;
+
+ area = get_vm_area(size, VM_IOREMAP);
+ if (area == NULL)
+ return NULL;
+
+ /*
+ * This ensures that page tables are constructed for this region
+ * of kernel virtual address space and mapped into init_mm.
+ */
+ if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
+ area->size, f, NULL)) {
+ free_vm_area(area);
+ return NULL;
+ }
+
+ /* Make sure the pagetables are constructed in process kernel
+ mappings */
+ vmalloc_sync_all();
+
+ return area;
+}
+EXPORT_SYMBOL_GPL(alloc_vm_area);
+
+void free_vm_area(struct vm_struct *area)
+{
+ struct vm_struct *ret;
+ ret = remove_vm_area(area->addr);
+ BUG_ON(ret != area);
+ kfree(area);
+}
+EXPORT_SYMBOL_GPL(free_vm_area);
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index faa6aaf..c0f6861 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -460,11 +460,7 @@
skb_pull(skb, plen);
skb_set_mac_header(skb, -ETH_HLEN);
skb->pkt_type = PACKET_HOST;
-#ifdef CONFIG_BR2684_FAST_TRANS
- skb->protocol = ((u16 *) skb->data)[-1];
-#else /* some protocols might require this: */
skb->protocol = br_type_trans(skb, net_dev);
-#endif /* CONFIG_BR2684_FAST_TRANS */
#else
skb_pull(skb, plen - ETH_HLEN);
skb->protocol = eth_type_trans(skb, net_dev);
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index a786e78..1ea2f86 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -125,7 +125,7 @@
char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
char *envp[] = { NULL };
- r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+ r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
if (r == 0) {
br->stp_enabled = BR_USER_STP;
printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
diff --git a/net/core/dev.c b/net/core/dev.c
index 13a0d9f..6357f54c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2715,20 +2715,6 @@
return 0;
}
-void __dev_addr_discard(struct dev_addr_list **list)
-{
- struct dev_addr_list *tmp;
-
- while (*list != NULL) {
- tmp = *list;
- *list = tmp->next;
- if (tmp->da_users > tmp->da_gusers)
- printk("__dev_addr_discard: address leakage! "
- "da_users=%d\n", tmp->da_users);
- kfree(tmp);
- }
-}
-
/**
* dev_unicast_delete - Release secondary unicast address.
* @dev: device
@@ -2777,11 +2763,30 @@
}
EXPORT_SYMBOL(dev_unicast_add);
-static void dev_unicast_discard(struct net_device *dev)
+static void __dev_addr_discard(struct dev_addr_list **list)
+{
+ struct dev_addr_list *tmp;
+
+ while (*list != NULL) {
+ tmp = *list;
+ *list = tmp->next;
+ if (tmp->da_users > tmp->da_gusers)
+ printk("__dev_addr_discard: address leakage! "
+ "da_users=%d\n", tmp->da_users);
+ kfree(tmp);
+ }
+}
+
+static void dev_addr_discard(struct net_device *dev)
{
netif_tx_lock_bh(dev);
+
__dev_addr_discard(&dev->uc_list);
dev->uc_count = 0;
+
+ __dev_addr_discard(&dev->mc_list);
+ dev->mc_count = 0;
+
netif_tx_unlock_bh(dev);
}
@@ -3739,8 +3744,7 @@
/*
* Flush the unicast and multicast chains
*/
- dev_unicast_discard(dev);
- dev_mc_discard(dev);
+ dev_addr_discard(dev);
if (dev->uninit)
dev->uninit(dev);
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 235a2a8..99aece1 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -177,18 +177,6 @@
}
EXPORT_SYMBOL(dev_mc_unsync);
-/*
- * Discard multicast list when a device is downed
- */
-
-void dev_mc_discard(struct net_device *dev)
-{
- netif_tx_lock_bh(dev);
- __dev_addr_discard(&dev->mc_list);
- dev->mc_count = 0;
- netif_tx_unlock_bh(dev);
-}
-
#ifdef CONFIG_PROC_FS
static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
{
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index cc84d8d..590a767 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -79,27 +79,27 @@
struct gen_estimator
{
- struct gen_estimator *next;
+ struct list_head list;
struct gnet_stats_basic *bstats;
struct gnet_stats_rate_est *rate_est;
spinlock_t *stats_lock;
- unsigned interval;
int ewma_log;
u64 last_bytes;
u32 last_packets;
u32 avpps;
u32 avbps;
+ struct rcu_head e_rcu;
};
struct gen_estimator_head
{
struct timer_list timer;
- struct gen_estimator *list;
+ struct list_head list;
};
static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
-/* Estimator array lock */
+/* Protects against NULL dereference */
static DEFINE_RWLOCK(est_lock);
static void est_timer(unsigned long arg)
@@ -107,13 +107,17 @@
int idx = (int)arg;
struct gen_estimator *e;
- read_lock(&est_lock);
- for (e = elist[idx].list; e; e = e->next) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(e, &elist[idx].list, list) {
u64 nbytes;
u32 npackets;
u32 rate;
spin_lock(e->stats_lock);
+ read_lock(&est_lock);
+ if (e->bstats == NULL)
+ goto skip;
+
nbytes = e->bstats->bytes;
npackets = e->bstats->packets;
rate = (nbytes - e->last_bytes)<<(7 - idx);
@@ -125,12 +129,14 @@
e->last_packets = npackets;
e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
e->rate_est->pps = (e->avpps+0x1FF)>>10;
+skip:
+ read_unlock(&est_lock);
spin_unlock(e->stats_lock);
}
- if (elist[idx].list != NULL)
+ if (!list_empty(&elist[idx].list))
mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
- read_unlock(&est_lock);
+ rcu_read_unlock();
}
/**
@@ -147,12 +153,17 @@
* &rate_est with the statistics lock grabed during this period.
*
* Returns 0 on success or a negative error code.
+ *
+ * NOTE: Called under rtnl_mutex
*/
int gen_new_estimator(struct gnet_stats_basic *bstats,
- struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
+ struct gnet_stats_rate_est *rate_est,
+ spinlock_t *stats_lock,
+ struct rtattr *opt)
{
struct gen_estimator *est;
struct gnet_estimator *parm = RTA_DATA(opt);
+ int idx;
if (RTA_PAYLOAD(opt) < sizeof(*parm))
return -EINVAL;
@@ -164,7 +175,7 @@
if (est == NULL)
return -ENOBUFS;
- est->interval = parm->interval + 2;
+ idx = parm->interval + 2;
est->bstats = bstats;
est->rate_est = rate_est;
est->stats_lock = stats_lock;
@@ -174,20 +185,25 @@
est->last_packets = bstats->packets;
est->avpps = rate_est->pps<<10;
- est->next = elist[est->interval].list;
- if (est->next == NULL) {
- init_timer(&elist[est->interval].timer);
- elist[est->interval].timer.data = est->interval;
- elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
- elist[est->interval].timer.function = est_timer;
- add_timer(&elist[est->interval].timer);
+ if (!elist[idx].timer.function) {
+ INIT_LIST_HEAD(&elist[idx].list);
+ setup_timer(&elist[idx].timer, est_timer, idx);
}
- write_lock_bh(&est_lock);
- elist[est->interval].list = est;
- write_unlock_bh(&est_lock);
+
+ if (list_empty(&elist[idx].list))
+ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+
+ list_add_rcu(&est->list, &elist[idx].list);
return 0;
}
+static void __gen_kill_estimator(struct rcu_head *head)
+{
+ struct gen_estimator *e = container_of(head,
+ struct gen_estimator, e_rcu);
+ kfree(e);
+}
+
/**
* gen_kill_estimator - remove a rate estimator
* @bstats: basic statistics
@@ -195,31 +211,32 @@
*
* Removes the rate estimator specified by &bstats and &rate_est
* and deletes the timer.
+ *
+ * NOTE: Called under rtnl_mutex
*/
void gen_kill_estimator(struct gnet_stats_basic *bstats,
struct gnet_stats_rate_est *rate_est)
{
int idx;
- struct gen_estimator *est, **pest;
+ struct gen_estimator *e, *n;
for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
- int killed = 0;
- pest = &elist[idx].list;
- while ((est=*pest) != NULL) {
- if (est->rate_est != rate_est || est->bstats != bstats) {
- pest = &est->next;
+
+ /* Skip non initialized indexes */
+ if (!elist[idx].timer.function)
+ continue;
+
+ list_for_each_entry_safe(e, n, &elist[idx].list, list) {
+ if (e->rate_est != rate_est || e->bstats != bstats)
continue;
- }
write_lock_bh(&est_lock);
- *pest = est->next;
+ e->bstats = NULL;
write_unlock_bh(&est_lock);
- kfree(est);
- killed++;
+ list_del_rcu(&e->list);
+ call_rcu(&e->e_rcu, __gen_kill_estimator);
}
- if (killed && elist[idx].list == NULL)
- del_timer(&elist[idx].timer);
}
}
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index dd9ef65..519de09 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -137,7 +137,7 @@
}
static void bictcp_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int data_acked)
+ u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
struct bictcp *ca = inet_csk_ca(sk);
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 1260e52..55fca18 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -324,8 +324,7 @@
/* This is Jacobson's slow start and congestion avoidance.
* SIGCOMM '88, p. 328.
*/
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
- int flag)
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index ebfaac2..d17da30 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -270,7 +270,7 @@
}
static void bictcp_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int data_acked)
+ u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
struct bictcp *ca = inet_csk_ca(sk);
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index 43d624e5..14a073d 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -109,7 +109,7 @@
tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
}
-static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
+static void hstcp_cong_avoid(struct sock *sk, u32 adk,
u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 4ba4a7a..632c05a 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -225,7 +225,7 @@
return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
}
-static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void htcp_cong_avoid(struct sock *sk, u32 ack, s32 rtt,
u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index e5be351..b3e55cf 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -85,7 +85,7 @@
* o Give cwnd a new value based on the model proposed
* o remember increments <1
*/
-static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void hybla_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -103,7 +103,7 @@
return;
if (!ca->hybla_en)
- return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
if (ca->rho == 0)
hybla_recalc_param(sk);
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
index b2b2256..cc5de6f 100644
--- a/net/ipv4/tcp_illinois.c
+++ b/net/ipv4/tcp_illinois.c
@@ -258,7 +258,7 @@
/*
* Increase window in response to successful acknowledgment.
*/
-static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4e5884a..fec8a7a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2323,11 +2323,11 @@
tcp_ack_no_tstamp(sk, seq_rtt, flag);
}
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int good)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
- icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+ icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight, good);
tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
}
@@ -2826,11 +2826,11 @@
/* Advance CWND, if state allows this. */
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
tcp_may_raise_cwnd(sk, flag))
- tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 0);
+ tcp_cong_avoid(sk, ack, prior_in_flight, 0);
tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
} else {
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
- tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
+ tcp_cong_avoid(sk, ack, prior_in_flight, 1);
}
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index e49836c..80e140e 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -115,13 +115,12 @@
* Will only call newReno CA when away from inference.
* From TCP-LP's paper, this will be handled in additive increasement.
*/
-static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
- int flag)
+static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
{
struct lp *lp = inet_csk_ca(sk);
if (!(lp->flag & LP_WITHIN_INF))
- tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
}
/**
diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
index 4624501..be27a33 100644
--- a/net/ipv4/tcp_scalable.c
+++ b/net/ipv4/tcp_scalable.c
@@ -15,7 +15,7 @@
#define TCP_SCALABLE_AI_CNT 50U
#define TCP_SCALABLE_MD_SCALE 3
-static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index e218a51..914e030 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -163,13 +163,13 @@
EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct vegas *vegas = inet_csk_ca(sk);
if (!vegas->doing_vegas_now)
- return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
/* The key players are v_beg_snd_una and v_beg_snd_nxt.
*
@@ -228,7 +228,7 @@
/* We don't have enough RTT samples to do the Vegas
* calculation, so we'll behave like Reno.
*/
- tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
} else {
u32 rtt, target_cwnd, diff;
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index ec854cc..7a55ddf 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -115,13 +115,13 @@
}
static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct veno *veno = inet_csk_ca(sk);
if (!veno->doing_veno_now)
- return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
/* limited by applications */
if (!tcp_is_cwnd_limited(sk, in_flight))
@@ -132,7 +132,7 @@
/* We don't have enough rtt samples to do the Veno
* calculation, so we'll behave like Reno.
*/
- tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
} else {
u32 rtt, target_cwnd;
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index 545ed23..c04b7c6 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -70,7 +70,7 @@
}
static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct yeah *yeah = inet_csk_ca(sk);
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index dcd7e32..4c670cf 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2567,7 +2567,7 @@
* Remove IrDA protocol
*
*/
-void __exit irsock_cleanup(void)
+void irsock_cleanup(void)
{
sock_unregister(PF_IRDA);
proto_unregister(&irda_proto);
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 7b5def1..435b563 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -95,14 +95,14 @@
return 0;
}
-static void __exit leftover_dongle(void *arg)
+static void leftover_dongle(void *arg)
{
struct dongle_reg *reg = arg;
IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
reg->type);
}
-void __exit irda_device_cleanup(void)
+void irda_device_cleanup(void)
{
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 774eb70..ee3889f 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -153,7 +153,7 @@
* Initializes the IrIAP layer, called by the module cleanup code in
* irmod.c
*/
-void __exit iriap_cleanup(void)
+void iriap_cleanup(void)
{
irlmp_unregister_service(service_handle);
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index 4adaae2..cf30245 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -36,39 +36,6 @@
*/
struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
-/*
- * Function strndup (str, max)
- *
- * My own kernel version of strndup!
- *
- * Faster, check boundary... Jean II
- */
-static char *strndup(char *str, size_t max)
-{
- char *new_str;
- int len;
-
- /* Check string */
- if (str == NULL)
- return NULL;
- /* Check length, truncate */
- len = strlen(str);
- if(len > max)
- len = max;
-
- /* Allocate new string */
- new_str = kmalloc(len + 1, GFP_ATOMIC);
- if (new_str == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
- return NULL;
- }
-
- /* Copy and truncate */
- memcpy(new_str, str, len);
- new_str[len] = '\0';
-
- return new_str;
-}
/*
* Function ias_new_object (name, id)
@@ -90,7 +57,7 @@
}
obj->magic = IAS_OBJECT_MAGIC;
- obj->name = strndup(name, IAS_MAX_CLASSNAME);
+ obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
if (!obj->name) {
IRDA_WARNING("%s(), Unable to allocate name!\n",
__FUNCTION__);
@@ -360,7 +327,7 @@
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
/* Insert value */
attrib->value = irias_new_integer_value(value);
@@ -404,7 +371,7 @@
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
attrib->value = irias_new_octseq_value( octets, len);
if (!attrib->name || !attrib->value) {
@@ -446,7 +413,7 @@
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
attrib->value = irias_new_string_value(value);
if (!attrib->name || !attrib->value) {
@@ -506,7 +473,7 @@
value->type = IAS_STRING;
value->charset = CS_ASCII;
- value->t.string = strndup(string, IAS_MAX_STRING);
+ value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
if (!value->t.string) {
IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
kfree(value);
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 2fc9f51..3d76aaf 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -95,7 +95,7 @@
return 0;
}
-void __exit irlap_cleanup(void)
+void irlap_cleanup(void)
{
IRDA_ASSERT(irlap != NULL, return;);
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 24a5e3f..7efa930 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -116,7 +116,7 @@
* Remove IrLMP layer
*
*/
-void __exit irlmp_cleanup(void)
+void irlmp_cleanup(void)
{
/* Check for main structure */
IRDA_ASSERT(irlmp != NULL, return;);
diff --git a/net/irda/irproc.c b/net/irda/irproc.c
index d6f9aba..181cb51 100644
--- a/net/irda/irproc.c
+++ b/net/irda/irproc.c
@@ -84,7 +84,7 @@
* Unregister irda entry in /proc file system
*
*/
-void __exit irda_proc_unregister(void)
+void irda_proc_unregister(void)
{
int i;
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 2e968e7..957e04f 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -287,7 +287,7 @@
* Unregister our sysctl interface
*
*/
-void __exit irda_sysctl_unregister(void)
+void irda_sysctl_unregister(void)
{
unregister_sysctl_table(irda_table_header);
}
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 7f50832a..3d7ab03 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -109,7 +109,7 @@
* Called by module destruction/cleanup code
*
*/
-void __exit irttp_cleanup(void)
+void irttp_cleanup(void)
{
/* Check for main structure */
IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 3ac39f1..3599770 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -436,6 +436,7 @@
config NETFILTER_XT_MATCH_CONNLIMIT
tristate '"connlimit" match support"'
depends on NETFILTER_XTABLES
+ depends on NF_CONNTRACK
---help---
This match allows you to match against the number of parallel
connections to a server per client IP address (or address block).
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a3c8e69..641cfbc 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1012,13 +1012,14 @@
{
struct sock *sk = sock->sk;
struct netlink_sock *nlk = nlk_sk(sk);
- int val = 0, err;
+ unsigned int val = 0;
+ int err;
if (level != SOL_NETLINK)
return -ENOPROTOOPT;
if (optlen >= sizeof(int) &&
- get_user(val, (int __user *)optval))
+ get_user(val, (unsigned int __user *)optval))
return -EFAULT;
switch (optname) {
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index d3f7c3f..8a74cac 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -97,7 +97,7 @@
select classes of this queuing discipline. Each class maps
the flow(s) it is handling to a given virtual circuit.
- See the top of <file:net/sched/sch_atm.c>) for more details.
+ See the top of <file:net/sched/sch_atm.c> for more details.
To compile this code as a module, choose M here: the
module will be called sch_atm.
@@ -137,7 +137,7 @@
tristate "Stochastic Fairness Queueing (SFQ)"
---help---
Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
- packet scheduling algorithm .
+ packet scheduling algorithm.
See the top of <file:net/sched/sch_sfq.c> for more details.
@@ -306,7 +306,7 @@
is important for real time data such as streaming sound or video.
Say Y here if you want to be able to classify outgoing packets based
- on their RSVP requests and you are using the IPv6.
+ on their RSVP requests and you are using the IPv6 protocol.
To compile this code as a module, choose M here: the
module will be called cls_rsvp6.
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 417ec8f..ddc4f2c 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -292,13 +292,12 @@
}
}
DPRINTK("atm_tc_change: new id %x\n", classid);
- flow = kmalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
+ flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
DPRINTK("atm_tc_change: flow %p\n", flow);
if (!flow) {
error = -ENOBUFS;
goto err_out;
}
- memset(flow, 0, sizeof(*flow));
flow->filter_list = NULL;
if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
flow->q = &noop_qdisc;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 157bfbd..b48f06f 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2141,7 +2141,7 @@
if (last == first)
break;
- last = last->u.next;
+ last = (struct xfrm_dst *)last->u.dst.next;
last->child_mtu_cached = mtu;
}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f573ac1..5575001 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -108,7 +108,8 @@
argv[i] = NULL;
/* do it */
- ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
+ ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
+ UMH_WAIT_PROC);
error_link:
key_put(keyring);