Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
  pkt_sched: Fix build with NET_SCHED disabled.
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index 15838d7..44c97e6 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -233,12 +233,10 @@
 config_item_type.
 
 	struct configfs_group_operations {
-		int (*make_item)(struct config_group *group,
-				 const char *name,
-				 struct config_item **new_item);
-		int (*make_group)(struct config_group *group,
-				  const char *name,
-				  struct config_group **new_group);
+		struct config_item *(*make_item)(struct config_group *group,
+						 const char *name);
+		struct config_group *(*make_group)(struct config_group *group,
+						   const char *name);
 		int (*commit_item)(struct config_item *item);
 		void (*disconnect_notify)(struct config_group *group,
 					  struct config_item *item);
diff --git a/Documentation/filesystems/configfs/configfs_example.c b/Documentation/filesystems/configfs/configfs_example.c
index 0b422ac..03964879 100644
--- a/Documentation/filesystems/configfs/configfs_example.c
+++ b/Documentation/filesystems/configfs/configfs_example.c
@@ -273,13 +273,13 @@
 	return item ? container_of(to_config_group(item), struct simple_children, group) : NULL;
 }
 
-static int simple_children_make_item(struct config_group *group, const char *name, struct config_item **new_item)
+static struct config_item *simple_children_make_item(struct config_group *group, const char *name)
 {
 	struct simple_child *simple_child;
 
 	simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
 	if (!simple_child)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 
 	config_item_init_type_name(&simple_child->item, name,
@@ -287,8 +287,7 @@
 
 	simple_child->storeme = 0;
 
-	*new_item = &simple_child->item;
-	return 0;
+	return &simple_child->item;
 }
 
 static struct configfs_attribute simple_children_attr_description = {
@@ -360,21 +359,20 @@
  * children of its own.
  */
 
-static int group_children_make_group(struct config_group *group, const char *name, struct config_group **new_group)
+static struct config_group *group_children_make_group(struct config_group *group, const char *name)
 {
 	struct simple_children *simple_children;
 
 	simple_children = kzalloc(sizeof(struct simple_children),
 				  GFP_KERNEL);
 	if (!simple_children)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 
 	config_group_init_type_name(&simple_children->group, name,
 				    &simple_children_type);
 
-	*new_group = &simple_children->group;
-	return 0;
+	return &simple_children->group;
 }
 
 static struct configfs_attribute group_children_attr_description = {
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index 88ad615..77ba0af 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -186,6 +186,17 @@
 	Locking: port_sem taken.
 	Interrupts: caller dependent.
 
+  flush_buffer(port)
+	Flush any write buffers, reset any DMA state and stop any
+	ongoing DMA transfers.
+
+	This will be called whenever the port->info->xmit circular
+	buffer is cleared.
+
+	Locking: port->lock taken.
+	Interrupts: locally disabled.
+	This call must not sleep
+
   set_termios(port,termios,oldtermios)
 	Change the port parameters, including word length, parity, stop
 	bits.  Update read_status_mask and ignore_status_mask to indicate
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 191194e..f0e613b 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -8,3 +8,4 @@
   7 -> Hauppauge WinTV-HVR1200                             [0070:71d1,0070:71d3]
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
+ 10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 1d6a245..1059146 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -8,10 +8,13 @@
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
   9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
- 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500,2040:6502]
+ 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
  14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513,2040:6517,2040:651b,2040:651f]
+ 17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
+ 18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
+ 19 -> PointNix Intra-Oral Camera               (em2860)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 67937df..39868af 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -37,7 +37,7 @@
  36 -> UPMOST PURPLE TV                         [12ab:0800]
  37 -> Items MuchTV Plus / IT-005
  38 -> Terratec Cinergy 200 TV                  [153b:1152]
- 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212]
+ 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212,5169:1502]
  40 -> Compro VideoMate TV PVR/FM               [185b:c100]
  41 -> Compro VideoMate TV Gold+                [185b:c100]
  42 -> Sabrent SBT-TVFM (saa7130)
@@ -128,7 +128,7 @@
 127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
 129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
-130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193,5ace:6191]
+130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
 133 -> NXP Snake DVB-S reference design
@@ -141,3 +141,7 @@
 140 -> Avermedia DVB-S Pro A700                 [1461:a7a1]
 141 -> Avermedia DVB-S Hybrid+FM A700           [1461:a7a2]
 142 -> Beholder BeholdTV H6                     [5ace:6290]
+143 -> Beholder BeholdTV M63                    [5ace:6191]
+144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
+146 -> ASUSTeK P7131 Analog
diff --git a/Documentation/video4linux/cx18.txt b/Documentation/video4linux/cx18.txt
index 6842c26..914cb7e 100644
--- a/Documentation/video4linux/cx18.txt
+++ b/Documentation/video4linux/cx18.txt
@@ -1,36 +1,30 @@
 Some notes regarding the cx18 driver for the Conexant CX23418 MPEG
 encoder chip:
 
-1) The only hardware currently supported is the Hauppauge HVR-1600
-   card and the Compro VideoMate H900 (note that this card only
-   supports analog input, it has no digital tuner!).
+1) Currently supported are:
 
-2) Some people have problems getting the i2c bus to work. Cause unknown.
+	- Hauppauge HVR-1600
+	- Compro VideoMate H900
+	- Yuan MPC718
+	- Conexant Raptor PAL/SECAM devkit
+
+2) Some people have problems getting the i2c bus to work.
    The symptom is that the eeprom cannot be read and the card is
-   unusable.
+   unusable. This is probably fixed, but if you have problems
+   then post to the video4linux or ivtv-users mailinglist.
 
-3) The audio from the analog tuner is mono only. Probably caused by
-   incorrect audio register information in the datasheet. We are
-   waiting for updated information from Conexant.
+3) VBI (raw or sliced) has not yet been implemented.
 
-4) VBI (raw or sliced) has not yet been implemented.
+4) MPEG indexing is not yet implemented.
 
-5) MPEG indexing is not yet implemented.
-
-6) The driver is still a bit rough around the edges, this should
+5) The driver is still a bit rough around the edges, this should
    improve over time.
 
 
 Firmware:
 
-The firmware needs to be extracted from the Windows Hauppauge HVR-1600
-driver, available here:
+You can obtain the firmware files here:
 
-http://hauppauge.lightpath.net/software/install_cd/hauppauge_cd_3.4d1.zip
+http://dl.ivtvdriver.org/ivtv/firmware/cx18-firmware.tar.gz
 
-Unzip, then copy the following files to the firmware directory
-and rename them as follows:
-
-Drivers/Driver18/hcw18apu.rom -> v4l-cx23418-apu.fw
-Drivers/Driver18/hcw18enc.rom -> v4l-cx23418-cpu.fw
-Drivers/Driver18/hcw18mlC.rom -> v4l-cx23418-dig.fw
+Untar and copy the .fw files to your firmware directory.
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
new file mode 100644
index 0000000..0c4880a
--- /dev/null
+++ b/Documentation/video4linux/gspca.txt
@@ -0,0 +1,243 @@
+List of the webcams know by gspca.
+
+The modules are:
+	gspca_main	main driver
+	gspca_xxxx	subdriver module with xxxx as follows
+
+xxxx		vend:prod
+----
+spca501		0000:0000	MystFromOri Unknow Camera
+spca501		040a:0002	Kodak DVC-325
+spca500		040a:0300	Kodak EZ200
+zc3xx		041e:041e	Creative WebCam Live!
+spca500		041e:400a	Creative PC-CAM 300
+sunplus		041e:400b	Creative PC-CAM 600
+sunplus		041e:4012	PC-Cam350
+sunplus		041e:4013	Creative Pccam750
+zc3xx		041e:4017	Creative Webcam Mobile PD1090
+spca508		041e:4018	Creative Webcam Vista (PD1100)
+spca561		041e:401a	Creative Webcam Vista (PD1100)
+zc3xx		041e:401c	Creative NX
+spca505		041e:401d	Creative Webcam NX ULTRA
+zc3xx		041e:401e	Creative Nx Pro
+zc3xx		041e:401f	Creative Webcam Notebook PD1171
+pac207		041e:4028	Creative Webcam Vista Plus
+zc3xx		041e:4029	Creative WebCam Vista Pro
+zc3xx		041e:4034	Creative Instant P0620
+zc3xx		041e:4035	Creative Instant P0620D
+zc3xx		041e:4036	Creative Live !
+zc3xx		041e:403a	Creative Nx Pro 2
+spca561		041e:403b	Creative Webcam Vista (VF0010)
+zc3xx		041e:4051	Creative Live!Cam Notebook Pro (VF0250)
+ov519		041e:4052	Creative Live! VISTA IM
+zc3xx		041e:4053	Creative Live!Cam Video IM
+ov519		041e:405f	Creative Live! VISTA VF0330
+ov519		041e:4060	Creative Live! VISTA VF0350
+ov519		041e:4061	Creative Live! VISTA VF0400
+ov519		041e:4064	Creative Live! VISTA VF0420
+ov519		041e:4068	Creative Live! VISTA VF0470
+spca561		0458:7004	Genius VideoCAM Express V2
+sunplus		0458:7006	Genius Dsc 1.3 Smart
+zc3xx		0458:7007	Genius VideoCam V2
+zc3xx		0458:700c	Genius VideoCam V3
+zc3xx		0458:700f	Genius VideoCam Web V2
+sonixj		0458:7025	Genius Eye 311Q
+sonixj		045e:00f5	MicroSoft VX3000
+sonixj		045e:00f7	MicroSoft VX1000
+ov519		045e:028c	Micro$oft xbox cam
+spca508		0461:0815	Micro Innovation IC200
+sunplus		0461:0821	Fujifilm MV-1
+zc3xx		0461:0a00	MicroInnovation WebCam320
+spca500		046d:0890	Logitech QuickCam traveler
+vc032x		046d:0892	Logitech Orbicam
+vc032x		046d:0896	Logitech Orbicam
+zc3xx		046d:08a0	Logitech QC IM
+zc3xx		046d:08a1	Logitech QC IM 0x08A1 +sound
+zc3xx		046d:08a2	Labtec Webcam Pro
+zc3xx		046d:08a3	Logitech QC Chat
+zc3xx		046d:08a6	Logitech QCim
+zc3xx		046d:08a7	Logitech QuickCam Image
+zc3xx		046d:08a9	Logitech Notebook Deluxe
+zc3xx		046d:08aa	Labtec Webcam  Notebook
+zc3xx		046d:08ac	Logitech QuickCam Cool
+zc3xx		046d:08ad	Logitech QCCommunicate STX
+zc3xx		046d:08ae	Logitech QuickCam for Notebooks
+zc3xx		046d:08af	Logitech QuickCam Cool
+zc3xx		046d:08b9	Logitech QC IM ???
+zc3xx		046d:08d7	Logitech QCam STX
+zc3xx		046d:08d9	Logitech QuickCam IM/Connect
+zc3xx		046d:08d8	Logitech Notebook Deluxe
+zc3xx		046d:08da	Logitech QuickCam Messenger
+zc3xx		046d:08dd	Logitech QuickCam for Notebooks
+spca500		046d:0900	Logitech Inc. ClickSmart 310
+spca500		046d:0901	Logitech Inc. ClickSmart 510
+sunplus		046d:0905	Logitech ClickSmart 820
+tv8532		046d:0920	QC Express
+tv8532		046d:0921	Labtec Webcam
+spca561		046d:0928	Logitech QC Express Etch2
+spca561		046d:0929	Labtec Webcam Elch2
+spca561		046d:092a	Logitech QC for Notebook
+spca561		046d:092b	Labtec Webcam Plus
+spca561		046d:092c	Logitech QC chat Elch2
+spca561		046d:092d	Logitech QC Elch2
+spca561		046d:092e	Logitech QC Elch2
+spca561		046d:092f	Logitech QC Elch2
+sunplus		046d:0960	Logitech ClickSmart 420
+sunplus		0471:0322	Philips DMVC1300K
+zc3xx		0471:0325	Philips SPC 200 NC
+zc3xx		0471:0326	Philips SPC 300 NC
+sonixj		0471:0327	Philips SPC 600 NC
+sonixj		0471:0328	Philips SPC 700 NC
+zc3xx		0471:032d	Philips spc210nc
+zc3xx		0471:032e	Philips spc315nc
+sonixj		0471:0330	Philips SPC 710NC
+spca501		0497:c001	Smile International
+sunplus		04a5:3003	Benq DC 1300
+sunplus		04a5:3008	Benq DC 1500
+sunplus		04a5:300a	Benq DC3410
+spca500		04a5:300c	Benq DC1016
+sunplus		04f1:1001	JVC GC A50
+spca561		04fc:0561	Flexcam 100
+sunplus		04fc:500c	Sunplus CA500C
+sunplus		04fc:504a	Aiptek Mini PenCam 1.3
+sunplus		04fc:504b	Maxell MaxPocket LE 1.3
+sunplus		04fc:5330	Digitrex 2110
+sunplus		04fc:5360	Sunplus Generic
+spca500		04fc:7333	PalmPixDC85
+sunplus		04fc:ffff	Pure DigitalDakota
+spca501		0506:00df	3Com HomeConnect Lite
+sunplus		052b:1513	Megapix V4
+tv8532		0545:808b	Veo Stingray
+tv8532		0545:8333	Veo Stingray
+sunplus		0546:3155	Polaroid PDC3070
+sunplus		0546:3191	Polaroid Ion 80
+sunplus		0546:3273	Polaroid PDC2030
+ov519		054c:0154	Sonny toy4
+ov519		054c:0155	Sonny toy5
+zc3xx		055f:c005	Mustek Wcam300A
+spca500		055f:c200	Mustek Gsmart 300
+sunplus		055f:c211	Kowa Bs888e Microcamera
+spca500		055f:c220	Gsmart Mini
+sunplus		055f:c230	Mustek Digicam 330K
+sunplus		055f:c232	Mustek MDC3500
+sunplus		055f:c360	Mustek DV4000 Mpeg4
+sunplus		055f:c420	Mustek gSmart Mini 2
+sunplus		055f:c430	Mustek Gsmart LCD 2
+sunplus		055f:c440	Mustek DV 3000
+sunplus		055f:c520	Mustek gSmart Mini 3
+sunplus		055f:c530	Mustek Gsmart LCD 3
+sunplus		055f:c540	Gsmart D30
+sunplus		055f:c630	Mustek MDC4000
+sunplus		055f:c650	Mustek MDC5500Z
+zc3xx		055f:d003	Mustek WCam300A
+zc3xx		055f:d004	Mustek WCam300 AN
+conex		0572:0041	Creative Notebook cx11646
+ov519		05a9:0519	OmniVision
+ov519		05a9:0530	OmniVision
+ov519		05a9:4519	OmniVision
+ov519		05a9:8519	OmniVision
+sunplus		05da:1018	Digital Dream Enigma 1.3
+stk014		05e1:0893	Syntek DV4000
+spca561		060b:a001	Maxell Compact Pc PM3
+zc3xx		0698:2003	CTX M730V built in
+spca500		06bd:0404	Agfa CL20
+spca500		06be:0800	Optimedia
+sunplus		06d6:0031	Trust 610 LCD PowerC@m Zoom
+spca506		06e1:a190	ADS Instant VCD
+spca508		0733:0110	ViewQuest VQ110
+spca508		0130:0130	Clone Digital Webcam 11043
+spca501		0733:0401	Intel Create and Share
+spca501		0733:0402	ViewQuest M318B
+spca505		0733:0430	Intel PC Camera Pro
+sunplus		0733:1311	Digital Dream Epsilon 1.3
+sunplus		0733:1314	Mercury 2.1MEG Deluxe Classic Cam
+sunplus		0733:2211	Jenoptik jdc 21 LCD
+sunplus		0733:2221	Mercury Digital Pro 3.1p
+sunplus		0733:3261	Concord 3045 spca536a
+sunplus		0733:3281	Cyberpix S550V
+spca506		0734:043b	3DeMon USB Capture aka
+spca500		084d:0003	D-Link DSC-350
+spca500		08ca:0103	Aiptek PocketDV
+sunplus		08ca:0104	Aiptek PocketDVII 1.3
+sunplus		08ca:0106	Aiptek Pocket DV3100+
+sunplus		08ca:2008	Aiptek Mini PenCam 2 M
+sunplus		08ca:2010	Aiptek PocketCam 3M
+sunplus		08ca:2016	Aiptek PocketCam 2 Mega
+sunplus		08ca:2018	Aiptek Pencam SD 2M
+sunplus		08ca:2020	Aiptek Slim 3000F
+sunplus		08ca:2022	Aiptek Slim 3200
+sunplus		08ca:2024	Aiptek DV3500 Mpeg4
+sunplus		08ca:2028	Aiptek PocketCam4M
+sunplus		08ca:2040	Aiptek PocketDV4100M
+sunplus		08ca:2042	Aiptek PocketDV5100
+sunplus		08ca:2050	Medion MD 41437
+sunplus		08ca:2060	Aiptek PocketDV5300
+tv8532		0923:010f	ICM532 cams
+mars		093a:050f	Mars-Semi Pc-Camera
+pac207		093a:2460	PAC207 Qtec Webcam 100
+pac207		093a:2463	Philips spc200nc pac207
+pac207		093a:2464	Labtec Webcam 1200
+pac207		093a:2468	PAC207
+pac207		093a:2470	Genius GF112
+pac207		093a:2471	PAC207 Genius VideoCam ge111
+pac207		093a:2472	PAC207 Genius VideoCam ge110
+pac7311		093a:2600	PAC7311 Typhoon
+pac7311		093a:2601	PAC7311 Phillips SPC610NC
+pac7311		093a:2603	PAC7312
+pac7311		093a:2608	PAC7311 Trust WB-3300p
+pac7311		093a:260e	PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
+pac7311		093a:260f	PAC7311 SnakeCam
+pac7311		093a:2621	PAC731x
+zc3xx		0ac8:0302	Z-star Vimicro zc0302
+vc032x		0ac8:0321	Vimicro generic vc0321
+vc032x		0ac8:0323	Vimicro Vc0323
+vc032x		0ac8:0328	A4Tech PK-130MG
+zc3xx		0ac8:301b	Z-Star zc301b
+zc3xx		0ac8:303b	Vimicro 0x303b
+zc3xx		0ac8:305b	Z-star Vimicro zc0305b
+zc3xx		0ac8:307b	Ldlc VC302+Ov7620
+vc032x		0ac8:c001	Sony embedded vimicro
+vc032x		0ac8:c002	Sony embedded vimicro
+spca508		0af9:0010	Hama USB Sightcam 100
+spca508		0af9:0011	Hama USB Sightcam 100
+sonixb		0c45:6001	Genius VideoCAM NB
+sonixb		0c45:6005	Microdia Sweex Mini Webcam
+sonixb		0c45:6007	Sonix sn9c101 + Tas5110D
+sonixb		0c45:6009	spcaCam@120
+sonixb		0c45:600d	spcaCam@120
+sonixb		0c45:6011	Microdia PC Camera (SN9C102)
+sonixb		0c45:6019	Generic Sonix OV7630
+sonixb		0c45:6024	Generic Sonix Tas5130c
+sonixb		0c45:6025	Xcam Shanga
+sonixb		0c45:6028	Sonix Btc Pc380
+sonixb		0c45:6029	spcaCam@150
+sonixb		0c45:602c	Generic Sonix OV7630
+sonixb		0c45:602d	LIC-200 LG
+sonixb		0c45:602e	Genius VideoCam Messenger
+sonixj		0c45:6040	Speed NVC 350K
+sonixj		0c45:607c	Sonix sn9c102p Hv7131R
+sonixj		0c45:60c0	Sangha Sn535
+sonixj		0c45:60ec	SN9C105+MO4000
+sonixj		0c45:60fb	Surfer NoName
+sonixj		0c45:60fc	LG-LIC300
+sonixj		0c45:612a	Avant Camera
+sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix
+sonixj		0c45:6130	Sonix Pccam
+sonixj		0c45:6138	Sn9c120 Mo4000
+sonixj		0c45:613b	Surfer SN-206
+sonixj		0c45:613c	Sonix Pccam168
+sunplus		0d64:0303	Sunplus FashionCam DXG
+etoms		102c:6151	Qcam Sangha CIF
+etoms		102c:6251	Qcam xxxxxx VGA
+zc3xx		10fd:0128	Typhoon Webshot II USB 300k 0x0128
+spca561		10fd:7e50	FlyCam Usb 100
+zc3xx		10fd:8050	Typhoon Webshot II USB 300k
+spca501		1776:501c	Arowana 300K CMOS Camera
+t613		17a1:0128	T613/TAS5130A
+vc032x		17ef:4802	Lenovo Vc0323+MI1310_SOC
+pac207		2001:f115	D-Link DSB-C120
+spca500		2899:012c	Toptro Industrial
+spca508		8086:0110	Intel Easy PC Camera
+spca500		8086:0630	Intel Pocket PC Camera
+spca506		99fa:8988	Grandtec V.cap
+spca561		abcd:cdee	Petcam
diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile
index 20c83a5..2172030 100644
--- a/arch/cris/arch-v10/boot/Makefile
+++ b/arch/cris/arch-v10/boot/Makefile
@@ -2,7 +2,6 @@
 # arch/cris/arch-v10/boot/Makefile
 #
 
-OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 
 subdir- := compressed rescue
diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile
index 4a031cb..08d943c 100644
--- a/arch/cris/arch-v10/boot/compressed/Makefile
+++ b/arch/cris/arch-v10/boot/compressed/Makefile
@@ -2,12 +2,10 @@
 # arch/cris/arch-v10/boot/compressed/Makefile
 #
 
-CC = gcc-cris -melf $(LINUXINCLUDE)
-ccflags-y += -O2
-LD = ld-cris
-ldflags-y += -T $(obj)/decompress.ld
+asflags-y += $(LINUXINCLUDE)
+ccflags-y += -O2 $(LINUXINCLUDE)
+ldflags-y += -T $(srctree)/$(obj)/decompress.ld
 OBJECTS = $(obj)/head.o $(obj)/misc.o
-OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 
 quiet_cmd_image = BUILD   $@
@@ -21,12 +19,6 @@
 $(obj)/decompress.bin: $(obj)/decompress.o FORCE
 	$(call if_changed,objcopy)
 
-$(obj)/head.o: $(obj)/head.S .config
-	@$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
-
-$(obj)/misc.o: $(obj)/misc.c .config
-	@$(CC) -D__KERNEL__ -c $< -o $@
-
 $(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE
 	$(call if_changed,image)
 
diff --git a/arch/cris/arch-v10/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld
index 0b0a14f..e80f459 100644
--- a/arch/cris/arch-v10/boot/compressed/decompress.ld
+++ b/arch/cris/arch-v10/boot/compressed/decompress.ld
@@ -1,4 +1,5 @@
-OUTPUT_FORMAT(elf32-us-cris)
+/* OUTPUT_FORMAT(elf32-us-cris) */
+OUTPUT_FORMAT(elf32-cris)
 
 MEMORY 
 	{
diff --git a/arch/cris/arch-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S
index 610bdb2..981fbae 100644
--- a/arch/cris/arch-v10/boot/compressed/head.S
+++ b/arch/cris/arch-v10/boot/compressed/head.S
@@ -15,77 +15,77 @@
 #define COMMAND_LINE_MAGIC 0x87109563
 
 	;; Exported symbols
-	
-	.globl	_input_data
 
-	
+	.globl	input_data
+
+
 	.text
 
 	nop
 	di
 
 ;; We need to initialze DRAM registers before we start using the DRAM
-	
-	cmp.d	RAM_INIT_MAGIC, r8	; Already initialized?
+
+	cmp.d	RAM_INIT_MAGIC, $r8	; Already initialized?
 	beq	dram_init_finished
 	nop
-	
+
 #include "../../lib/dram_init.S"
-	
-dram_init_finished:	
-		
+
+dram_init_finished:
+
 	;; Initiate the PA and PB ports
 
-	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
-	move.b   r0, [R_PORT_PA_DATA]
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
+	move.b   $r0, [R_PORT_PA_DATA]
 
-	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
-	move.b   r0, [R_PORT_PA_DIR]
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
+	move.b   $r0, [R_PORT_PA_DIR]
 
-	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
-	move.b   r0, [R_PORT_PB_DATA]
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
+	move.b   $r0, [R_PORT_PB_DATA]
 
-	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
-	move.b   r0, [R_PORT_PB_DIR]
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
+	move.b   $r0, [R_PORT_PB_DIR]
 
 	;; Setup the stack to a suitably high address.
 	;; We assume 8 MB is the minimum DRAM in an eLinux
 	;; product and put the sp at the top for now.
 
-	move.d	0x40800000, sp
+	move.d	0x40800000, $sp
 
 	;; Figure out where the compressed piggyback image is
 	;; in the flash (since we wont try to copy it to DRAM
 	;; before unpacking). It is at _edata, but in flash.
 	;; Use (_edata - basse) as offset to the current PC.
-	
-basse:	move.d	pc, r5
-	and.d	0x7fffffff, r5	; strip any non-cache bit
-	subq	2, r5		; compensate for the move.d pc instr
-	move.d	r5, r0		; save for later - flash address of 'basse'
-	add.d	_edata, r5
-	sub.d	basse, r5	; r5 = flash address of '_edata'
-	
+
+basse:	move.d	$pc, $r5
+	and.d	0x7fffffff, $r5	; strip any non-cache bit
+	subq	2, $r5		; compensate for the move.d $pc instr
+	move.d	$r5, $r0		; save for later - flash address of 'basse'
+	add.d	_edata, $r5
+	sub.d	basse, $r5	; $r5 = flash address of '_edata'
+
 	;; Copy text+data to DRAM
-	
-	move.d	basse, r1	; destination
-	move.d	_edata, r2	; end destination
-1:	move.w	[r0+], r3
-	move.w	r3, [r1+]
-	cmp.d	r2, r1
+
+	move.d	basse, $r1	; destination
+	move.d	_edata, $r2	; end destination
+1:	move.w	[$r0+], $r3
+	move.w	$r3, [$r1+]
+	cmp.d	$r2, $r1
 	bcs	1b
 	nop
 
-	move.d	r5, [_input_data] ; for the decompressor
+	move.d	$r5, [input_data] ; for the decompressor
 
 
 	;; Clear the decompressors BSS (between _edata and _end)
-	
-	moveq	0, r0
-	move.d	_edata, r1
-	move.d	_end, r2
-1:	move.w	r0, [r1+]
-	cmp.d	r2, r1
+
+	moveq	0, $r0
+	move.d	_edata, $r1
+	move.d	_end, $r2
+1:	move.w	$r0, [$r1+]
+	cmp.d	$r2, $r1
 	bcs	1b
 	nop
 
@@ -94,16 +94,16 @@
 	move.d  $r10, [$r12]
 	move.d	_cmd_line_addr, $r12
 	move.d  $r11, [$r12]
-	
-	;; Do the decompression and save compressed size in _inptr
 
-	jsr	_decompress_kernel
-	
-	;; Put start address of root partition in r9 so the kernel can use it
+	;; Do the decompression and save compressed size in inptr
+
+	jsr	decompress_kernel
+
+	;; Put start address of root partition in $r9 so the kernel can use it
 	;; when mounting from flash
 
-	move.d	[_input_data], r9	; flash address of compressed kernel
-	add.d	[_inptr], r9		; size of compressed kernel
+	move.d	[input_data], $r9	; flash address of compressed kernel
+	add.d	[inptr], $r9		; size of compressed kernel
 
 	;; Restore command line magic and address.
 	move.d  _cmd_line_magic, $r10
@@ -112,12 +112,12 @@
 	move.d  [$r11], $r11
 
 	;; Enter the decompressed kernel
-	move.d	RAM_INIT_MAGIC, r8	; Tell kernel that DRAM is initialized
+	move.d	RAM_INIT_MAGIC, $r8	; Tell kernel that DRAM is initialized
 	jump	0x40004000	; kernel is linked to this address
-	
+
 	.data
 
-_input_data:
+input_data:
 	.dword	0		; used by the decompressor
 _cmd_line_magic:
 	.dword 0
diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c
index 9a43ab1..18e13bc 100644
--- a/arch/cris/arch-v10/boot/compressed/misc.c
+++ b/arch/cris/arch-v10/boot/compressed/misc.c
@@ -29,12 +29,10 @@
 #define OF(args)  args
 #define STATIC static
 
-void* memset(void* s, int c, size_t n);
-void* memcpy(void* __dest, __const void* __src,
-	     size_t __n);
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *__dest, __const void *__src, size_t __n);
 
-#define memzero(s, n)     memset ((s), 0, (n))
-
+#define memzero(s, n)     memset((s), 0, (n))
 
 typedef unsigned char  uch;
 typedef unsigned short ush;
@@ -62,57 +60,69 @@
 #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
 #define RESERVED     0xC0 /* bit 6,7:   reserved */
 
-#define get_byte() inbuf[inptr++]	
-	
+#define get_byte() (inbuf[inptr++])
+
 /* Diagnostic functions */
 #ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Assert(cond, msg) do { \
+		if (!(cond)) \
+			error(msg); \
+	} while (0)
 #  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#  define Tracev(x) do { \
+		if (verbose) \
+			fprintf x; \
+	} while (0)
+#  define Tracevv(x) do { \
+		if (verbose > 1) \
+			fprintf x; \
+	} while (0)
+#  define Tracec(c, x) do { \
+		if (verbose && (c)) \
+			fprintf x; \
+	} while (0)
+#  define Tracecv(c, x) do { \
+		if (verbose > 1 && (c)) \
+			fprintf x; \
+	} while (0)
 #else
-#  define Assert(cond,msg)
+#  define Assert(cond, msg)
 #  define Trace(x)
 #  define Tracev(x)
 #  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
+#  define Tracec(c, x)
+#  define Tracecv(c, x)
 #endif
 
-static int  fill_inbuf(void);
 static void flush_window(void);
 static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
 
 extern char *input_data;  /* lives in head.S */
 
 static long bytes_out = 0;
 static uch *output_data;
 static unsigned long output_ptr = 0;
- 
+
 static void *malloc(int size);
 static void free(void *where);
-static void error(char *m);
 static void gzip_mark(void **);
 static void gzip_release(void **);
- 
+
 static void puts(const char *);
 
 /* the "heap" is put directly after the BSS ends, at end */
-  
-extern int end;
-static long free_mem_ptr = (long)&end;
- 
+
+extern int _end;
+static long free_mem_ptr = (long)&_end;
+
 #include "../../../../../lib/inflate.c"
 
 static void *malloc(int size)
 {
 	void *p;
 
-	if (size <0) error("Malloc error");
+	if (size < 0)
+		error("Malloc error");
 
 	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
 
@@ -142,44 +152,47 @@
 puts(const char *s)
 {
 #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
-	while(*s) {
+	while (*s) {
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
-		while(!(*R_SERIAL0_STATUS & (1 << 5))) ;
+		while (!(*R_SERIAL0_STATUS & (1 << 5))) ;
 		*R_SERIAL0_TR_DATA = *s++;
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT1
-		while(!(*R_SERIAL1_STATUS & (1 << 5))) ;
+		while (!(*R_SERIAL1_STATUS & (1 << 5))) ;
 		*R_SERIAL1_TR_DATA = *s++;
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT2
-		while(!(*R_SERIAL2_STATUS & (1 << 5))) ;
+		while (!(*R_SERIAL2_STATUS & (1 << 5))) ;
 		*R_SERIAL2_TR_DATA = *s++;
 #endif
 #ifdef CONFIG_ETRAX_DEBUG_PORT3
-		while(!(*R_SERIAL3_STATUS & (1 << 5))) ;
+		while (!(*R_SERIAL3_STATUS & (1 << 5))) ;
 		*R_SERIAL3_TR_DATA = *s++;
 #endif
 	}
 #endif
 }
 
-void*
-memset(void* s, int c, size_t n)
+void *memset(void *s, int c, size_t n)
 {
 	int i;
-	char *ss = (char*)s;
+	char *ss = (char *)s;
 
-	for (i=0;i<n;i++) ss[i] = c;
+	for (i = 0; i < n; i++)
+		ss[i] = c;
+
+	return s;
 }
 
-void*
-memcpy(void* __dest, __const void* __src,
-			    size_t __n)
+void *memcpy(void *__dest, __const void *__src, size_t __n)
 {
 	int i;
 	char *d = (char *)__dest, *s = (char *)__src;
 
-	for (i=0;i<__n;i++) d[i] = s[i];
+	for (i = 0; i < __n; i++)
+		d[i] = s[i];
+
+	return __dest;
 }
 
 /* ===========================================================================
@@ -187,46 +200,44 @@
  * (Used for the decompressed data only.)
  */
 
-static void
-flush_window()
+static void flush_window(void)
 {
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, *out, ch;
-    
-    in = window;
-    out = &output_data[output_ptr]; 
-    for (n = 0; n < outcnt; n++) {
-	    ch = *out++ = *in++;
-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    output_ptr += (ulg)outcnt;
-    outcnt = 0;
+	ulg c = crc;         /* temporary variable */
+	unsigned n;
+	uch *in, *out, ch;
+
+	in = window;
+	out = &output_data[output_ptr];
+	for (n = 0; n < outcnt; n++) {
+		ch = *out = *in;
+		out++;
+		in++;
+		c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+	}
+	crc = c;
+	bytes_out += (ulg)outcnt;
+	output_ptr += (ulg)outcnt;
+	outcnt = 0;
 }
 
-static void
-error(char *x)
+static void error(char *x)
 {
 	puts("\n\n");
 	puts(x);
 	puts("\n\n -- System halted\n");
 
-	while(1);	/* Halt */
+	while (1);	/* Halt */
 }
 
-void
-setup_normal_output_buffer()
+void setup_normal_output_buffer(void)
 {
 	output_data = (char *)KERNEL_LOAD_ADR;
 }
 
-void
-decompress_kernel()
+void decompress_kernel(void)
 {
 	char revision;
-	
+
 	/* input_data is set in head.S */
 	inbuf = input_data;
 
@@ -257,11 +268,10 @@
 
 	makecrc();
 
-	__asm__ volatile ("move vr,%0" : "=rm" (revision));
-	if (revision < 10)
-	{
+	__asm__ volatile ("move $vr,%0" : "=rm" (revision));
+	if (revision < 10) {
 		puts("You need an ETRAX 100LX to run linux 2.6\n");
-		while(1);
+		while (1);
 	}
 
 	puts("Uncompressing Linux...\n");
diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile
index 2e5045b..07688da 100644
--- a/arch/cris/arch-v10/boot/rescue/Makefile
+++ b/arch/cris/arch-v10/boot/rescue/Makefile
@@ -2,12 +2,9 @@
 # Makefile for rescue (bootstrap) code
 #
 
-CC = gcc-cris -mlinux $(LINUXINCLUDE)
-ccflags-y += -O2
-asflags-y += -traditional
-LD = gcc-cris -mlinux -nostdlib
-ldflags-y += -T $(obj)/rescue.ld
-OBJCOPY = objcopy-cris
+ccflags-y += -O2 $(LINUXINCLUDE)
+asflags-y += $(LINUXINCLUDE)
+ldflags-y += -T $(srctree)/$(obj)/rescue.ld
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
 OBJECT := $(obj)/head.o
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index 52103d1..8769dc9 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -233,7 +233,7 @@
 
 		if (copy_to_user((struct rtc_time *) arg, &tm,
 				 sizeof tm)) {
-			spin_unlock(&rtc_lock);
+			mutex_unlock(&rtc_lock);
 			return -EFAULT;
 		}
 
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
index 04d5eee..3dc6e91 100644
--- a/arch/cris/arch-v10/kernel/debugport.c
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -426,12 +426,18 @@
 	return count;
 }
 
-static int
-dummy_write_room(struct tty_struct *tty)
+static int dummy_write_room(struct tty_struct *tty)
 {
 	return 8192;
 }
 
+static const struct tty_operations dummy_ops = {
+	.open = dummy_open,
+	.close = dummy_close,
+	.write = dummy_write,
+	.write_room = dummy_write_room,
+};
+
 void __init
 init_dummy_console(void)
 {
@@ -444,14 +450,14 @@
 	dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	dummy_driver.subtype = SERIAL_TYPE_NORMAL;
 	dummy_driver.init_termios = tty_std_termios;
+	/* Normally B9600 default... */
 	dummy_driver.init_termios.c_cflag =
-		B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+		B115200 | CS8 | CREAD | HUPCL | CLOCAL;
 	dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	dummy_driver.init_termios.c_ispeed = 115200;
+	dummy_driver.init_termios.c_ospeed = 115200;
 
-	dummy_driver.open = dummy_open;
-	dummy_driver.close = dummy_close;
-	dummy_driver.write = dummy_write;
-	dummy_driver.write_room = dummy_write_room;
+	dummy_driver.ops = &dummy_ops;
 	if (tty_register_driver(&dummy_driver))
 		panic("Couldn't register dummy serial driver\n");
 }
diff --git a/arch/cris/arch-v32/boot/Makefile b/arch/cris/arch-v32/boot/Makefile
index 3f91349..99896ad 100644
--- a/arch/cris/arch-v32/boot/Makefile
+++ b/arch/cris/arch-v32/boot/Makefile
@@ -2,7 +2,6 @@
 # arch/cris/arch-v32/boot/Makefile
 #
 
-OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary -R .note -R .comment
 
 subdir- := compressed rescue
diff --git a/arch/cris/arch-v32/boot/compressed/Makefile b/arch/cris/arch-v32/boot/compressed/Makefile
index 2c8c2c3..d6335f2 100644
--- a/arch/cris/arch-v32/boot/compressed/Makefile
+++ b/arch/cris/arch-v32/boot/compressed/Makefile
@@ -2,14 +2,10 @@
 # arch/cris/arch-v32/boot/compressed/Makefile
 #
 
-CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
 asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
 ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
-LD = gcc-cris -mlinux -march=v32 -nostdlib
-ldflags-y += -T $(obj)/decompress.ld
-obj-y = head.o misc.o
+ldflags-y += -T $(srctree)/$(obj)/decompress.ld
 OBJECTS = $(obj)/head.o $(obj)/misc.o
-OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 
 quiet_cmd_image = BUILD   $@
diff --git a/arch/cris/arch-v32/boot/rescue/Makefile b/arch/cris/arch-v32/boot/rescue/Makefile
index c098779..44ae0ad 100644
--- a/arch/cris/arch-v32/boot/rescue/Makefile
+++ b/arch/cris/arch-v32/boot/rescue/Makefile
@@ -7,9 +7,8 @@
 		-I $(srctree)/include/asm/arch
 asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch
 LD = gcc-cris -mlinux -march=v32 -nostdlib
-ldflags-y += -T $(obj)/rescue.ld
+ldflags-y += -T $(srctree)/$(obj)/rescue.ld
 LDPOSTFLAGS = -lgcc
-OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
 OBJECT := $(obj)/head.o
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c
index 53db387..f263ab5 100644
--- a/arch/cris/arch-v32/drivers/pcf8563.c
+++ b/arch/cris/arch-v32/drivers/pcf8563.c
@@ -229,7 +229,7 @@
 
 		if (copy_to_user((struct rtc_time *) arg, &tm,
 				 sizeof tm)) {
-			spin_unlock(&rtc_lock);
+			mutex_unlock(&rtc_lock);
 			return -EFAULT;
 		}
 
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 23cafc8..24b1ad5 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -193,18 +193,6 @@
  * -------------------------------------------------------------------
  */
 
-#if 0
-/*
- * not really used in our situation so keep them commented out for now
- */
-static DECLARE_TASK_QUEUE(tq_serial); /* used to be at the top of the file */
-static void do_serial_bh(void)
-{
-	run_task_queue(&tq_serial);
-	printk(KERN_ERR "do_serial_bh: called\n");
-}
-#endif
-
 static void do_softint(struct work_struct *private_)
 {
 	printk(KERN_ERR "simserial: do_softint called\n");
@@ -351,11 +339,7 @@
 	info->xmit.head = info->xmit.tail = 0;
 	local_irq_restore(flags);
 
-	wake_up_interruptible(&tty->write_wait);
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	tty_wakeup(tty);
 }
 
 /*
@@ -404,12 +388,6 @@
 	printk(KERN_INFO "simrs_unthrottle called\n");
 }
 
-/*
- * rs_break() --- routine which turns the break handling on or off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
-}
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
@@ -422,14 +400,6 @@
 	}
 
 	switch (cmd) {
-		case TIOCMGET:
-			printk(KERN_INFO "rs_ioctl: TIOCMGET called\n");
-			return -EINVAL;
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			printk(KERN_INFO "rs_ioctl: TIOCMBIS/BIC/SET called\n");
-			return -EINVAL;
 		case TIOCGSERIAL:
 			printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n");
 			return 0;
@@ -488,14 +458,6 @@
 
 static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-	unsigned int cflag = tty->termios->c_cflag;
-
-	if (   (cflag == old_termios->c_cflag)
-	    && (   RELEVANT_IFLAG(tty->termios->c_iflag)
-		== RELEVANT_IFLAG(old_termios->c_iflag)))
-	  return;
-
-
 	/* Handle turning off CRTSCTS */
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
@@ -623,9 +585,8 @@
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	shutdown(info);
-	if (tty->ops->flush_buffer)
-		tty->ops->flush_buffer(tty);
-	if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
+	rs_flush_buffer(tty);
+	tty_ldisc_flush(tty);
 	info->event = 0;
 	info->tty = NULL;
 	if (info->blocked_open) {
@@ -955,7 +916,6 @@
 	.stop = rs_stop,
 	.start = rs_start,
 	.hangup = rs_hangup,
-	.break_ctl = rs_break,
 	.wait_until_sent = rs_wait_until_sent,
 	.read_proc = rs_read_proc,
 };
diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile
index 112791d..bf22fb9 100644
--- a/arch/ia64/kvm/Makefile
+++ b/arch/ia64/kvm/Makefile
@@ -43,7 +43,8 @@
 EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
 EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
 
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
+		coalesced_mmio.o)
 
 kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o
 obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 68c978b..2672f4d 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -187,6 +187,9 @@
 
 		r = 1;
 		break;
+	case KVM_CAP_COALESCED_MMIO:
+		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
+		break;
 	default:
 		r = 0;
 	}
@@ -195,11 +198,11 @@
 }
 
 static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
-					gpa_t addr)
+					gpa_t addr, int len, int is_write)
 {
 	struct kvm_io_device *dev;
 
-	dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+	dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write);
 
 	return dev;
 }
@@ -231,7 +234,7 @@
 	kvm_run->exit_reason = KVM_EXIT_MMIO;
 	return 0;
 mmio:
-	mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr);
+	mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir);
 	if (mmio_dev) {
 		if (!p->dir)
 			kvm_iodevice_write(mmio_dev, p->addr, p->size,
@@ -1035,14 +1038,6 @@
 	}
 }
 
-/*
- * Make sure that a cpu that is being hot-unplugged does not have any vcpus
- * cached on it. Leave it as blank for IA64.
- */
-void decache_vcpus_on_cpu(int cpu)
-{
-}
-
 static void vti_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 }
@@ -1460,6 +1455,9 @@
 	return 0;
 }
 
+void kvm_arch_flush_shadow(struct kvm *kvm)
+{
+}
 
 long kvm_arch_dev_ioctl(struct file *filp,
 		unsigned int ioctl, unsigned long arg)
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 55ea52f..8c5e1de 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -490,28 +490,6 @@
 	  Note for Falcon users: You also have an MFP port, it's just not
 	  wired to the outside... But you could use the port under Linux.
 
-config ATARI_SCC
-	tristate "Atari SCC serial support"
-	depends on ATARI
-	---help---
-	  If you have serial ports based on a Zilog SCC chip (Modem2, Serial2,
-	  LAN) and like to use them under Linux, say Y. All built-in SCC's are
-	  supported (TT, MegaSTE, Falcon), and also the ST-ESCC. If you have
-	  two connectors for channel A (Serial2 and LAN), they are visible as
-	  two separate devices.
-
-	  To compile this driver as a module, choose M here.
-
-config ATARI_SCC_DMA
-	bool "Atari SCC serial DMA support"
-	depends on ATARI_SCC
-	help
-	  This enables DMA support for receiving data on channel A of the SCC.
-	  If you have a TT you may say Y here and read
-	  drivers/char/atari_SCC.README. All other users should say N here,
-	  because only the TT has SCC-DMA, even if your machine keeps claiming
-	  so at boot time.
-
 config ATARI_MIDI
 	tristate "Atari MIDI serial support"
 	depends on ATARI
@@ -578,18 +556,6 @@
 	depends on INPUT_ADBHID
 	default y
 
-config ADB_KEYBOARD
-	bool "Support for ADB keyboard (old driver)"
-	depends on MAC && !INPUT_ADBHID
-	help
-	  This option allows you to use an ADB keyboard attached to your
-	  machine. Note that this disables any other (ie. PS/2) keyboard
-	  support, even if your machine is physically capable of using both at
-	  the same time.
-
-	  If you use an ADB keyboard (4 pin connector), say Y here.
-	  If you use a PS/2 keyboard (6 pin connector), say N here.
-
 config HPDCA
 	tristate "HP DCA serial support"
 	depends on DIO && SERIAL_8250
@@ -640,7 +606,7 @@
 
 config SERIAL_CONSOLE
 	bool "Support for serial port console"
-	depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
+	depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
 	---help---
 	  If you say Y here, it will be possible to use a serial port as the
 	  system console (the system console is the device which receives all
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index b15173f..8133dbc 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -13,7 +13,7 @@
 # Copyright (C) 1994 by Hamish Macdonald
 #
 
-KBUILD_DEFCONFIG := amiga_defconfig
+KBUILD_DEFCONFIG := multi_defconfig
 
 # override top level makefile
 AS += -m68020
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 50f5daa..df679d9 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -36,14 +36,11 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 
-unsigned long amiga_model;
-EXPORT_SYMBOL(amiga_model);
+static unsigned long amiga_model;
 
 unsigned long amiga_eclock;
 EXPORT_SYMBOL(amiga_eclock);
 
-unsigned long amiga_masterclock;
-
 unsigned long amiga_colorclock;
 EXPORT_SYMBOL(amiga_colorclock);
 
@@ -51,7 +48,9 @@
 EXPORT_SYMBOL(amiga_chipset);
 
 unsigned char amiga_vblank;
-unsigned char amiga_psfreq;
+EXPORT_SYMBOL(amiga_vblank);
+
+static unsigned char amiga_psfreq;
 
 struct amiga_hw_present amiga_hw_present;
 EXPORT_SYMBOL(amiga_hw_present);
@@ -92,8 +91,6 @@
 static char amiga_model_name[13] = "Amiga ";
 
 static void amiga_sched_init(irq_handler_t handler);
-/* amiga specific irq functions */
-extern void amiga_init_IRQ(void);
 static void amiga_get_model(char *model);
 static int amiga_get_hardware_list(char *buffer);
 /* amiga specific timer functions */
@@ -107,8 +104,6 @@
 extern void amiga_init_sound(void);
 static void amiga_mem_console_write(struct console *co, const char *b,
 				    unsigned int count);
-void amiga_serial_console_write(struct console *co, const char *s,
-				unsigned int count);
 #ifdef CONFIG_HEARTBEAT
 static void amiga_heartbeat(int on);
 #endif
@@ -418,8 +413,7 @@
 	mach_heartbeat = amiga_heartbeat;
 #endif
 
-	/* Fill in the clock values (based on the 700 kHz E-Clock) */
-	amiga_masterclock = 40*amiga_eclock;	/* 28 MHz */
+	/* Fill in the clock value (based on the 700 kHz E-Clock) */
 	amiga_colorclock = 5*amiga_eclock;	/* 3.5 MHz */
 
 	/* clear all DMA bits */
@@ -817,8 +811,8 @@
 		;
 }
 
-void amiga_serial_console_write(struct console *co, const char *s,
-				unsigned int count)
+static void amiga_serial_console_write(struct console *co, const char *s,
+				       unsigned int count)
 {
 	while (count--) {
 		if (*s == '\n')
@@ -827,7 +821,7 @@
 	}
 }
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#if 0
 void amiga_serial_puts(const char *s)
 {
 	amiga_serial_console_write(NULL, s, strlen(s));
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c
index 043ddbc..702b15c 100644
--- a/arch/m68k/atari/debug.c
+++ b/arch/m68k/atari/debug.c
@@ -20,14 +20,6 @@
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 
-/* Flag that Modem1 port is already initialized and used */
-int atari_MFP_init_done;
-EXPORT_SYMBOL(atari_MFP_init_done);
-
-/* Flag that Modem1 port is already initialized and used */
-int atari_SCC_init_done;
-EXPORT_SYMBOL(atari_SCC_init_done);
-
 /* Can be set somewhere, if a SCC master reset has already be done and should
  * not be repeated; used by kgdb */
 int atari_SCC_reset_done;
@@ -47,8 +39,8 @@
 	mfp.usart_dta = c;
 }
 
-void atari_mfp_console_write(struct console *co, const char *str,
-			     unsigned int count)
+static void atari_mfp_console_write(struct console *co, const char *str,
+				    unsigned int count)
 {
 	while (count--) {
 		if (*str == '\n')
@@ -66,8 +58,8 @@
 	scc.cha_b_data = c;
 }
 
-void atari_scc_console_write(struct console *co, const char *str,
-			     unsigned int count)
+static void atari_scc_console_write(struct console *co, const char *str,
+				    unsigned int count)
 {
 	while (count--) {
 		if (*str == '\n')
@@ -83,8 +75,8 @@
 	acia.mid_data = c;
 }
 
-void atari_midi_console_write(struct console *co, const char *str,
-			      unsigned int count)
+static void atari_midi_console_write(struct console *co, const char *str,
+				     unsigned int count)
 {
 	while (count--) {
 		if (*str == '\n')
@@ -136,7 +128,7 @@
 	}
 }
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#if 0
 int atari_mfp_console_wait_key(struct console *co)
 {
 	while (!(mfp.rcv_stat & 0x80))	/* wait for rx buf filled */
@@ -166,11 +158,7 @@
  * SCC serial ports. They're used by the debugging interface, kgdb, and the
  * serial console code.
  */
-#ifndef CONFIG_SERIAL_CONSOLE
 static void __init atari_init_mfp_port(int cflag)
-#else
-void atari_init_mfp_port(int cflag)
-#endif
 {
 	/*
 	 * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
@@ -193,8 +181,6 @@
 	mfp.tim_dt_d = baud_table[baud];
 	mfp.tim_ct_cd |= 0x01;		/* start timer D, 1:4 */
 	mfp.trn_stat |= 0x01;		/* enable TX */
-
-	atari_MFP_init_done = 1;
 }
 
 #define SCC_WRITE(reg, val)				\
@@ -214,11 +200,7 @@
 			MFPDELAY();			\
 	} while (0)
 
-#ifndef CONFIG_SERIAL_CONSOLE
 static void __init atari_init_scc_port(int cflag)
-#else
-void atari_init_scc_port(int cflag)
-#endif
 {
 	extern int atari_SCC_reset_done;
 	static int clksrc_table[9] =
@@ -277,14 +259,9 @@
 	SCC_WRITE(5, reg5 | 8);
 
 	atari_SCC_reset_done = 1;
-	atari_SCC_init_done = 1;
 }
 
-#ifndef CONFIG_SERIAL_CONSOLE
 static void __init atari_init_midi_port(int cflag)
-#else
-void atari_init_midi_port(int cflag)
-#endif
 {
 	int baud = cflag & CBAUD;
 	int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile
index 0214d2f..9506d88 100644
--- a/arch/m68k/fpsp040/Makefile
+++ b/arch/m68k/fpsp040/Makefile
@@ -10,7 +10,6 @@
 	    x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \
 	    x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o
 
-EXTRA_AFLAGS := -traditional
 EXTRA_LDFLAGS := -x
 
 $(OS_OBJS): fpsp.h
diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile
index 2fe8472..43b4350 100644
--- a/arch/m68k/ifpsp060/Makefile
+++ b/arch/m68k/ifpsp060/Makefile
@@ -6,5 +6,4 @@
 
 obj-y := fskeleton.o iskeleton.o os.o
 
-EXTRA_AFLAGS := -traditional
 EXTRA_LDFLAGS := -x
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 7a62a71..3a7f622 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -16,5 +16,3 @@
 
 obj-$(CONFIG_PCI)	+= bios32.o
 obj-y$(CONFIG_MMU_SUN3) += dma.o	# no, it's not a typo
-
-EXTRA_AFLAGS := -traditional
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index a9fb83a..ea1e44d 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -26,6 +26,7 @@
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
+#include <asm/fpu.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
@@ -40,6 +41,11 @@
 #include <asm/dvma.h>
 #endif
 
+#if !FPSTATESIZE || !NR_IRQS
+#warning No CPU/platform type selected, your kernel will not work!
+#warning Are you building an allnoconfig kernel?
+#endif
+
 unsigned long m68k_machtype;
 EXPORT_SYMBOL(m68k_machtype);
 unsigned long m68k_cputype;
@@ -116,6 +122,7 @@
 extern int mvme16x_parse_bootinfo(const struct bi_record *);
 extern int mvme147_parse_bootinfo(const struct bi_record *);
 extern int hp300_parse_bootinfo(const struct bi_record *);
+extern int apollo_parse_bootinfo(const struct bi_record *);
 
 extern void config_amiga(void);
 extern void config_atari(void);
@@ -183,6 +190,8 @@
 				unknown = mvme147_parse_bootinfo(record);
 			else if (MACH_IS_HP300)
 				unknown = hp300_parse_bootinfo(record);
+			else if (MACH_IS_APOLLO)
+				unknown = apollo_parse_bootinfo(record);
 			else
 				unknown = 1;
 		}
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 7537cc5..99b0784 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -1,6 +1,7 @@
 /* ld script to make m68k Linux kernel */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 
 OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
 OUTPUT_ARCH(m68k)
@@ -41,7 +42,7 @@
   _edata = .;			/* End of data section */
 
   /* will be freed after init */
-  . = ALIGN(4096);		/* Init code and data */
+  . = ALIGN(PAGE_SIZE);		/* Init code and data */
   __init_begin = .;
   .init.text : {
 	_sinittext = .;
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index cdc313e..8a4919e 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -1,6 +1,7 @@
 /* ld script to make m68k Linux kernel */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
 
 OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
 OUTPUT_ARCH(m68k)
@@ -34,7 +35,7 @@
   _edata = .;
 
   /* will be freed after init */
-  . = ALIGN(8192);	/* Init code and data */
+  . = ALIGN(PAGE_SIZE);	/* Init code and data */
 __init_begin = .;
 	.init.text : {
 		_sinittext = .;
@@ -61,12 +62,12 @@
 	}
 	SECURITY_INIT
 #ifdef CONFIG_BLK_DEV_INITRD
-	. = ALIGN(8192);
+	. = ALIGN(PAGE_SIZE);
 	__initramfs_start = .;
 	.init.ramfs : { *(.init.ramfs) }
 	__initramfs_end = .;
 #endif
-	. = ALIGN(8192);
+	. = ALIGN(PAGE_SIZE);
 	__init_end = .;
 	.data.init.task : { *(.data.init_task) }
 
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index a18af09..af9abf8 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -2,7 +2,5 @@
 # Makefile for m68k-specific library files..
 #
 
-EXTRA_AFLAGS := -traditional
-
 lib-y	:= ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
 	   checksum.o string.o uaccess.o
diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile
index 1d265ba..daebd80 100644
--- a/arch/m68k/mac/Makefile
+++ b/arch/m68k/mac/Makefile
@@ -2,5 +2,5 @@
 # Makefile for Linux arch/m68k/mac source directory
 #
 
-obj-y		:= config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
+obj-y		:= config.o macints.o iop.o via.o oss.o psc.o \
 			baboon.o macboing.o debug.o misc.o
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index 673a108..dae9c98 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -23,9 +23,7 @@
 /* #define DEBUG_IRQS */
 
 int baboon_present;
-volatile struct baboon *baboon;
-
-irqreturn_t baboon_irq(int, void *);
+static volatile struct baboon *baboon;
 
 #if 0
 extern int macide_ack_intr(struct ata_channel *);
@@ -50,20 +48,10 @@
 }
 
 /*
- * Register the Baboon interrupt dispatcher on nubus slot $C.
- */
-
-void __init baboon_register_interrupts(void)
-{
-	request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-		    "baboon", (void *) baboon);
-}
-
-/*
  * Baboon interrupt handler. This works a lot like a VIA.
  */
 
-irqreturn_t baboon_irq(int irq, void *dev_id)
+static irqreturn_t baboon_irq(int irq, void *dev_id)
 {
 	int irq_bit, irq_num;
 	unsigned char events;
@@ -95,6 +83,16 @@
 	return IRQ_HANDLED;
 }
 
+/*
+ * Register the Baboon interrupt dispatcher on nubus slot $C.
+ */
+
+void __init baboon_register_interrupts(void)
+{
+	request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+		    "baboon", (void *) baboon);
+}
+
 void baboon_irq_enable(int irq) {
 #ifdef DEBUG_IRQUSE
 	printk("baboon_irq_enable(%d)\n", irq);
diff --git a/arch/m68k/mac/bootparse.c b/arch/m68k/mac/bootparse.c
deleted file mode 100644
index 36d2236..0000000
--- a/arch/m68k/mac/bootparse.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/irq.h>
-#include <asm/setup.h>
-#include <asm/bootinfo.h>
-#include <asm/macintosh.h>
-
-/*
- *	Booter vars
- */
-
-int boothowto;
-int _boothowto;
-
-/*
- *	Called early to parse the environment (passed to us from the booter)
- *	into a bootinfo struct. Will die as soon as we have our own booter
- */
-
-#define atol(x)	simple_strtoul(x,NULL,0)
-
-void parse_booter(char *env)
-{
-	char *name;
-	char *value;
-#if 0
-	while(0 && *env)
-#else
-	while(*env)
-#endif
-	{
-		name=env;
-		value=name;
-		while(*value!='='&&*value)
-			value++;
-		if(*value=='=')
-			*value++=0;
-		env=value;
-		while(*env)
-			env++;
-		env++;
-#if 0
-		if(strcmp(name,"VIDEO_ADDR")==0)
-			mac_mch.videoaddr=atol(value);
-		if(strcmp(name,"ROW_BYTES")==0)
-			mac_mch.videorow=atol(value);
-		if(strcmp(name,"SCREEN_DEPTH")==0)
-			mac_mch.videodepth=atol(value);
-		if(strcmp(name,"DIMENSIONS")==0)
-			mac_mch.dimensions=atol(value);
-#endif
-		if(strcmp(name,"BOOTTIME")==0)
-			mac_bi_data.boottime=atol(value);
-		if(strcmp(name,"GMTBIAS")==0)
-			mac_bi_data.gmtbias=atol(value);
-		if(strcmp(name,"BOOTERVER")==0)
-			mac_bi_data.bootver=atol(value);
-		if(strcmp(name,"MACOS_VIDEO")==0)
-			mac_bi_data.videological=atol(value);
-		if(strcmp(name,"MACOS_SCC")==0)
-			mac_bi_data.sccbase=atol(value);
-		if(strcmp(name,"MACHINEID")==0)
-			mac_bi_data.id=atol(value);
-		if(strcmp(name,"MEMSIZE")==0)
-			mac_bi_data.memsize=atol(value);
-		if(strcmp(name,"SERIAL_MODEM_FLAGS")==0)
-			mac_bi_data.serialmf=atol(value);
-		if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0)
-			mac_bi_data.serialhsk=atol(value);
-		if(strcmp(name,"SERIAL_MODEM_GPICLK")==0)
-			mac_bi_data.serialgpi=atol(value);
-		if(strcmp(name,"SERIAL_PRINT_FLAGS")==0)
-			mac_bi_data.printmf=atol(value);
-		if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0)
-			mac_bi_data.printhsk=atol(value);
-		if(strcmp(name,"SERIAL_PRINT_GPICLK")==0)
-			mac_bi_data.printgpi=atol(value);
-		if(strcmp(name,"PROCESSOR")==0)
-			mac_bi_data.cpuid=atol(value);
-		if(strcmp(name,"ROMBASE")==0)
-			mac_bi_data.rombase=atol(value);
-		if(strcmp(name,"TIMEDBRA")==0)
-			mac_bi_data.timedbra=atol(value);
-		if(strcmp(name,"ADBDELAY")==0)
-			mac_bi_data.adbdelay=atol(value);
-	}
-#if 0	/* XXX: TODO with m68k_mach_* */
-	/* Fill in the base stuff */
-	boot_info.machtype=MACH_MAC;
-	/* Read this from the macinfo we got ! */
-/*	boot_info.cputype=CPU_68020|FPUB_68881;*/
-/*	boot_info.memory[0].addr=0;*/
-/*	boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/
-	boot_info.num_memory=1;		/* On a MacII */
-	boot_info.ramdisk_size=0;	/* For now */
-	*boot_info.command_line=0;
-#endif
- }
-
-
-void print_booter(char *env)
-{
-	char *name;
-	char *value;
-	while(*env)
-	{
-		name=env;
-		value=name;
-		while(*value!='='&&*value)
-			value++;
-		if(*value=='=')
-			*value++=0;
-		env=value;
-		while(*env)
-			env++;
-		env++;
-		printk("%s=%s\n", name,value);
-	}
- }
-
-
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index ad3e3ba..c45e184 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -46,7 +46,6 @@
 /* Mac bootinfo struct */
 
 struct mac_booter_data mac_bi_data;
-int mac_bisize = sizeof mac_bi_data;
 
 /* New m68k bootinfo stuff and videobase */
 
@@ -55,10 +54,8 @@
 
 extern struct mem_info m68k_ramdisk;
 
-void *mac_env;					/* Loaded by the boot asm */
-
 /* The phys. video addr. - might be bogus on some machines */
-unsigned long mac_orig_videoaddr;
+static unsigned long mac_orig_videoaddr;
 
 /* Mac specific timer functions */
 extern unsigned long mac_gettimeoffset(void);
@@ -79,6 +76,8 @@
 extern void nubus_sweep_video(void);
 
 static void mac_get_model(char *str);
+static void mac_identify(void);
+static void mac_report_hardware(void);
 
 static void __init mac_sched_init(irq_handler_t vector)
 {
@@ -765,7 +764,7 @@
 	}
 };
 
-void __init mac_identify(void)
+static void __init mac_identify(void)
 {
 	struct mac_model *m;
 
@@ -821,7 +820,7 @@
 	baboon_init();
 }
 
-void __init mac_report_hardware(void)
+static void __init mac_report_hardware(void)
 {
 	printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index e8a5713..2165740 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -51,6 +51,8 @@
 static int peng, line;
 #endif
 
+#if 0
+
 void mac_debugging_short(int pos, short num)
 {
 #ifdef DEBUG_SCREEN
@@ -125,6 +127,8 @@
 #endif
 }
 
+#endif  /*  0  */
+
 #ifdef DEBUG_SERIAL
 /*
  * TODO: serial debug code
@@ -142,12 +146,6 @@
 
 # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
 
-/* Flag that serial port is already initialized and used */
-int mac_SCC_init_done;
-/* Can be set somewhere, if a SCC master reset has already be done and should
- * not be repeated; used by kgdb */
-int mac_SCC_reset_done;
-
 static int scc_port = -1;
 
 static struct console mac_console_driver = {
@@ -171,8 +169,8 @@
  * this driver if Mac.
  */
 
-void mac_debug_console_write(struct console *co, const char *str,
-			     unsigned int count)
+static void mac_debug_console_write(struct console *co, const char *str,
+				    unsigned int count)
 {
 	mac_serial_print(str);
 }
@@ -209,8 +207,8 @@
 	scc.cha_a_data = c;
 }
 
-void mac_sccb_console_write(struct console *co, const char *str,
-			    unsigned int count)
+static void mac_sccb_console_write(struct console *co, const char *str,
+				   unsigned int count)
 {
 	while (count--) {
 		if (*str == '\n')
@@ -219,8 +217,8 @@
 	}
 }
 
-void mac_scca_console_write(struct console *co, const char *str,
-			    unsigned int count)
+static void mac_scca_console_write(struct console *co, const char *str,
+				   unsigned int count)
 {
 	while (count--) {
 		if (*str == '\n')
@@ -265,14 +263,8 @@
 		    barrier();				\
 	} while(0)
 
-#ifndef CONFIG_SERIAL_CONSOLE
 static void __init mac_init_scc_port(int cflag, int port)
-#else
-void mac_init_scc_port(int cflag, int port)
-#endif
 {
-	extern int mac_SCC_reset_done;
-
 	/*
 	 * baud rates: 1200, 1800, 2400, 4800, 9600, 19.2k, 38.4k, 57.6k, 115.2k
 	 */
@@ -340,22 +332,9 @@
 		SCCA_WRITE(3, reg3 | 1);
 		SCCA_WRITE(5, reg5 | 8);
 	}
-
-	mac_SCC_reset_done = 1;
-	mac_SCC_init_done = 1;
 }
 #endif /* DEBUG_SERIAL */
 
-void mac_init_scca_port(int cflag)
-{
-	mac_init_scc_port(cflag, 0);
-}
-
-void mac_init_sccb_port(int cflag)
-{
-	mac_init_scc_port(cflag, 1);
-}
-
 static int __init mac_debug_setup(char *arg)
 {
 	if (!MACH_IS_MAC)
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 3c943d2..43d83e0 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -30,8 +30,8 @@
 int oss_present;
 volatile struct mac_oss *oss;
 
-irqreturn_t oss_irq(int, void *);
-irqreturn_t oss_nubus_irq(int, void *);
+static irqreturn_t oss_irq(int, void *);
+static irqreturn_t oss_nubus_irq(int, void *);
 
 extern irqreturn_t via1_irq(int, void *);
 extern irqreturn_t mac_scc_dispatch(int, void *);
@@ -92,7 +92,7 @@
  * and SCSI; everything else is routed to its own autovector IRQ.
  */
 
-irqreturn_t oss_irq(int irq, void *dev_id)
+static irqreturn_t oss_irq(int irq, void *dev_id)
 {
 	int events;
 
@@ -126,7 +126,7 @@
  * Unlike the VIA/RBV this is on its own autovector interrupt level.
  */
 
-irqreturn_t oss_nubus_irq(int irq, void *dev_id)
+static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
 {
 	int events, irq_bit, i;
 
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index d66f723..f84a4dd 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -36,7 +36,7 @@
  * Debugging dump, used in various places to see what's going on.
  */
 
-void psc_debug_dump(void)
+static void psc_debug_dump(void)
 {
 	int	i;
 
@@ -55,7 +55,7 @@
  * expanded to cover what I think are the other 7 channels.
  */
 
-void psc_dma_die_die_die(void)
+static void psc_dma_die_die_die(void)
 {
 	int i;
 
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index fa485df..f3b27d0 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -45,7 +45,7 @@
 int rbv_present;
 int via_alt_mapping;
 EXPORT_SYMBOL(via_alt_mapping);
-__u8 rbv_clear;
+static __u8 rbv_clear;
 
 /*
  * Globals for accessing the VIA chip registers without having to
diff --git a/arch/m68k/math-emu/Makefile b/arch/m68k/math-emu/Makefile
index 5399404..a0935bf 100644
--- a/arch/m68k/math-emu/Makefile
+++ b/arch/m68k/math-emu/Makefile
@@ -2,8 +2,6 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_AFLAGS := -traditional
-
 #EXTRA_AFLAGS += -DFPU_EMU_DEBUG
 #EXTRA_CFLAGS += -DFPU_EMU_DEBUG
 
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index 30d34f2..226795b 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -285,7 +285,6 @@
 	 * to a couple of allocated pages
 	 */
 	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
-	memset(empty_zero_page, 0, PAGE_SIZE);
 
 	/*
 	 * Set up SFC/DFC registers
diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c
index 6a6513a..edceefc 100644
--- a/arch/m68k/mm/sun3mmu.c
+++ b/arch/m68k/mm/sun3mmu.c
@@ -53,7 +53,6 @@
 	wp_works_ok = 0;
 #endif
 	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
-	memset(empty_zero_page, 0, PAGE_SIZE);
 
 	address = PAGE_OFFSET;
 	pg_dir = swapper_pg_dir;
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 476e18e..be9de2f 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -41,14 +41,12 @@
 static int  q40_get_hardware_list(char *buffer);
 extern void q40_sched_init(irq_handler_t handler);
 
-extern unsigned long q40_gettimeoffset(void);
-extern int q40_hwclk(int, struct rtc_time *);
-extern unsigned int q40_get_ss(void);
-extern int q40_set_clock_mmss(unsigned long);
+static unsigned long q40_gettimeoffset(void);
+static int q40_hwclk(int, struct rtc_time *);
+static unsigned int q40_get_ss(void);
+static int q40_set_clock_mmss(unsigned long);
 static int q40_get_rtc_pll(struct rtc_pll_info *pll);
 static int q40_set_rtc_pll(struct rtc_pll_info *pll);
-extern void q40_reset(void);
-void q40_halt(void);
 extern void q40_waitbut(void);
 void q40_set_vectors(void);
 
@@ -127,7 +125,7 @@
 }
 #endif
 
-void q40_reset(void)
+static void q40_reset(void)
 {
         halted = 1;
         printk("\n\n*******************************************\n"
@@ -137,7 +135,8 @@
 	while (1)
 		;
 }
-void q40_halt(void)
+
+static void q40_halt(void)
 {
         halted = 1;
         printk("\n\n*******************\n"
@@ -165,7 +164,8 @@
 {
 	0x3f8,0x2f8,0x3e8,0x2e8,0
 };
-void q40_disable_irqs(void)
+
+static void q40_disable_irqs(void)
 {
 	unsigned i, j;
 
@@ -227,7 +227,7 @@
 }
 
 
-unsigned long q40_gettimeoffset(void)
+static unsigned long q40_gettimeoffset(void)
 {
 	return 5000 * (ql_ticks != 0);
 }
@@ -248,7 +248,7 @@
  * };
  */
 
-int q40_hwclk(int op, struct rtc_time *t)
+static int q40_hwclk(int op, struct rtc_time *t)
 {
 	if (op) {
 		/* Write.... */
@@ -285,7 +285,7 @@
 	return 0;
 }
 
-unsigned int q40_get_ss(void)
+static unsigned int q40_get_ss(void)
 {
 	return bcd2bin(Q40_RTC_SECS);
 }
@@ -295,7 +295,7 @@
  * clock is out by > 30 minutes.  Logic lifted from atari code.
  */
 
-int q40_set_clock_mmss(unsigned long nowtime)
+static int q40_set_clock_mmss(unsigned long nowtime)
 {
 	int retval = 0;
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile
index be1a847..38ba0e0 100644
--- a/arch/m68k/sun3/Makefile
+++ b/arch/m68k/sun3/Makefile
@@ -2,6 +2,6 @@
 # Makefile for Linux arch/m68k/sun3 source directory
 #
 
-obj-y	:= sun3ints.o sun3dvma.o sbus.o idprom.o
+obj-y	:= sun3ints.o sun3dvma.o idprom.o
 
 obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index c0fbd27..732087d 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -36,7 +36,7 @@
 char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
 
 extern unsigned long sun3_gettimeoffset(void);
-extern void sun3_sched_init(irq_handler_t handler);
+static void sun3_sched_init(irq_handler_t handler);
 extern void sun3_get_model (char* model);
 extern void idprom_init (void);
 extern int sun3_hwclk(int set, struct rtc_time *t);
@@ -114,7 +114,8 @@
 
 /* sun3 bootmem allocation */
 
-void __init sun3_bootmem_alloc(unsigned long memory_start, unsigned long memory_end)
+static void __init sun3_bootmem_alloc(unsigned long memory_start,
+				      unsigned long memory_end)
 {
 	unsigned long start_page;
 
@@ -164,7 +165,7 @@
 	sun3_bootmem_alloc(memory_start, memory_end);
 }
 
-void __init sun3_sched_init(irq_handler_t timer_routine)
+static void __init sun3_sched_init(irq_handler_t timer_routine)
 {
 	sun3_disable_interrupts();
         intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
diff --git a/arch/m68k/sun3/dvma.c b/arch/m68k/sun3/dvma.c
index d2b3093..d522eaa 100644
--- a/arch/m68k/sun3/dvma.c
+++ b/arch/m68k/sun3/dvma.c
@@ -19,7 +19,7 @@
 
 static unsigned long ptelist[120];
 
-inline unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr)
+static unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr)
 {
 	unsigned long pte;
 	unsigned long j;
diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c
index dca6ab6..c86ac37 100644
--- a/arch/m68k/sun3/idprom.c
+++ b/arch/m68k/sun3/idprom.c
@@ -1,4 +1,4 @@
-/* $Id: idprom.c,v 1.22 1996/11/13 05:09:25 davem Exp $
+/*
  * idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
@@ -25,7 +25,7 @@
  * of the Sparc CPU and have a meaningful IDPROM machtype value that we
  * know about.  See asm-sparc/machines.h for empirical constants.
  */
-struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
+static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
 /* First, Sun3's */
     { .name = "Sun 3/160 Series",	.id_machtype = (SM_SUN3 | SM_3_160) },
     { .name = "Sun 3/50",		.id_machtype = (SM_SUN3 | SM_3_50) },
diff --git a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c
index fb0f6a2..60f9d45 100644
--- a/arch/m68k/sun3/mmu_emu.c
+++ b/arch/m68k/sun3/mmu_emu.c
@@ -55,7 +55,7 @@
 
 /* pointers to the mm structs for each task in each
    context. 0xffffffff is a marker for kernel context */
-struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {
+static struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {
     [0] = (struct mm_struct *)0xffffffff
 };
 
diff --git a/arch/m68k/sun3/prom/Makefile b/arch/m68k/sun3/prom/Makefile
index 6e48ae2..da7eac0 100644
--- a/arch/m68k/sun3/prom/Makefile
+++ b/arch/m68k/sun3/prom/Makefile
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
diff --git a/arch/m68k/sun3/prom/console.c b/arch/m68k/sun3/prom/console.c
index 52c1427..2bcb6e4 100644
--- a/arch/m68k/sun3/prom/console.c
+++ b/arch/m68k/sun3/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.10 1996/12/18 06:46:54 tridge Exp $
+/*
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -104,8 +104,6 @@
 				return PROMDEV_ITTYB;
 		}
 		return PROMDEV_I_UNK;
-	case PROM_AP1000:
-		return PROMDEV_I_UNK;
 	};
 }
 #endif
@@ -166,8 +164,6 @@
 			};
 		}
 		break;
-	case PROM_AP1000:
-		return PROMDEV_I_UNK;
 	};
 	return PROMDEV_O_UNK;
 }
diff --git a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c
index 202adfc..d8e6349 100644
--- a/arch/m68k/sun3/prom/init.c
+++ b/arch/m68k/sun3/prom/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.9 1996/12/18 06:46:55 tridge Exp $
+/*
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -31,11 +31,6 @@
 
 void __init prom_init(struct linux_romvec *rp)
 {
-#ifdef CONFIG_AP1000
-	extern struct linux_romvec *ap_prom_init(void);
-	rp = ap_prom_init();
-#endif
-
 	romvec = rp;
 #ifndef CONFIG_SUN3
 	switch(romvec->pv_romvers) {
@@ -53,10 +48,6 @@
 		prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
 		prom_halt();
 		break;
-	case 42: /* why not :-) */
-		prom_vers = PROM_AP1000;
-		break;
-
 	default:
 		prom_printf("PROMLIB: Bad PROM version %d\n",
 			    romvec->pv_romvers);
diff --git a/arch/m68k/sun3/prom/misc.c b/arch/m68k/sun3/prom/misc.c
index b88716f..3d60e13 100644
--- a/arch/m68k/sun3/prom/misc.c
+++ b/arch/m68k/sun3/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $
+/*
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
diff --git a/arch/m68k/sun3/prom/printf.c b/arch/m68k/sun3/prom/printf.c
index e7bfde3..df85018 100644
--- a/arch/m68k/sun3/prom/printf.c
+++ b/arch/m68k/sun3/prom/printf.c
@@ -1,4 +1,4 @@
-/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $
+/*
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -37,10 +37,6 @@
 
 	bptr = ppbuf;
 
-#ifdef CONFIG_AP1000
-        ap_write(1,bptr,strlen(bptr));
-#else
-
 #ifdef CONFIG_KGDB
 	if (kgdb_initialized) {
 		printk("kgdb_initialized = %d\n", kgdb_initialized);
@@ -54,7 +50,6 @@
 		prom_putchar(ch);
 	}
 #endif
-#endif
 	va_end(args);
 	return;
 }
diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c
deleted file mode 100644
index babdbfa..0000000
--- a/arch/m68k/sun3/sbus.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SBus helper functions
- *
- * Sun3 don't have a sbus, but many of the used devices are also
- * used on Sparc machines with sbus. To avoid having a lot of
- * duplicate code, we provide necessary glue stuff to make using
- * of the sbus driver code possible.
- *
- * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- */
-
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-int __init sbus_init(void)
-{
-	return 0;
-}
-
-void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
-                      u32 bus_type, int rdonly)
-{
-	return (void *)address;
-}
-
-subsys_initcall(sbus_init);
diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c
index 8709677..f9277e8 100644
--- a/arch/m68k/sun3/sun3dvma.c
+++ b/arch/m68k/sun3/sun3dvma.c
@@ -29,7 +29,7 @@
 extern void sun3_dvma_init(void);
 #endif
 
-unsigned long iommu_use[IOMMU_TOTAL_ENTRIES];
+static unsigned long iommu_use[IOMMU_TOTAL_ENTRIES];
 
 #define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT)
 
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index cf93481..7364cd6 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -30,7 +30,7 @@
 	sun3_enable_irq(0);
 }
 
-int led_pattern[8] = {
+static int led_pattern[8] = {
        ~(0x80), ~(0x01),
        ~(0x40), ~(0x02),
        ~(0x20), ~(0x04),
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index d21df5f..b9c754f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -330,6 +330,7 @@
 	select SGI_HAS_DS1286
 	select SGI_HAS_I8042
 	select SGI_HAS_INDYDOG
+	select SGI_HAS_HAL2
 	select SGI_HAS_SEEQ
 	select SGI_HAS_WD93
 	select SGI_HAS_ZILOG
@@ -386,7 +387,6 @@
 	select SGI_HAS_I8042
 	select SGI_HAS_INDYDOG
 	select SGI_HAS_HAL2
-	select SGI_HAS_HAL2
 	select SGI_HAS_SEEQ
 	select SGI_HAS_WD93
 	select SGI_HAS_ZILOG
@@ -558,6 +558,24 @@
 config MACH_TX49XX
 	bool "Toshiba TX49 series based machines"
 
+config MIKROTIK_RB532
+	bool "Mikrotik RB532 boards"
+	select CEVT_R4K
+	select CSRC_R4K
+	select DMA_NONCOHERENT
+	select GENERIC_HARDIRQS_NO__DO_IRQ
+	select HW_HAS_PCI
+	select IRQ_CPU
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SWAP_IO_SPACE
+	select BOOT_RAW
+	select GENERIC_GPIO
+	help
+	  Support the Mikrotik(tm) RouterBoard 532 series,
+	  based on the IDT RC32434 SoC.
+
 config WR_PPMC
 	bool "Wind River PPMC board"
 	select CEVT_R4K
@@ -899,7 +917,7 @@
 
 config MIPS_L1_CACHE_SHIFT
 	int
-	default "4" if MACH_DECSTATION
+	default "4" if MACH_DECSTATION || MIKROTIK_RB532
 	default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM
 	default "4" if PMC_MSP4200_EVAL
 	default "5"
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 3564533..9aab51c 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -560,6 +560,13 @@
 core-$(CONFIG_TOSHIBA_JMR3927)	+= arch/mips/txx9/jmr3927/
 
 #
+# Routerboard 532 board
+#
+core-$(CONFIG_MIKROTIK_RB532)	+= arch/mips/rb532/
+cflags-$(CONFIG_MIKROTIK_RB532) += -Iinclude/asm-mips/mach-rc32434
+load-$(CONFIG_MIKROTIK_RB532)	+= 0xffffffff80101000
+
+#
 # Toshiba RBTX4927 board or
 # Toshiba RBTX4937 board
 #
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index dd23beb..b516442 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -81,8 +81,8 @@
 
 	set_io_port_base(CKSEG1ADDR(GT_DEF_PCI0_IO_BASE));
 
-	/* I/O port resource must include LCD/buttons */
-	ioport_resource.end = 0x0fffffff;
+	/* I/O port resource */
+	ioport_resource.end = 0x01ffffff;
 
 	/* These resources have been reserved by VIA SuperI/O chip. */
 	for (i = 0; i < ARRAY_SIZE(cobalt_reserved_resources); i++)
diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig
new file mode 100644
index 0000000..f28dc32
--- /dev/null
+++ b/arch/mips/configs/rb532_defconfig
@@ -0,0 +1,1314 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25
+# Mon Apr 28 12:24:17 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+CONFIG_MIKROTIK_RB532=y
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_GPIO=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_KPROBES is not set
+# CONFIG_HAVE_KRETPROBES is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+CONFIG_DEFAULT_VEGAS=y
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="vegas"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+CONFIG_LLC2=m
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RR=m
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+CONFIG_NET_SCH_NETEM=m
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_FLOW is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+# CONFIG_NET_ACT_NAT is not set
+CONFIG_NET_ACT_PEDIT=m
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+# CONFIG_AX25 is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+CONFIG_PATA_RB532=y
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+CONFIG_IFB=m
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_KORINA=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_TC35815 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=y
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_VIA_RHINE_NAPI=y
+# CONFIG_SC92031 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+CONFIG_ATMEL=m
+# CONFIG_PCI_ATMEL is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L1=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+# CONFIG_HID is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=m
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 65af3cc..c266211 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -129,23 +129,6 @@
 	return error;
 }
 
-
-asmlinkage int sys_truncate64(const char __user *path, unsigned int high,
-			      unsigned int low)
-{
-	if ((int)high < 0)
-		return -EINVAL;
-	return sys_truncate(path, ((long) high << 32) | low);
-}
-
-asmlinkage int sys_ftruncate64(unsigned int fd, unsigned int high,
-			       unsigned int low)
-{
-	if ((int)high < 0)
-		return -EINVAL;
-	return sys_ftruncate(fd, ((long) high << 32) | low);
-}
-
 /*
  * sys_execve() executes a new program.
  */
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index c058c0b..fc4fd4d 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -354,7 +354,7 @@
 	sys	sys_mkdir		2
 	sys	sys_rmdir		1	/* 4040 */
 	sys	sys_dup			1
-	sys	sys_pipe		0
+	sys	sysm_pipe		0
 	sys	sys_times		1
 	sys	sys_ni_syscall		0
 	sys	sys_brk			1	/* 4045 */
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index dc597b6..2b73fd1 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -219,7 +219,7 @@
 	PTR	sys_readv
 	PTR	sys_writev
 	PTR	sys_access			/* 5020 */
-	PTR	sys_pipe
+	PTR	sysm_pipe
 	PTR	sys_select
 	PTR	sys_sched_yield
 	PTR	sys_mremap
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 12940ec..2654e75 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -141,7 +141,7 @@
 	PTR	compat_sys_readv
 	PTR	compat_sys_writev
 	PTR	sys_access			/* 6020 */
-	PTR	sys_pipe
+	PTR	sysm_pipe
 	PTR	compat_sys_select
 	PTR	sys_sched_yield
 	PTR	sys_mremap
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 9a275ef..76167be 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -247,7 +247,7 @@
 	PTR	sys_mkdir
 	PTR	sys_rmdir			/* 4040 */
 	PTR	sys_dup
-	PTR	sys_pipe
+	PTR	sysm_pipe
 	PTR	compat_sys_times
 	PTR	sys_ni_syscall
 	PTR	sys_brk				/* 4045 */
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index af1bdc8..3523c8d 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -40,7 +40,14 @@
 #include <asm/sysmips.h>
 #include <asm/uaccess.h>
 
-asmlinkage int sys_pipe(nabi_no_regargs volatile struct pt_regs regs)
+/*
+ * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
+ * convention.  It returns results in registers $v0 / $v1 which means there
+ * is no need for it to do verify the validity of a userspace pointer
+ * argument.  Historically that used to be expensive in Linux.  These days
+ * the performance advantage is negligible.
+ */
+asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs)
 {
 	int fd[2];
 	int error, res;
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index ed49ef0..52e6c58 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -24,6 +24,7 @@
 #include <asm/signal.h>
 #include <asm/uaccess.h>
 
+#include <asm/fpu.h>
 #include <asm/fpu_emulator.h>
 
 #define SIGNALLING_NAN 0x7ff800007ff80000LL
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 57e34ca..15e01ae 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -49,3 +49,4 @@
 obj-$(CONFIG_VICTOR_MPC30X)	+= fixup-mpc30x.o
 obj-$(CONFIG_ZAO_CAPCELLA)	+= fixup-capcella.o
 obj-$(CONFIG_WR_PPMC)		+= fixup-wrppmc.o
+obj-$(CONFIG_MIKROTIK_RB532)	+= pci-rc32434.o ops-rc32434.o fixup-rc32434.o
diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c
new file mode 100644
index 0000000..75b90dc
--- /dev/null
+++ b/arch/mips/pci/fixup-rc32434.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or source@mvista.com
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach-rc32434/rc32434.h>
+
+static int __devinitdata irq_map[2][12] = {
+	{0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1},
+	{0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3}
+};
+
+int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq = 0;
+
+	if (dev->bus->number < 2 && PCI_SLOT(dev->devfn) < 12)
+		irq = irq_map[dev->bus->number][PCI_SLOT(dev->devfn)];
+
+	return irq + GROUP4_IRQ_BASE + 4;
+}
+
+static void rc32434_pci_early_fixup(struct pci_dev *dev)
+{
+	if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) {
+		/* disable prefetched memory range */
+		pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0);
+		pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x10);
+
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4);
+	}
+}
+
+/*
+ * The fixup applies to both the IDT and VIA devices present on the board
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, rc32434_pci_early_fixup);
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	return 0;
+}
diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c
new file mode 100644
index 0000000..d1f8fa2
--- /dev/null
+++ b/arch/mips/pci/ops-rc32434.c
@@ -0,0 +1,207 @@
+/*
+ *  BRIEF MODULE DESCRIPTION
+ *     pci_ops for IDT EB434 board
+ *
+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *  Copyright 2006 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include <asm/cpu.h>
+#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/pci.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+
+#define PCI_CFG_SET(bus, slot, func, off) \
+	(rc32434_pci->pcicfga = (0x80000000 | \
+				((bus) << 16) | ((slot)<<11) | \
+				((func)<<8) | (off)))
+
+static inline int config_access(unsigned char access_type,
+				struct pci_bus *bus, unsigned int devfn,
+				unsigned char where, u32 *data)
+{
+	unsigned int slot = PCI_SLOT(devfn);
+	u8 func = PCI_FUNC(devfn);
+
+	/* Setup address */
+	PCI_CFG_SET(bus->number, slot, func, where);
+	rc32434_sync();
+
+	if (access_type == PCI_ACCESS_WRITE)
+		rc32434_pci->pcicfgd = *data;
+	else
+		*data = rc32434_pci->pcicfgd;
+
+	rc32434_sync();
+
+	return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly.  Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
+			    int where, u8 *val)
+{
+	u32 data;
+	int ret;
+
+	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
+	*val = (data >> ((where & 3) << 3)) & 0xff;
+	return ret;
+}
+
+static int read_config_word(struct pci_bus *bus, unsigned int devfn,
+			    int where, u16 *val)
+{
+	u32 data;
+	int ret;
+
+	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
+	*val = (data >> ((where & 3) << 3)) & 0xffff;
+	return ret;
+}
+
+static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
+			     int where, u32 *val)
+{
+	int ret;
+	int delay = 1;
+
+	/*
+	 * Don't scan too far, else there will be errors with plugged in
+	 * daughterboard (rb564).
+	 */
+	if (bus->number == 0 && PCI_SLOT(devfn) > 21)
+		return 0;
+
+retry:
+	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
+
+	/*
+	 * Certain devices react delayed at device scan time, this
+	 * gives them time to settle
+	 */
+	if (where == PCI_VENDOR_ID) {
+		if (ret == 0xffffffff || ret == 0x00000000 ||
+		    ret == 0x0000ffff || ret == 0xffff0000) {
+			if (delay > 4)
+				return 0;
+			delay *= 2;
+			msleep(delay);
+			goto retry;
+		}
+	}
+
+	return ret;
+}
+
+static int
+write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
+		  u8 val)
+{
+	u32 data = 0;
+
+	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+		return -1;
+
+	data = (data & ~(0xff << ((where & 3) << 3))) |
+	    (val << ((where & 3) << 3));
+
+	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+		return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
+		  u16 val)
+{
+	u32 data = 0;
+
+	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+		return -1;
+
+	data = (data & ~(0xffff << ((where & 3) << 3))) |
+	    (val << ((where & 3) << 3));
+
+	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+		return -1;
+
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
+		   u32 val)
+{
+	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
+		return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_config_read(struct pci_bus *bus, unsigned int devfn,
+			   int where, int size, u32 *val)
+{
+	switch (size) {
+	case 1:
+		return read_config_byte(bus, devfn, where, (u8 *) val);
+	case 2:
+		return read_config_word(bus, devfn, where, (u16 *) val);
+	default:
+		return read_config_dword(bus, devfn, where, val);
+	}
+}
+
+static int pci_config_write(struct pci_bus *bus, unsigned int devfn,
+			    int where, int size, u32 val)
+{
+	switch (size) {
+	case 1:
+		return write_config_byte(bus, devfn, where, (u8) val);
+	case 2:
+		return write_config_word(bus, devfn, where, (u16) val);
+	default:
+		return write_config_dword(bus, devfn, where, val);
+	}
+}
+
+struct pci_ops rc32434_pci_ops = {
+	.read = pci_config_read,
+	.write = pci_config_write,
+};
diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c
new file mode 100644
index 0000000..1c2821e
--- /dev/null
+++ b/arch/mips/pci/pci-rc32434.c
@@ -0,0 +1,221 @@
+/*
+ *  BRIEF MODULE DESCRIPTION
+ *     PCI initialization for IDT EB434 board
+ *
+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/pci.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+/* define an unsigned array for the PCI registers */
+static unsigned int korina_cnfg_regs[25] = {
+	KORINA_CNFG1, KORINA_CNFG2, KORINA_CNFG3, KORINA_CNFG4,
+	KORINA_CNFG5, KORINA_CNFG6, KORINA_CNFG7, KORINA_CNFG8,
+	KORINA_CNFG9, KORINA_CNFG10, KORINA_CNFG11, KORINA_CNFG12,
+	KORINA_CNFG13, KORINA_CNFG14, KORINA_CNFG15, KORINA_CNFG16,
+	KORINA_CNFG17, KORINA_CNFG18, KORINA_CNFG19, KORINA_CNFG20,
+	KORINA_CNFG21, KORINA_CNFG22, KORINA_CNFG23, KORINA_CNFG24
+};
+static struct resource rc32434_res_pci_mem1;
+static struct resource rc32434_res_pci_mem2;
+
+static struct resource rc32434_res_pci_mem1 = {
+	.name = "PCI MEM1",
+	.start = 0x50000000,
+	.end = 0x5FFFFFFF,
+	.flags = IORESOURCE_MEM,
+	.parent = &rc32434_res_pci_mem1,
+	.sibling = NULL,
+	.child = &rc32434_res_pci_mem2
+};
+
+static struct resource rc32434_res_pci_mem2 = {
+	.name = "PCI Mem2",
+	.start = 0x60000000,
+	.end = 0x6FFFFFFF,
+	.flags = IORESOURCE_MEM,
+	.parent = &rc32434_res_pci_mem1,
+	.sibling = NULL,
+	.child = NULL
+};
+
+static struct resource rc32434_res_pci_io1 = {
+	.name = "PCI I/O1",
+	.start = 0x18800000,
+	.end = 0x188FFFFF,
+	.flags = IORESOURCE_IO,
+};
+
+extern struct pci_ops rc32434_pci_ops;
+
+#define PCI_MEM1_START	PCI_ADDR_START
+#define PCI_MEM1_END	(PCI_ADDR_START + CPUTOPCI_MEM_WIN - 1)
+#define PCI_MEM2_START	(PCI_ADDR_START + CPUTOPCI_MEM_WIN)
+#define PCI_MEM2_END	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN)  - 1)
+#define PCI_IO1_START	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN))
+#define PCI_IO1_END 							\
+	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN - 1)
+#define PCI_IO2_START							\
+	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN)
+#define PCI_IO2_END 							\
+	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + (2 * CPUTOPCI_IO_WIN) - 1)
+
+struct pci_controller rc32434_controller2;
+
+struct pci_controller rc32434_controller = {
+	.pci_ops = &rc32434_pci_ops,
+	.mem_resource = &rc32434_res_pci_mem1,
+	.io_resource = &rc32434_res_pci_io1,
+	.mem_offset = 0,
+	.io_offset = 0,
+
+};
+
+#ifdef __MIPSEB__
+#define PCI_ENDIAN_FLAG PCILBAC_sb_m
+#else
+#define PCI_ENDIAN_FLAG 0
+#endif
+
+static int __init rc32434_pcibridge_init(void)
+{
+	unsigned int pcicvalue, pcicdata = 0;
+	unsigned int dummyread, pcicntlval;
+	int loopCount;
+	unsigned int pci_config_addr;
+
+	pcicvalue = rc32434_pci->pcic;
+	pcicvalue = (pcicvalue >> PCIM_SHFT) & PCIM_BIT_LEN;
+	if (!((pcicvalue == PCIM_H_EA) ||
+	      (pcicvalue == PCIM_H_IA_FIX) ||
+	      (pcicvalue == PCIM_H_IA_RR))) {
+		pr_err(KERN_ERR "PCI init error!!!\n");
+		/* Not in Host Mode, return ERROR */
+		return -1;
+	}
+	/* Enables the Idle Grant mode, Arbiter Parking */
+	pcicdata |= (PCI_CTL_IGM | PCI_CTL_EAP | PCI_CTL_EN);
+	rc32434_pci->pcic = pcicdata;	/* Enable the PCI bus Interface */
+	/* Zero out the PCI status & PCI Status Mask */
+	for (;;) {
+		pcicdata = rc32434_pci->pcis;
+		if (!(pcicdata & PCI_STAT_RIP))
+			break;
+	}
+
+	rc32434_pci->pcis = 0;
+	rc32434_pci->pcism = 0xFFFFFFFF;
+	/* Zero out the PCI decoupled registers */
+	rc32434_pci->pcidac = 0;	/*
+					 * disable PCI decoupled accesses at
+					 * initialization
+					 */
+	rc32434_pci->pcidas = 0;	/* clear the status */
+	rc32434_pci->pcidasm = 0x0000007F;	/* Mask all the interrupts */
+	/* Mask PCI Messaging Interrupts */
+	rc32434_pci_msg->pciiic = 0;
+	rc32434_pci_msg->pciiim = 0xFFFFFFFF;
+	rc32434_pci_msg->pciioic = 0;
+	rc32434_pci_msg->pciioim = 0;
+
+
+	/* Setup PCILB0 as Memory Window */
+	rc32434_pci->pcilba[0].address = (unsigned int) (PCI_ADDR_START);
+
+	/* setup the PCI map address as same as the local address */
+
+	rc32434_pci->pcilba[0].mapping = (unsigned int) (PCI_ADDR_START);
+
+
+	/* Setup PCILBA1 as MEM */
+	rc32434_pci->pcilba[0].control =
+	    (((SIZE_256MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG);
+	dummyread = rc32434_pci->pcilba[0].control;	/* flush the CPU write Buffers */
+	rc32434_pci->pcilba[1].address = 0x60000000;
+	rc32434_pci->pcilba[1].mapping = 0x60000000;
+
+	/* setup PCILBA2 as IO Window */
+	rc32434_pci->pcilba[1].control =
+	    (((SIZE_256MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG);
+	dummyread = rc32434_pci->pcilba[1].control;	/* flush the CPU write Buffers */
+	rc32434_pci->pcilba[2].address = 0x18C00000;
+	rc32434_pci->pcilba[2].mapping = 0x18FFFFFF;
+
+	/* setup PCILBA2 as IO Window */
+	rc32434_pci->pcilba[2].control =
+	    (((SIZE_4MB & 0x1f) << PCI_LBAC_SIZE_BIT) | PCI_ENDIAN_FLAG);
+	dummyread = rc32434_pci->pcilba[2].control;	/* flush the CPU write Buffers */
+
+	/* Setup PCILBA3 as IO Window */
+	rc32434_pci->pcilba[3].address = 0x18800000;
+	rc32434_pci->pcilba[3].mapping = 0x18800000;
+	rc32434_pci->pcilba[3].control =
+	    ((((SIZE_1MB & 0x1ff) << PCI_LBAC_SIZE_BIT) | PCI_LBAC_MSI) |
+	     PCI_ENDIAN_FLAG);
+	dummyread = rc32434_pci->pcilba[3].control;	/* flush the CPU write Buffers */
+
+	pci_config_addr = (unsigned int) (0x80000004);
+	for (loopCount = 0; loopCount < 24; loopCount++) {
+		rc32434_pci->pcicfga = pci_config_addr;
+		dummyread = rc32434_pci->pcicfga;
+		rc32434_pci->pcicfgd = korina_cnfg_regs[loopCount];
+		dummyread = rc32434_pci->pcicfgd;
+		pci_config_addr += 4;
+	}
+	rc32434_pci->pcitc =
+	    (unsigned int) ((PCITC_RTIMER_VAL & 0xff) << PCI_TC_RTIMER_BIT) |
+	    ((PCITC_DTIMER_VAL & 0xff) << PCI_TC_DTIMER_BIT);
+
+	pcicntlval = rc32434_pci->pcic;
+	pcicntlval &= ~PCI_CTL_TNR;
+	rc32434_pci->pcic = pcicntlval;
+	pcicntlval = rc32434_pci->pcic;
+
+	return 0;
+}
+
+static int __init rc32434_pci_init(void)
+{
+	pr_info("PCI: Initializing PCI\n");
+
+	ioport_resource.start = rc32434_res_pci_io1.start;
+	ioport_resource.end = rc32434_res_pci_io1.end;
+
+	rc32434_pcibridge_init();
+
+	register_pci_controller(&rc32434_controller);
+	rc32434_sync();
+
+	return 0;
+}
+
+arch_initcall(rc32434_pci_init);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index d7d6cb0..77bd5b6 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -204,7 +204,7 @@
  *  If we set up a device for bus mastering, we need to check the latency
  *  timer as certain crappy BIOSes forget to set it properly.
  */
-unsigned int pcibios_max_latency = 255;
+static unsigned int pcibios_max_latency = 255;
 
 void pcibios_set_master(struct pci_dev *dev)
 {
diff --git a/arch/mips/rb532/Makefile b/arch/mips/rb532/Makefile
new file mode 100644
index 0000000..8f0b6b6
--- /dev/null
+++ b/arch/mips/rb532/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the RB532 board specific parts of the kernel
+#
+
+obj-y	 += irq.o time.o setup.o serial.o prom.o gpio.o devices.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
new file mode 100644
index 0000000..44fb0a6
--- /dev/null
+++ b/arch/mips/rb532/devices.c
@@ -0,0 +1,331 @@
+/*
+ *  RouterBoard 500 Platform devices
+ *
+ *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/bootinfo.h>
+
+#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/dma.h>
+#include <asm/mach-rc32434/dma_v.h>
+#include <asm/mach-rc32434/eth.h>
+#include <asm/mach-rc32434/rb.h>
+#include <asm/mach-rc32434/integ.h>
+#include <asm/mach-rc32434/gpio.h>
+
+#define ETH0_DMA_RX_IRQ   	(GROUP1_IRQ_BASE + 0)
+#define ETH0_DMA_TX_IRQ   	(GROUP1_IRQ_BASE + 1)
+#define ETH0_RX_OVR_IRQ   	(GROUP3_IRQ_BASE + 9)
+#define ETH0_TX_UND_IRQ   	(GROUP3_IRQ_BASE + 10)
+
+#define ETH0_RX_DMA_ADDR  (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
+#define ETH0_TX_DMA_ADDR  (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
+
+/* NAND definitions */
+#define GPIO_RDY (1 << 0x08)
+#define GPIO_WPX (1 << 0x09)
+#define GPIO_ALE (1 << 0x0a)
+#define GPIO_CLE (1 << 0x0b)
+
+extern char *board_type;
+
+static struct resource korina_dev0_res[] = {
+	{
+		.name = "korina_regs",
+		.start = ETH0_BASE_ADDR,
+		.end = ETH0_BASE_ADDR + sizeof(struct eth_regs),
+		.flags = IORESOURCE_MEM,
+	 }, {
+		.name = "korina_rx",
+		.start = ETH0_DMA_RX_IRQ,
+		.end = ETH0_DMA_RX_IRQ,
+		.flags = IORESOURCE_IRQ
+	}, {
+		.name = "korina_tx",
+		.start = ETH0_DMA_TX_IRQ,
+		.end = ETH0_DMA_TX_IRQ,
+		.flags = IORESOURCE_IRQ
+	}, {
+		.name = "korina_ovr",
+		.start = ETH0_RX_OVR_IRQ,
+		.end = ETH0_RX_OVR_IRQ,
+		.flags = IORESOURCE_IRQ
+	}, {
+		.name = "korina_und",
+		.start = ETH0_TX_UND_IRQ,
+		.end = ETH0_TX_UND_IRQ,
+		.flags = IORESOURCE_IRQ
+	}, {
+		.name = "korina_dma_rx",
+		.start = ETH0_RX_DMA_ADDR,
+		.end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
+		.flags = IORESOURCE_MEM,
+	 }, {
+		.name = "korina_dma_tx",
+		.start = ETH0_TX_DMA_ADDR,
+		.end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
+		.flags = IORESOURCE_MEM,
+	 }
+};
+
+static struct korina_device korina_dev0_data = {
+	.name = "korina0",
+	.mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee}
+};
+
+static struct platform_device korina_dev0 = {
+	.id = 0,
+	.name = "korina",
+	.dev.platform_data = &korina_dev0_data,
+	.resource = korina_dev0_res,
+	.num_resources = ARRAY_SIZE(korina_dev0_res),
+};
+
+#define CF_GPIO_NUM 13
+
+static struct resource cf_slot0_res[] = {
+	{
+		.name = "cf_membase",
+		.flags = IORESOURCE_MEM
+	}, {
+		.name = "cf_irq",
+		.start = (8 + 4 * 32 + CF_GPIO_NUM),	/* 149 */
+		.end = (8 + 4 * 32 + CF_GPIO_NUM),
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct cf_device cf_slot0_data = {
+	.gpio_pin = 13
+};
+
+static struct platform_device cf_slot0 = {
+	.id = 0,
+	.name = "pata-rb532-cf",
+	.dev.platform_data = &cf_slot0_data,
+	.resource = cf_slot0_res,
+	.num_resources = ARRAY_SIZE(cf_slot0_res),
+};
+
+/* Resources and device for NAND */
+static int rb532_dev_ready(struct mtd_info *mtd)
+{
+	return readl(IDT434_REG_BASE + GPIOD) & GPIO_RDY;
+}
+
+static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd->priv;
+	unsigned char orbits, nandbits;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		orbits = (ctrl & NAND_CLE) << 1;
+		orbits |= (ctrl & NAND_ALE) >> 1;
+
+		nandbits = (~ctrl & NAND_CLE) << 1;
+		nandbits |= (~ctrl & NAND_ALE) >> 1;
+
+		set_latch_u5(orbits, nandbits);
+	}
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, chip->IO_ADDR_W);
+}
+
+static struct resource nand_slot0_res[] = {
+	[0] = {
+		.name = "nand_membase",
+		.flags = IORESOURCE_MEM
+	}
+};
+
+static struct platform_nand_data rb532_nand_data = {
+	.ctrl.dev_ready = rb532_dev_ready,
+	.ctrl.cmd_ctrl	= rb532_cmd_ctrl,
+};
+
+static struct platform_device nand_slot0 = {
+	.name = "gen_nand",
+	.id = -1,
+	.resource = nand_slot0_res,
+	.num_resources = ARRAY_SIZE(nand_slot0_res),
+	.dev.platform_data = &rb532_nand_data,
+};
+
+static struct mtd_partition rb532_partition_info[] = {
+	{
+		.name = "Routerboard NAND boot",
+		.offset = 0,
+		.size = 4 * 1024 * 1024,
+	}, {
+		.name = "rootfs",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = MTDPART_SIZ_FULL,
+	}
+};
+
+static struct platform_device rb532_led = {
+	.name = "rb532-led",
+	.id = 0,
+};
+
+static struct gpio_keys_button rb532_gpio_btn[] = {
+	{
+		.gpio = 1,
+		.code = BTN_0,
+		.desc = "S1",
+		.active_low = 1,
+	}
+};
+
+static struct gpio_keys_platform_data rb532_gpio_btn_data = {
+	.buttons = rb532_gpio_btn,
+	.nbuttons = ARRAY_SIZE(rb532_gpio_btn),
+};
+
+static struct platform_device rb532_button = {
+	.name 	= "gpio-keys",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rb532_gpio_btn_data,
+	}
+};
+
+static struct resource rb532_wdt_res[] = {
+	{
+		.name = "rb532_wdt_res",
+		.start = INTEG0_BASE_ADDR,
+		.end = INTEG0_BASE_ADDR + sizeof(struct integ),
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device rb532_wdt = {
+	.name 		= "rc32434_wdt",
+	.id 		= -1,
+	.resource 	= rb532_wdt_res,
+	.num_resources	= ARRAY_SIZE(rb532_wdt_res),
+};
+
+static struct platform_device *rb532_devs[] = {
+	&korina_dev0,
+	&nand_slot0,
+	&cf_slot0,
+	&rb532_led,
+	&rb532_button,
+	&rb532_wdt
+};
+
+static void __init parse_mac_addr(char *macstr)
+{
+	int i, j;
+	unsigned char result, value;
+
+	for (i = 0; i < 6; i++) {
+		result = 0;
+
+		if (i != 5 && *(macstr + 2) != ':')
+			return;
+
+		for (j = 0; j < 2; j++) {
+			if (isxdigit(*macstr)
+			    && (value =
+				isdigit(*macstr) ? *macstr -
+				'0' : toupper(*macstr) - 'A' + 10) < 16) {
+				result = result * 16 + value;
+				macstr++;
+			} else
+				return;
+		}
+
+		macstr++;
+		korina_dev0_data.mac[i] = result;
+	}
+}
+
+
+/* DEVICE CONTROLLER 1 */
+#define CFG_DC_DEV1 	((void *)0xb8010010)
+#define CFG_DC_DEV2 	((void *)0xb8010020)
+#define CFG_DC_DEVBASE    0x0
+#define CFG_DC_DEVMASK    0x4
+#define CFG_DC_DEVC       0x8
+#define CFG_DC_DEVTC      0xC
+
+/* NAND definitions */
+#define NAND_CHIP_DELAY	25
+
+static void __init rb532_nand_setup(void)
+{
+	switch (mips_machtype) {
+	case MACH_MIKROTIK_RB532A:
+		set_latch_u5(LO_FOFF | LO_CEX,
+				LO_ULED | LO_ALE | LO_CLE | LO_WPX);
+		break;
+	default:
+		set_latch_u5(LO_WPX | LO_FOFF | LO_CEX,
+				LO_ULED | LO_ALE | LO_CLE);
+		break;
+	}
+
+	/* Setup NAND specific settings */
+	rb532_nand_data.chip.nr_chips = 1;
+	rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info);
+	rb532_nand_data.chip.partitions = rb532_partition_info;
+	rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY;
+	rb532_nand_data.chip.options = NAND_NO_AUTOINCR;
+}
+
+
+static int __init plat_setup_devices(void)
+{
+	/* Look for the CF card reader */
+	if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK))
+		rb532_devs[1] = NULL;
+	else {
+		cf_slot0_res[0].start =
+		    readl(CFG_DC_DEV1 + CFG_DC_DEVBASE);
+		cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000;
+	}
+
+	/* Read the NAND resources from the device controller */
+	nand_slot0_res[0].start = readl(CFG_DC_DEV2 + CFG_DC_DEVBASE);
+	nand_slot0_res[0].end = nand_slot0_res[0].start + 0x1000;
+
+	/* Initialise the NAND device */
+	rb532_nand_setup();
+
+	return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs));
+}
+
+static int __init setup_kmac(char *s)
+{
+	printk(KERN_INFO "korina mac = %s\n", s);
+	parse_mac_addr(s);
+	return 0;
+}
+
+__setup("kmac=", setup_kmac);
+
+arch_initcall(plat_setup_devices);
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c
new file mode 100644
index 0000000..b2fe82d
--- /dev/null
+++ b/arch/mips/rb532/gpio.c
@@ -0,0 +1,220 @@
+/*
+ *  Miscellaneous functions for IDT EB434 board
+ *
+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *  Copyright 2006 Phil Sutter <n0-1@freewrt.org>
+ *  Copyright 2007 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/addrspace.h>
+
+#include <asm/mach-rc32434/rb.h>
+
+struct rb532_gpio_reg __iomem *rb532_gpio_reg0;
+EXPORT_SYMBOL(rb532_gpio_reg0);
+
+struct mpmc_device dev3;
+
+static struct resource rb532_gpio_reg0_res[] = {
+	{
+		.name 	= "gpio_reg0",
+		.start 	= (u32)(IDT434_REG_BASE + GPIOBASE),
+		.end 	= (u32)(IDT434_REG_BASE + GPIOBASE + sizeof(struct rb532_gpio_reg)),
+		.flags 	= IORESOURCE_MEM,
+	}
+};
+
+static struct resource rb532_dev3_ctl_res[] = {
+	{
+		.name	= "dev3_ctl",
+		.start	= (u32)(IDT434_REG_BASE + DEV3BASE),
+		.end	= (u32)(IDT434_REG_BASE + DEV3BASE + sizeof(struct dev_reg)),
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val)
+{
+	unsigned flags, data;
+	unsigned i = 0;
+
+	spin_lock_irqsave(&dev3.lock, flags);
+
+	data = *(volatile unsigned *) (IDT434_REG_BASE + reg_offs);
+	for (i = 0; i != len; ++i) {
+		if (val & (1 << i))
+			data |= (1 << (i + bit));
+		else
+			data &= ~(1 << (i + bit));
+	}
+	writel(data, (IDT434_REG_BASE + reg_offs));
+
+	spin_unlock_irqrestore(&dev3.lock, flags);
+}
+EXPORT_SYMBOL(set_434_reg);
+
+unsigned get_434_reg(unsigned reg_offs)
+{
+	return readl(IDT434_REG_BASE + reg_offs);
+}
+EXPORT_SYMBOL(get_434_reg);
+
+void set_latch_u5(unsigned char or_mask, unsigned char nand_mask)
+{
+	unsigned flags;
+
+	spin_lock_irqsave(&dev3.lock, flags);
+
+	dev3.state = (dev3.state | or_mask) & ~nand_mask;
+	writel(dev3.state, &dev3.base);
+
+	spin_unlock_irqrestore(&dev3.lock, flags);
+}
+EXPORT_SYMBOL(set_latch_u5);
+
+unsigned char get_latch_u5(void)
+{
+	return dev3.state;
+}
+EXPORT_SYMBOL(get_latch_u5);
+
+int rb532_gpio_get_value(unsigned gpio)
+{
+	return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio);
+}
+EXPORT_SYMBOL(rb532_gpio_get_value);
+
+void rb532_gpio_set_value(unsigned gpio, int value)
+{
+	unsigned tmp;
+
+	tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio);
+	if (value)
+		tmp |= 1 << gpio;
+
+	writel(tmp, (void *)&rb532_gpio_reg0->gpiod);
+}
+EXPORT_SYMBOL(rb532_gpio_set_value);
+
+int rb532_gpio_direction_input(unsigned gpio)
+{
+	writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio),
+	       (void *)&rb532_gpio_reg0->gpiocfg);
+
+	return 0;
+}
+EXPORT_SYMBOL(rb532_gpio_direction_input);
+
+int rb532_gpio_direction_output(unsigned gpio, int value)
+{
+	gpio_set_value(gpio, value);
+	writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio),
+	       (void *)&rb532_gpio_reg0->gpiocfg);
+
+	return 0;
+}
+EXPORT_SYMBOL(rb532_gpio_direction_output);
+
+void rb532_gpio_set_int_level(unsigned gpio, int value)
+{
+	unsigned tmp;
+
+	tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio);
+	if (value)
+		tmp |= 1 << gpio;
+	writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel);
+}
+EXPORT_SYMBOL(rb532_gpio_set_int_level);
+
+int rb532_gpio_get_int_level(unsigned gpio)
+{
+	return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio);
+}
+EXPORT_SYMBOL(rb532_gpio_get_int_level);
+
+void rb532_gpio_set_int_status(unsigned gpio, int value)
+{
+	unsigned tmp;
+
+	tmp = readl(&rb532_gpio_reg0->gpioistat);
+	if (value)
+		tmp |= 1 << gpio;
+	writel(tmp, (void *)&rb532_gpio_reg0->gpioistat);
+}
+EXPORT_SYMBOL(rb532_gpio_set_int_status);
+
+int rb532_gpio_get_int_status(unsigned gpio)
+{
+	return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio);
+}
+EXPORT_SYMBOL(rb532_gpio_get_int_status);
+
+void rb532_gpio_set_func(unsigned gpio, int value)
+{
+	unsigned tmp;
+
+	tmp = readl(&rb532_gpio_reg0->gpiofunc);
+	if (value)
+		tmp |= 1 << gpio;
+	writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc);
+}
+EXPORT_SYMBOL(rb532_gpio_set_func);
+
+int rb532_gpio_get_func(unsigned gpio)
+{
+	return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio);
+}
+EXPORT_SYMBOL(rb532_gpio_get_func);
+
+int __init rb532_gpio_init(void)
+{
+	rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start,
+				rb532_gpio_reg0_res[0].end -
+				rb532_gpio_reg0_res[0].start);
+
+	if (!rb532_gpio_reg0) {
+		printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
+		return -ENXIO;
+	}
+
+	dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start,
+				rb532_dev3_ctl_res[0].end -
+				rb532_dev3_ctl_res[0].start);
+
+	if (!dev3.base) {
+		printk(KERN_ERR "rb532: cannot remap device controller 3\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+arch_initcall(rb532_gpio_init);
diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c
new file mode 100644
index 0000000..c0d0f95
--- /dev/null
+++ b/arch/mips/rb532/irq.c
@@ -0,0 +1,209 @@
+/*
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *              stevel@mvista.com or source@mvista.com
+ */
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+#include <asm/mach-rc32434/rc32434.h>
+
+struct intr_group {
+	u32 mask;	/* mask of valid bits in pending/mask registers */
+	volatile u32 *base_addr;
+};
+
+#define RC32434_NR_IRQS  (GROUP4_IRQ_BASE + 32)
+
+#if (NR_IRQS < RC32434_NR_IRQS)
+#error Too little irqs defined. Did you override <asm/irq.h> ?
+#endif
+
+static const struct intr_group intr_group[NUM_INTR_GROUPS] = {
+	{
+		.mask	= 0x0000efff,
+		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
+	{
+		.mask	= 0x00001fff,
+		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
+	{
+		.mask	= 0x00000007,
+		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
+	{
+		.mask	= 0x0003ffff,
+		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
+	{
+		.mask	= 0xffffffff,
+		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
+};
+
+#define READ_PEND(base) (*(base))
+#define READ_MASK(base) (*(base + 2))
+#define WRITE_MASK(base, val) (*(base + 2) = (val))
+
+static inline int irq_to_group(unsigned int irq_nr)
+{
+	return (irq_nr - GROUP0_IRQ_BASE) >> 5;
+}
+
+static inline int group_to_ip(unsigned int group)
+{
+	return group + 2;
+}
+
+static inline void enable_local_irq(unsigned int ip)
+{
+	int ipnum = 0x100 << ip;
+
+	set_c0_status(ipnum);
+}
+
+static inline void disable_local_irq(unsigned int ip)
+{
+	int ipnum = 0x100 << ip;
+
+	clear_c0_status(ipnum);
+}
+
+static inline void ack_local_irq(unsigned int ip)
+{
+	int ipnum = 0x100 << ip;
+
+	clear_c0_cause(ipnum);
+}
+
+static void rb532_enable_irq(unsigned int irq_nr)
+{
+	int ip = irq_nr - GROUP0_IRQ_BASE;
+	unsigned int group, intr_bit;
+	volatile unsigned int *addr;
+
+	if (ip < 0)
+		enable_local_irq(irq_nr);
+	else {
+		group = ip >> 5;
+
+		ip &= (1 << 5) - 1;
+		intr_bit = 1 << ip;
+
+		enable_local_irq(group_to_ip(group));
+
+		addr = intr_group[group].base_addr;
+		WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit);
+	}
+}
+
+static void rb532_disable_irq(unsigned int irq_nr)
+{
+	int ip = irq_nr - GROUP0_IRQ_BASE;
+	unsigned int group, intr_bit, mask;
+	volatile unsigned int *addr;
+
+	if (ip < 0) {
+		disable_local_irq(irq_nr);
+	} else {
+		group = ip >> 5;
+
+		ip &= (1 << 5) - 1;
+		intr_bit = 1 << ip;
+		addr = intr_group[group].base_addr;
+		mask = READ_MASK(addr);
+		mask |= intr_bit;
+		WRITE_MASK(addr, mask);
+
+		/*
+		 * if there are no more interrupts enabled in this
+		 * group, disable corresponding IP
+		 */
+		if (mask == intr_group[group].mask)
+			disable_local_irq(group_to_ip(group));
+	}
+}
+
+static void rb532_mask_and_ack_irq(unsigned int irq_nr)
+{
+	rb532_disable_irq(irq_nr);
+	ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
+}
+
+static struct irq_chip rc32434_irq_type = {
+	.name		= "RB532",
+	.ack		= rb532_disable_irq,
+	.mask		= rb532_disable_irq,
+	.mask_ack	= rb532_mask_and_ack_irq,
+	.unmask		= rb532_enable_irq,
+};
+
+void __init arch_init_irq(void)
+{
+	int i;
+
+	pr_info("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
+
+	for (i = 0; i < RC32434_NR_IRQS; i++)
+		set_irq_chip_and_handler(i,  &rc32434_irq_type,
+					handle_level_irq);
+}
+
+/* Main Interrupt dispatcher */
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int ip, pend, group;
+	volatile unsigned int *addr;
+	unsigned int cp0_cause = read_c0_cause() & read_c0_status();
+
+	if (cp0_cause & CAUSEF_IP7) {
+		do_IRQ(7);
+	} else {
+		ip = (cp0_cause & 0x7c00);
+		if (ip) {
+			group = 21 + (fls(ip) - 32);
+
+			addr = intr_group[group].base_addr;
+
+			pend = READ_PEND(addr);
+			pend &= ~READ_MASK(addr);	/* only unmasked interrupts */
+			pend = 39 + (fls(pend) - 32);
+			do_IRQ((group << 5) + pend);
+		}
+	}
+}
diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c
new file mode 100644
index 0000000..1bc0af8
--- /dev/null
+++ b/arch/mips/rb532/prom.c
@@ -0,0 +1,158 @@
+/*
+ *  RouterBoard 500 specific prom routines
+ *
+ *  Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com>
+ *  Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr>
+ *  Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org>
+ *			Felix Fietkau <nbd@openwrt.org>
+ *			Florian Fainelli <florian@openwrt.org>
+ *
+ *  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., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+
+#include <asm/bootinfo.h>
+#include <asm/mach-rc32434/ddr.h>
+#include <asm/mach-rc32434/prom.h>
+
+extern void __init setup_serial_port(void);
+
+unsigned int idt_cpu_freq = 132000000;
+EXPORT_SYMBOL(idt_cpu_freq);
+unsigned int gpio_bootup_state;
+EXPORT_SYMBOL(gpio_bootup_state);
+
+static struct resource ddr_reg[] = {
+	{
+		.name = "ddr-reg",
+		.start = DDR0_PHYS_ADDR,
+		.end = DDR0_PHYS_ADDR + sizeof(struct ddr_ram),
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+void __init prom_free_prom_memory(void)
+{
+	/* No prom memory to free */
+}
+
+static inline int match_tag(char *arg, const char *tag)
+{
+	return strncmp(arg, tag, strlen(tag)) == 0;
+}
+
+static inline unsigned long tag2ul(char *arg, const char *tag)
+{
+	char *num;
+
+	num = arg + strlen(tag);
+	return simple_strtoul(num, 0, 10);
+}
+
+void __init prom_setup_cmdline(void)
+{
+	char cmd_line[CL_SIZE];
+	char *cp, *board;
+	int prom_argc;
+	char **prom_argv, **prom_envp;
+	int i;
+
+	prom_argc = fw_arg0;
+	prom_argv = (char **) fw_arg1;
+	prom_envp = (char **) fw_arg2;
+
+	cp = cmd_line;
+		/* Note: it is common that parameters start
+		 * at argv[1] and not argv[0],
+		 * however, our elf loader starts at [0] */
+	for (i = 0; i < prom_argc; i++) {
+		if (match_tag(prom_argv[i], FREQ_TAG)) {
+			idt_cpu_freq = tag2ul(prom_argv[i], FREQ_TAG);
+			continue;
+		}
+#ifdef IGNORE_CMDLINE_MEM
+		/* parses out the "mem=xx" arg */
+		if (match_tag(prom_argv[i], MEM_TAG))
+			continue;
+#endif
+		if (i > 0)
+			*(cp++) = ' ';
+		if (match_tag(prom_argv[i], BOARD_TAG)) {
+			board = prom_argv[i] + strlen(BOARD_TAG);
+
+			if (match_tag(board, BOARD_RB532A))
+				mips_machtype = MACH_MIKROTIK_RB532A;
+			else
+				mips_machtype = MACH_MIKROTIK_RB532;
+		}
+
+		if (match_tag(prom_argv[i], GPIO_TAG))
+			gpio_bootup_state = tag2ul(prom_argv[i], GPIO_TAG);
+
+		strcpy(cp, prom_argv[i]);
+		cp += strlen(prom_argv[i]);
+	}
+	*(cp++) = ' ';
+
+	i = strlen(arcs_cmdline);
+	if (i > 0) {
+		*(cp++) = ' ';
+		strcpy(cp, arcs_cmdline);
+		cp += strlen(arcs_cmdline);
+	}
+	if (gpio_bootup_state & 0x02)
+		strcpy(cp, GPIO_INIT_NOBUTTON);
+	else
+		strcpy(cp, GPIO_INIT_BUTTON);
+
+	cmd_line[CL_SIZE-1] = '\0';
+
+	strcpy(arcs_cmdline, cmd_line);
+}
+
+void __init prom_init(void)
+{
+	struct ddr_ram __iomem *ddr;
+	phys_t memsize;
+	phys_t ddrbase;
+
+	ddr = ioremap_nocache(ddr_reg[0].start,
+			ddr_reg[0].end - ddr_reg[0].start);
+
+	if (!ddr) {
+		printk(KERN_ERR "Unable to remap DDR register\n");
+		return;
+	}
+
+	ddrbase = (phys_t)&ddr->ddrbase;
+	memsize = (phys_t)&ddr->ddrmask;
+	memsize = 0 - memsize;
+
+	prom_setup_cmdline();
+
+	/* give all RAM to boot allocator,
+	 * except for the first 0x400 and the last 0x200 bytes */
+	add_memory_region(ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM);
+}
diff --git a/arch/mips/rb532/serial.c b/arch/mips/rb532/serial.c
new file mode 100644
index 0000000..1a05b5d
--- /dev/null
+++ b/arch/mips/rb532/serial.c
@@ -0,0 +1,53 @@
+/*
+ *  BRIEF MODULE DESCRIPTION
+ *     Serial port initialisation.
+ *
+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/serial.h>
+#include <asm/mach-rc32434/rc32434.h>
+
+extern unsigned int idt_cpu_freq;
+
+static struct uart_port rb532_uart = {
+	.type = PORT_16550A,
+	.line = 0,
+	.irq = RC32434_UART0_IRQ,
+	.iotype = UPIO_MEM,
+	.membase = (char *)KSEG1ADDR(RC32434_UART0_BASE),
+	.regshift = 2
+};
+
+int __init setup_serial_port(void)
+{
+	rb532_uart.uartclk = idt_cpu_freq;
+
+	return early_serial_setup(&rb532_uart);
+}
+arch_initcall(setup_serial_port);
diff --git a/arch/mips/rb532/setup.c b/arch/mips/rb532/setup.c
new file mode 100644
index 0000000..7aafa95
--- /dev/null
+++ b/arch/mips/rb532/setup.c
@@ -0,0 +1,79 @@
+/*
+ * setup.c - boot time setup code
+ */
+
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <linux/ioport.h>
+
+#include <asm/mach-rc32434/rc32434.h>
+#include <asm/mach-rc32434/pci.h>
+
+struct pci_reg __iomem *pci_reg;
+EXPORT_SYMBOL(pci_reg);
+
+static struct resource pci0_res[] = {
+	{
+		.name = "pci_reg0",
+		.start = PCI0_BASE_ADDR,
+		.end = PCI0_BASE_ADDR + sizeof(struct pci_reg),
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static void rb_machine_restart(char *command)
+{
+	/* just jump to the reset vector */
+	writel(0x80000001, (void *)KSEG1ADDR(RC32434_REG_BASE + RC32434_RST));
+	((void (*)(void)) KSEG1ADDR(0x1FC00000u))();
+}
+
+static void rb_machine_halt(void)
+{
+	for (;;)
+		continue;
+}
+
+void __init plat_mem_setup(void)
+{
+	u32 val;
+
+	_machine_restart = rb_machine_restart;
+	_machine_halt = rb_machine_halt;
+	pm_power_off = rb_machine_halt;
+
+	set_io_port_base(KSEG1);
+
+	pci_reg = ioremap_nocache(pci0_res[0].start,
+				pci0_res[0].end - pci0_res[0].start);
+	if (!pci_reg) {
+		printk(KERN_ERR "Could not remap PCI registers\n");
+		return;
+	}
+
+	val = __raw_readl(&pci_reg->pcic);
+	val &= 0xFFFFFF7;
+	__raw_writel(val, (void *)&pci_reg->pcic);
+
+#ifdef CONFIG_PCI
+	/* Enable PCI interrupts in EPLD Mask register */
+	*epld_mask = 0x0;
+	*(epld_mask + 1) = 0x0;
+#endif
+	write_c0_wired(0);
+}
+
+const char *get_system_type(void)
+{
+	switch (mips_machtype) {
+	case MACH_MIKROTIK_RB532A:
+		return "Mikrotik RB532A";
+		break;
+	default:
+		return "Mikrotik RB532";
+		break;
+	}
+}
diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c
new file mode 100644
index 0000000..db74edf
--- /dev/null
+++ b/arch/mips/rb532/time.c
@@ -0,0 +1,67 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ *  Setting up the clock on the MIPS boards.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <linux/irq.h>
+#include <linux/timex.h>
+
+#include <asm/mipsregs.h>
+#include <asm/debug.h>
+#include <asm/time.h>
+#include <asm/mach-rc32434/rc32434.h>
+
+extern unsigned int idt_cpu_freq;
+
+/*
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick. There is no RTC available.
+ *
+ * The RC32434 counts at half the CPU *core* speed.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+	mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2;
+
+	return mips_hpt_frequency / HZ;
+}
+
+void __init plat_time_init(void)
+{
+	unsigned int est_freq, flags;
+	unsigned long r4k_offset;
+
+	local_irq_save(flags);
+
+	printk(KERN_INFO "calculating r4koff... ");
+	r4k_offset = cal_r4koff();
+	printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+	est_freq = 2 * r4k_offset * HZ;
+	est_freq += 5000;	/* round */
+	est_freq -= est_freq % 10000;
+	printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000,
+	       (est_freq % 1000000) * 100 / 1000000);
+	local_irq_restore(flags);
+}
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
index fc6df96..6014123 100644
--- a/arch/mips/sgi-ip22/ip22-platform.c
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -188,8 +188,7 @@
 	if (ip22_is_fullhouse())
 		return 0; /* full house has no volume buttons */
 
-	return IS_ERR(platform_device_register_simple("sgiindybtns",
-						      -1, NULL, 0));
+	return IS_ERR(platform_device_register_simple("sgibtns", -1, NULL, 0));
 }
 
 device_initcall(sgi_button_devinit);
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c
index fee7a2e..30e12e2 100644
--- a/arch/mips/sgi-ip22/ip28-berr.c
+++ b/arch/mips/sgi-ip22/ip28-berr.c
@@ -412,7 +412,7 @@
 	 * Now we have an asynchronous bus error, speculatively or DMA caused.
 	 * Need to search all DMA descriptors for the error address.
 	 */
-	for (i = 0; i < ARRAY_SIZE(hpc3); ++i) {
+	for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) {
 		struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
 		if ((cpu_err_stat & CPU_ERRMASK) &&
 		    (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp))
@@ -421,7 +421,7 @@
 		    (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp))
 			break;
 	}
-	if (i < ARRAY_SIZE(hpc3)) {
+	if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) {
 		struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
 		printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:"
 		       " ctl %08x, ndp %08x, cbp %08x\n",
diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c
index 2ee401b..3d63721 100644
--- a/arch/mips/sgi-ip32/ip32-platform.c
+++ b/arch/mips/sgi-ip32/ip32-platform.c
@@ -85,18 +85,7 @@
 
 static __init int sgio2btns_devinit(void)
 {
-	struct platform_device *pd;
-	int ret;
-
-	pd = platform_device_alloc("sgio2btns", -1);
-	if (!pd)
-		return -ENOMEM;
-
-	ret = platform_device_add(pd);
-	if (ret)
-		platform_device_put(pd);
-
-	return ret;
+	return IS_ERR(platform_device_register_simple("sgibtns", -1, NULL, 0));
 }
 
 device_initcall(sgio2btns_devinit);
diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig
index b92a134..6de4c5a 100644
--- a/arch/mips/txx9/Kconfig
+++ b/arch/mips/txx9/Kconfig
@@ -7,6 +7,8 @@
 	bool "Toshiba RBTX49[23]7 board"
 	depends on MACH_TX49XX
 	select SOC_TX4927
+	# TX4937 is subset of TX4938
+	select SOC_TX4938
 	help
 	  This Toshiba board is based on the TX4927 processor. Say Y here to
 	  support this machine type
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile
index 668fdaa..9c12077 100644
--- a/arch/mips/txx9/generic/Makefile
+++ b/arch/mips/txx9/generic/Makefile
@@ -4,8 +4,8 @@
 
 obj-y	+= setup.o
 obj-$(CONFIG_PCI)	+= pci.o
-obj-$(CONFIG_SOC_TX4927)	+= mem_tx4927.o irq_tx4927.o
-obj-$(CONFIG_SOC_TX4938)	+= mem_tx4938.o irq_tx4938.o
+obj-$(CONFIG_SOC_TX4927)	+= mem_tx4927.o setup_tx4927.o irq_tx4927.o
+obj-$(CONFIG_SOC_TX4938)	+= mem_tx4927.o setup_tx4938.o irq_tx4938.o
 obj-$(CONFIG_TOSHIBA_FPCIB0)	+= smsc_fdc37m81x.o
 obj-$(CONFIG_KGDB)	+= dbgio.o
 
diff --git a/arch/mips/txx9/generic/irq_tx4927.c b/arch/mips/txx9/generic/irq_tx4927.c
index 6377bd8..cbea1fd 100644
--- a/arch/mips/txx9/generic/irq_tx4927.c
+++ b/arch/mips/txx9/generic/irq_tx4927.c
@@ -31,7 +31,7 @@
 void __init tx4927_irq_init(void)
 {
 	mips_cpu_irq_init();
-	txx9_irq_init(TX4927_IRC_REG);
+	txx9_irq_init(TX4927_IRC_REG & 0xfffffffffULL);
 	set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4927_IRC_INT,
 				handle_simple_irq);
 }
diff --git a/arch/mips/txx9/generic/irq_tx4938.c b/arch/mips/txx9/generic/irq_tx4938.c
index 5fc86c9..6eac684 100644
--- a/arch/mips/txx9/generic/irq_tx4938.c
+++ b/arch/mips/txx9/generic/irq_tx4938.c
@@ -19,7 +19,7 @@
 void __init tx4938_irq_init(void)
 {
 	mips_cpu_irq_init();
-	txx9_irq_init(TX4938_IRC_REG);
+	txx9_irq_init(TX4938_IRC_REG & 0xfffffffffULL);
 	set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4938_IRC_INT,
 				handle_simple_irq);
 }
diff --git a/arch/mips/txx9/generic/mem_tx4927.c b/arch/mips/txx9/generic/mem_tx4927.c
index 12dfc37..ef6ea6e 100644
--- a/arch/mips/txx9/generic/mem_tx4927.c
+++ b/arch/mips/txx9/generic/mem_tx4927.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/mips/tx4927/common/tx4927_prom.c
+ * linux/arch/mips/txx9/generic/mem_tx4927.c
  *
  * common tx4927 memory interface
  *
@@ -32,8 +32,9 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <asm/txx9/tx4927.h>
 
-static unsigned int __init tx4927_process_sdccr(unsigned long addr)
+static unsigned int __init tx4927_process_sdccr(u64 __iomem *addr)
 {
 	u64 val;
 	unsigned int sdccr_ce;
@@ -45,97 +46,32 @@
 	unsigned int rs = 0;
 	unsigned int cs = 0;
 	unsigned int mw = 0;
-	unsigned int msize = 0;
 
-	val = __raw_readq((void __iomem *)addr);
+	val = __raw_readq(addr);
 
 	/* MVMCP -- need #defs for these bits masks */
 	sdccr_ce = ((val & (1 << 10)) >> 10);
 	sdccr_bs = ((val & (1 << 8)) >> 8);
 	sdccr_rs = ((val & (3 << 5)) >> 5);
-	sdccr_cs = ((val & (3 << 2)) >> 2);
+	sdccr_cs = ((val & (7 << 2)) >> 2);
 	sdccr_mw = ((val & (1 << 0)) >> 0);
 
 	if (sdccr_ce) {
-		switch (sdccr_bs) {
-		case 0:{
-				bs = 2;
-				break;
-			}
-		case 1:{
-				bs = 4;
-				break;
-			}
-		}
-		switch (sdccr_rs) {
-		case 0:{
-				rs = 2048;
-				break;
-			}
-		case 1:{
-				rs = 4096;
-				break;
-			}
-		case 2:{
-				rs = 8192;
-				break;
-			}
-		case 3:{
-				rs = 0;
-				break;
-			}
-		}
-		switch (sdccr_cs) {
-		case 0:{
-				cs = 256;
-				break;
-			}
-		case 1:{
-				cs = 512;
-				break;
-			}
-		case 2:{
-				cs = 1024;
-				break;
-			}
-		case 3:{
-				cs = 2048;
-				break;
-			}
-		}
-		switch (sdccr_mw) {
-		case 0:{
-				mw = 8;
-				break;
-			}	/* 8 bytes = 64 bits */
-		case 1:{
-				mw = 4;
-				break;
-			}	/* 4 bytes = 32 bits */
-		}
+		bs = 2 << sdccr_bs;
+		rs = 2048 << sdccr_rs;
+		cs = 256 << sdccr_cs;
+		mw = 8 >> sdccr_mw;
 	}
 
-	/*            bytes per chip     MB per chip      num chips */
-	msize = (((rs * cs * mw) / (1024 * 1024)) * bs);
-
-	return (msize);
+	return rs * cs * mw * bs;
 }
 
-
 unsigned int __init tx4927_get_mem_size(void)
 {
-	unsigned int c0;
-	unsigned int c1;
-	unsigned int c2;
-	unsigned int c3;
-	unsigned int total;
+	unsigned int total = 0;
+	int i;
 
-	/* MVMCP -- need #defs for these registers */
-	c0 = tx4927_process_sdccr(0xff1f8000);
-	c1 = tx4927_process_sdccr(0xff1f8008);
-	c2 = tx4927_process_sdccr(0xff1f8010);
-	c3 = tx4927_process_sdccr(0xff1f8018);
-	total = c0 + c1 + c2 + c3;
-
-	return (total);
+	for (i = 0; i < ARRAY_SIZE(tx4927_sdramcptr->cr); i++)
+		total += tx4927_process_sdccr(&tx4927_sdramcptr->cr[i]);
+	return total;
 }
diff --git a/arch/mips/txx9/generic/mem_tx4938.c b/arch/mips/txx9/generic/mem_tx4938.c
deleted file mode 100644
index 20baeae..0000000
--- a/arch/mips/txx9/generic/mem_tx4938.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/arch/mips/tx4938/common/prom.c
- *
- * common tx4938 memory interface
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/io.h>
-
-static unsigned int __init
-tx4938_process_sdccr(u64 * addr)
-{
-	u64 val;
-	unsigned int sdccr_ce;
-	unsigned int sdccr_rs;
-	unsigned int sdccr_cs;
-	unsigned int sdccr_mw;
-	unsigned int rs = 0;
-	unsigned int cs = 0;
-	unsigned int mw = 0;
-	unsigned int bc = 4;
-	unsigned int msize = 0;
-
-	val = ____raw_readq((void __iomem *)addr);
-
-	/* MVMCP -- need #defs for these bits masks */
-	sdccr_ce = ((val & (1 << 10)) >> 10);
-	sdccr_rs = ((val & (3 << 5)) >> 5);
-	sdccr_cs = ((val & (7 << 2)) >> 2);
-	sdccr_mw = ((val & (1 << 0)) >> 0);
-
-	if (sdccr_ce) {
-		switch (sdccr_rs) {
-		case 0:{
-				rs = 2048;
-				break;
-			}
-		case 1:{
-				rs = 4096;
-				break;
-			}
-		case 2:{
-				rs = 8192;
-				break;
-			}
-		default:{
-				rs = 0;
-				break;
-			}
-		}
-		switch (sdccr_cs) {
-		case 0:{
-				cs = 256;
-				break;
-			}
-		case 1:{
-				cs = 512;
-				break;
-			}
-		case 2:{
-				cs = 1024;
-				break;
-			}
-		case 3:{
-				cs = 2048;
-				break;
-			}
-		case 4:{
-				cs = 4096;
-				break;
-			}
-		default:{
-				cs = 0;
-				break;
-			}
-		}
-		switch (sdccr_mw) {
-		case 0:{
-				mw = 8;
-				break;
-			}	/* 8 bytes = 64 bits */
-		case 1:{
-				mw = 4;
-				break;
-			}	/* 4 bytes = 32 bits */
-		}
-	}
-
-	/*           bytes per chip    MB per chip          bank count */
-	msize = (((rs * cs * mw) / (1024 * 1024)) * (bc));
-
-	/* MVMCP -- bc hard coded to 4 from table 9.3.1     */
-	/*          boad supports bc=2 but no way to detect */
-
-	return (msize);
-}
-
-unsigned int __init
-tx4938_get_mem_size(void)
-{
-	unsigned int c0;
-	unsigned int c1;
-	unsigned int c2;
-	unsigned int c3;
-	unsigned int total;
-
-	/* MVMCP -- need #defs for these registers */
-	c0 = tx4938_process_sdccr((u64 *) 0xff1f8000);
-	c1 = tx4938_process_sdccr((u64 *) 0xff1f8008);
-	c2 = tx4938_process_sdccr((u64 *) 0xff1f8010);
-	c3 = tx4938_process_sdccr((u64 *) 0xff1f8018);
-	total = c0 + c1 + c2 + c3;
-
-	return (total);
-}
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index 5afc5d5..8c60c78 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -19,7 +19,9 @@
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <asm/bootinfo.h>
+#include <asm/time.h>
 #include <asm/txx9/generic.h>
 #ifdef CONFIG_CPU_TX49XX
 #include <asm/txx9/tx4938.h>
@@ -30,6 +32,7 @@
 static char txx9_ce_res_name[8][4];	/* "CEn" */
 
 /* pcode, internal register */
+unsigned int txx9_pcode;
 char txx9_pcode_str[8];
 static struct resource txx9_reg_res = {
 	.name = txx9_pcode_str,
@@ -59,15 +62,16 @@
 unsigned int txx9_cpu_clock;
 unsigned int txx9_gbus_clock;
 
+int txx9_ccfg_toeon __initdata = 1;
 
 /* Minimum CLK support */
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
 	if (!strcmp(id, "spi-baseclk"))
-		return (struct clk *)(txx9_gbus_clock / 2 / 4);
+		return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4);
 	if (!strcmp(id, "imbus_clk"))
-		return (struct clk *)(txx9_gbus_clock / 2);
+		return (struct clk *)((unsigned long)txx9_gbus_clock / 2);
 	return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
@@ -94,6 +98,22 @@
 }
 EXPORT_SYMBOL(clk_put);
 
+/* GPIO support */
+
+#ifdef CONFIG_GENERIC_GPIO
+int gpio_to_irq(unsigned gpio)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned irq)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+#endif
+
 extern struct txx9_board_vec jmr3927_vec;
 extern struct txx9_board_vec rbtx4927_vec;
 extern struct txx9_board_vec rbtx4937_vec;
@@ -107,6 +127,12 @@
 	int argc = (int)fw_arg0;
 	char **argv = (char **)fw_arg1;
 	int i;			/* Always ignore the "-c" at argv[0] */
+#ifdef CONFIG_64BIT
+	char *fixed_argv[32];
+	for (i = 0; i < argc; i++)
+		fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i));
+	argv = fixed_argv;
+#endif
 
 	/* ignore all built-in args if any f/w args given */
 	if (argc > 1)
@@ -126,15 +152,19 @@
 #endif
 #ifdef CONFIG_CPU_TX49XX
 	switch (TX4938_REV_PCODE()) {
+#ifdef CONFIG_TOSHIBA_RBTX4927
 	case 0x4927:
 		txx9_board_vec = &rbtx4927_vec;
 		break;
 	case 0x4937:
 		txx9_board_vec = &rbtx4937_vec;
 		break;
+#endif
+#ifdef CONFIG_TOSHIBA_RBTX4938
 	case 0x4938:
 		txx9_board_vec = &rbtx4938_vec;
 		break;
+#endif
 	}
 #endif
 
@@ -160,6 +190,10 @@
 /* wrappers */
 void __init plat_mem_setup(void)
 {
+	ioport_resource.start = 0;
+	ioport_resource.end = ~0UL;	/* no limit */
+	iomem_resource.start = 0;
+	iomem_resource.end = ~0UL;	/* no limit */
 	txx9_board_vec->mem_setup();
 }
 
diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c
new file mode 100644
index 0000000..89d6e28
--- /dev/null
+++ b/arch/mips/txx9/generic/setup_tx4927.c
@@ -0,0 +1,194 @@
+/*
+ * TX4927 setup routines
+ * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * 2003-2005 (c) MontaVista Software, Inc.
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+#include <linux/param.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9tmr.h>
+#include <asm/txx9pio.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/tx4927.h>
+
+void __init tx4927_wdr_init(void)
+{
+	/* clear WatchDogReset (W1C) */
+	tx4927_ccfg_set(TX4927_CCFG_WDRST);
+	/* do reset on watchdog */
+	tx4927_ccfg_set(TX4927_CCFG_WR);
+}
+
+static struct resource tx4927_sdram_resource[4];
+
+void __init tx4927_setup(void)
+{
+	int i;
+	__u32 divmode;
+	int cpuclk = 0;
+	u64 ccfg;
+
+	txx9_reg_res_init(TX4927_REV_PCODE(), TX4927_REG_BASE,
+			  TX4927_REG_SIZE);
+
+	/* SDRAMC,EBUSC are configured by PROM */
+	for (i = 0; i < 8; i++) {
+		if (!(TX4927_EBUSC_CR(i) & 0x8))
+			continue;	/* disabled */
+		txx9_ce_res[i].start = (unsigned long)TX4927_EBUSC_BA(i);
+		txx9_ce_res[i].end =
+			txx9_ce_res[i].start + TX4927_EBUSC_SIZE(i) - 1;
+		request_resource(&iomem_resource, &txx9_ce_res[i]);
+	}
+
+	/* clocks */
+	ccfg = ____raw_readq(&tx4927_ccfgptr->ccfg);
+	if (txx9_master_clock) {
+		/* calculate gbus_clock and cpu_clock from master_clock */
+		divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK;
+		switch (divmode) {
+		case TX4927_CCFG_DIVMODE_8:
+		case TX4927_CCFG_DIVMODE_10:
+		case TX4927_CCFG_DIVMODE_12:
+		case TX4927_CCFG_DIVMODE_16:
+			txx9_gbus_clock = txx9_master_clock * 4; break;
+		default:
+			txx9_gbus_clock = txx9_master_clock;
+		}
+		switch (divmode) {
+		case TX4927_CCFG_DIVMODE_2:
+		case TX4927_CCFG_DIVMODE_8:
+			cpuclk = txx9_gbus_clock * 2; break;
+		case TX4927_CCFG_DIVMODE_2_5:
+		case TX4927_CCFG_DIVMODE_10:
+			cpuclk = txx9_gbus_clock * 5 / 2; break;
+		case TX4927_CCFG_DIVMODE_3:
+		case TX4927_CCFG_DIVMODE_12:
+			cpuclk = txx9_gbus_clock * 3; break;
+		case TX4927_CCFG_DIVMODE_4:
+		case TX4927_CCFG_DIVMODE_16:
+			cpuclk = txx9_gbus_clock * 4; break;
+		}
+		txx9_cpu_clock = cpuclk;
+	} else {
+		if (txx9_cpu_clock == 0)
+			txx9_cpu_clock = 200000000;	/* 200MHz */
+		/* calculate gbus_clock and master_clock from cpu_clock */
+		cpuclk = txx9_cpu_clock;
+		divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK;
+		switch (divmode) {
+		case TX4927_CCFG_DIVMODE_2:
+		case TX4927_CCFG_DIVMODE_8:
+			txx9_gbus_clock = cpuclk / 2; break;
+		case TX4927_CCFG_DIVMODE_2_5:
+		case TX4927_CCFG_DIVMODE_10:
+			txx9_gbus_clock = cpuclk * 2 / 5; break;
+		case TX4927_CCFG_DIVMODE_3:
+		case TX4927_CCFG_DIVMODE_12:
+			txx9_gbus_clock = cpuclk / 3; break;
+		case TX4927_CCFG_DIVMODE_4:
+		case TX4927_CCFG_DIVMODE_16:
+			txx9_gbus_clock = cpuclk / 4; break;
+		}
+		switch (divmode) {
+		case TX4927_CCFG_DIVMODE_8:
+		case TX4927_CCFG_DIVMODE_10:
+		case TX4927_CCFG_DIVMODE_12:
+		case TX4927_CCFG_DIVMODE_16:
+			txx9_master_clock = txx9_gbus_clock / 4; break;
+		default:
+			txx9_master_clock = txx9_gbus_clock;
+		}
+	}
+	/* change default value to udelay/mdelay take reasonable time */
+	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
+
+	/* CCFG */
+	tx4927_wdr_init();
+	/* clear BusErrorOnWrite flag (W1C) */
+	tx4927_ccfg_set(TX4927_CCFG_BEOW);
+	/* enable Timeout BusError */
+	if (txx9_ccfg_toeon)
+		tx4927_ccfg_set(TX4927_CCFG_TOE);
+
+	/* DMA selection */
+	txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_DMASEL_ALL);
+
+	/* Use external clock for external arbiter */
+	if (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB))
+		txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_PCICLKEN_ALL);
+
+	printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
+	       txx9_pcode_str,
+	       (cpuclk + 500000) / 1000000,
+	       (txx9_master_clock + 500000) / 1000000,
+	       (__u32)____raw_readq(&tx4927_ccfgptr->crir),
+	       (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg),
+	       (unsigned long long)____raw_readq(&tx4927_ccfgptr->pcfg));
+
+	printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str);
+	for (i = 0; i < 4; i++) {
+		__u64 cr = TX4927_SDRAMC_CR(i);
+		unsigned long base, size;
+		if (!((__u32)cr & 0x00000400))
+			continue;	/* disabled */
+		base = (unsigned long)(cr >> 49) << 21;
+		size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
+		printk(" CR%d:%016llx", i, (unsigned long long)cr);
+		tx4927_sdram_resource[i].name = "SDRAM";
+		tx4927_sdram_resource[i].start = base;
+		tx4927_sdram_resource[i].end = base + size - 1;
+		tx4927_sdram_resource[i].flags = IORESOURCE_MEM;
+		request_resource(&iomem_resource, &tx4927_sdram_resource[i]);
+	}
+	printk(" TR:%09llx\n",
+	       (unsigned long long)____raw_readq(&tx4927_sdramcptr->tr));
+
+	/* TMR */
+	/* disable all timers */
+	for (i = 0; i < TX4927_NR_TMR; i++)
+		txx9_tmr_init(TX4927_TMR_REG(i) & 0xfffffffffULL);
+
+	/* PIO */
+	txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO);
+	__raw_writel(0, &tx4927_pioptr->maskcpu);
+	__raw_writel(0, &tx4927_pioptr->maskext);
+}
+
+void __init tx4927_time_init(unsigned int tmrnr)
+{
+	if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_TINTDIS)
+		txx9_clockevent_init(TX4927_TMR_REG(tmrnr) & 0xfffffffffULL,
+				     TXX9_IRQ_BASE + TX4927_IR_TMR(tmrnr),
+				     TXX9_IMCLK);
+}
+
+void __init tx4927_setup_serial(void)
+{
+#ifdef CONFIG_SERIAL_TXX9
+	int i;
+	struct uart_port req;
+
+	for (i = 0; i < 2; i++) {
+		memset(&req, 0, sizeof(req));
+		req.line = i;
+		req.iotype = UPIO_MEM;
+		req.membase = (unsigned char __iomem *)TX4927_SIO_REG(i);
+		req.mapbase = TX4927_SIO_REG(i) & 0xfffffffffULL;
+		req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i);
+		req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
+		req.uartclk = TXX9_IMCLK;
+		early_serial_txx9_setup(&req);
+	}
+#endif /* CONFIG_SERIAL_TXX9 */
+}
diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c
new file mode 100644
index 0000000..317378d
--- /dev/null
+++ b/arch/mips/txx9/generic/setup_tx4938.c
@@ -0,0 +1,259 @@
+/*
+ * TX4938/4937 setup routines
+ * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
+ *	    and RBTX49xx patch from CELF patch archive.
+ *
+ * 2003-2005 (c) MontaVista Software, Inc.
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+#include <linux/param.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9tmr.h>
+#include <asm/txx9pio.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/tx4938.h>
+
+void __init tx4938_wdr_init(void)
+{
+	/* clear WatchDogReset (W1C) */
+	tx4938_ccfg_set(TX4938_CCFG_WDRST);
+	/* do reset on watchdog */
+	tx4938_ccfg_set(TX4938_CCFG_WR);
+}
+
+static struct resource tx4938_sdram_resource[4];
+static struct resource tx4938_sram_resource;
+
+#define TX4938_SRAM_SIZE 0x800
+
+void __init tx4938_setup(void)
+{
+	int i;
+	__u32 divmode;
+	int cpuclk = 0;
+	u64 ccfg;
+
+	txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE,
+			  TX4938_REG_SIZE);
+
+	/* SDRAMC,EBUSC are configured by PROM */
+	for (i = 0; i < 8; i++) {
+		if (!(TX4938_EBUSC_CR(i) & 0x8))
+			continue;	/* disabled */
+		txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i);
+		txx9_ce_res[i].end =
+			txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1;
+		request_resource(&iomem_resource, &txx9_ce_res[i]);
+	}
+
+	/* clocks */
+	ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg);
+	if (txx9_master_clock) {
+		/* calculate gbus_clock and cpu_clock from master_clock */
+		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
+		switch (divmode) {
+		case TX4938_CCFG_DIVMODE_8:
+		case TX4938_CCFG_DIVMODE_10:
+		case TX4938_CCFG_DIVMODE_12:
+		case TX4938_CCFG_DIVMODE_16:
+		case TX4938_CCFG_DIVMODE_18:
+			txx9_gbus_clock = txx9_master_clock * 4; break;
+		default:
+			txx9_gbus_clock = txx9_master_clock;
+		}
+		switch (divmode) {
+		case TX4938_CCFG_DIVMODE_2:
+		case TX4938_CCFG_DIVMODE_8:
+			cpuclk = txx9_gbus_clock * 2; break;
+		case TX4938_CCFG_DIVMODE_2_5:
+		case TX4938_CCFG_DIVMODE_10:
+			cpuclk = txx9_gbus_clock * 5 / 2; break;
+		case TX4938_CCFG_DIVMODE_3:
+		case TX4938_CCFG_DIVMODE_12:
+			cpuclk = txx9_gbus_clock * 3; break;
+		case TX4938_CCFG_DIVMODE_4:
+		case TX4938_CCFG_DIVMODE_16:
+			cpuclk = txx9_gbus_clock * 4; break;
+		case TX4938_CCFG_DIVMODE_4_5:
+		case TX4938_CCFG_DIVMODE_18:
+			cpuclk = txx9_gbus_clock * 9 / 2; break;
+		}
+		txx9_cpu_clock = cpuclk;
+	} else {
+		if (txx9_cpu_clock == 0)
+			txx9_cpu_clock = 300000000;	/* 300MHz */
+		/* calculate gbus_clock and master_clock from cpu_clock */
+		cpuclk = txx9_cpu_clock;
+		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
+		switch (divmode) {
+		case TX4938_CCFG_DIVMODE_2:
+		case TX4938_CCFG_DIVMODE_8:
+			txx9_gbus_clock = cpuclk / 2; break;
+		case TX4938_CCFG_DIVMODE_2_5:
+		case TX4938_CCFG_DIVMODE_10:
+			txx9_gbus_clock = cpuclk * 2 / 5; break;
+		case TX4938_CCFG_DIVMODE_3:
+		case TX4938_CCFG_DIVMODE_12:
+			txx9_gbus_clock = cpuclk / 3; break;
+		case TX4938_CCFG_DIVMODE_4:
+		case TX4938_CCFG_DIVMODE_16:
+			txx9_gbus_clock = cpuclk / 4; break;
+		case TX4938_CCFG_DIVMODE_4_5:
+		case TX4938_CCFG_DIVMODE_18:
+			txx9_gbus_clock = cpuclk * 2 / 9; break;
+		}
+		switch (divmode) {
+		case TX4938_CCFG_DIVMODE_8:
+		case TX4938_CCFG_DIVMODE_10:
+		case TX4938_CCFG_DIVMODE_12:
+		case TX4938_CCFG_DIVMODE_16:
+		case TX4938_CCFG_DIVMODE_18:
+			txx9_master_clock = txx9_gbus_clock / 4; break;
+		default:
+			txx9_master_clock = txx9_gbus_clock;
+		}
+	}
+	/* change default value to udelay/mdelay take reasonable time */
+	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
+
+	/* CCFG */
+	tx4938_wdr_init();
+	/* clear BusErrorOnWrite flag (W1C) */
+	tx4938_ccfg_set(TX4938_CCFG_BEOW);
+	/* enable Timeout BusError */
+	if (txx9_ccfg_toeon)
+		tx4938_ccfg_set(TX4938_CCFG_TOE);
+
+	/* DMA selection */
+	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL);
+
+	/* Use external clock for external arbiter */
+	if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB))
+		txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL);
+
+	printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
+	       txx9_pcode_str,
+	       (cpuclk + 500000) / 1000000,
+	       (txx9_master_clock + 500000) / 1000000,
+	       (__u32)____raw_readq(&tx4938_ccfgptr->crir),
+	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
+	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg));
+
+	printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str);
+	for (i = 0; i < 4; i++) {
+		__u64 cr = TX4938_SDRAMC_CR(i);
+		unsigned long base, size;
+		if (!((__u32)cr & 0x00000400))
+			continue;	/* disabled */
+		base = (unsigned long)(cr >> 49) << 21;
+		size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
+		printk(" CR%d:%016llx", i, (unsigned long long)cr);
+		tx4938_sdram_resource[i].name = "SDRAM";
+		tx4938_sdram_resource[i].start = base;
+		tx4938_sdram_resource[i].end = base + size - 1;
+		tx4938_sdram_resource[i].flags = IORESOURCE_MEM;
+		request_resource(&iomem_resource, &tx4938_sdram_resource[i]);
+	}
+	printk(" TR:%09llx\n",
+	       (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr));
+
+	/* SRAM */
+	if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) {
+		unsigned int size = TX4938_SRAM_SIZE;
+		tx4938_sram_resource.name = "SRAM";
+		tx4938_sram_resource.start =
+			(____raw_readq(&tx4938_sramcptr->cr) >> (39-11))
+			& ~(size - 1);
+		tx4938_sram_resource.end =
+			tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1;
+		tx4938_sram_resource.flags = IORESOURCE_MEM;
+		request_resource(&iomem_resource, &tx4938_sram_resource);
+	}
+
+	/* TMR */
+	/* disable all timers */
+	for (i = 0; i < TX4938_NR_TMR; i++)
+		txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL);
+
+	/* DMA */
+	for (i = 0; i < 2; i++)
+		____raw_writeq(TX4938_DMA_MCR_MSTEN,
+			       (void __iomem *)(TX4938_DMA_REG(i) + 0x50));
+
+	/* PIO */
+	txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO);
+	__raw_writel(0, &tx4938_pioptr->maskcpu);
+	__raw_writel(0, &tx4938_pioptr->maskext);
+
+	if (txx9_pcode == 0x4938) {
+		__u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg);
+		/* set PCIC1 reset */
+		txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST);
+		if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) {
+			mdelay(1);	/* at least 128 cpu clock */
+			/* clear PCIC1 reset */
+			txx9_clear64(&tx4938_ccfgptr->clkctr,
+				     TX4938_CLKCTR_PCIC1RST);
+		} else {
+			printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str);
+			/* stop PCIC1 */
+			txx9_set64(&tx4938_ccfgptr->clkctr,
+				   TX4938_CLKCTR_PCIC1CKD);
+		}
+		if (!(pcfg & TX4938_PCFG_ETH0_SEL)) {
+			printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str);
+			txx9_set64(&tx4938_ccfgptr->clkctr,
+				   TX4938_CLKCTR_ETH0RST);
+			txx9_set64(&tx4938_ccfgptr->clkctr,
+				   TX4938_CLKCTR_ETH0CKD);
+		}
+		if (!(pcfg & TX4938_PCFG_ETH1_SEL)) {
+			printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str);
+			txx9_set64(&tx4938_ccfgptr->clkctr,
+				   TX4938_CLKCTR_ETH1RST);
+			txx9_set64(&tx4938_ccfgptr->clkctr,
+				   TX4938_CLKCTR_ETH1CKD);
+		}
+	}
+}
+
+void __init tx4938_time_init(unsigned int tmrnr)
+{
+	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS)
+		txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL,
+				     TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr),
+				     TXX9_IMCLK);
+}
+
+void __init tx4938_setup_serial(void)
+{
+#ifdef CONFIG_SERIAL_TXX9
+	int i;
+	struct uart_port req;
+	unsigned int ch_mask = 0;
+
+	if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL)
+		ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */
+	for (i = 0; i < 2; i++) {
+		if ((1 << i) & ch_mask)
+			continue;
+		memset(&req, 0, sizeof(req));
+		req.line = i;
+		req.iotype = UPIO_MEM;
+		req.membase = (unsigned char __iomem *)TX4938_SIO_REG(i);
+		req.mapbase = TX4938_SIO_REG(i) & 0xfffffffffULL;
+		req.irq = TXX9_IRQ_BASE + TX4938_IR_SIO(i);
+		req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
+		req.uartclk = TXX9_IMCLK;
+		early_serial_txx9_setup(&req);
+	}
+#endif /* CONFIG_SERIAL_TXX9 */
+}
diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c
index 5e35ef7..03647eb 100644
--- a/arch/mips/txx9/jmr3927/setup.c
+++ b/arch/mips/txx9/jmr3927/setup.c
@@ -105,14 +105,6 @@
 	_machine_halt = jmr3927_machine_halt;
 	pm_power_off = jmr3927_machine_power_off;
 
-	/*
-	 * IO/MEM resources.
-	 */
-	ioport_resource.start = 0;
-	ioport_resource.end = 0xffffffff;
-	iomem_resource.start = 0;
-	iomem_resource.end = 0xffffffff;
-
 	/* Reboot on panic */
 	panic_timeout = 180;
 
diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c
index 70f1321..cd748a9 100644
--- a/arch/mips/txx9/rbtx4927/irq.c
+++ b/arch/mips/txx9/rbtx4927/irq.c
@@ -126,14 +126,12 @@
 	.mask_ack = toshiba_rbtx4927_irq_ioc_disable,
 	.unmask = toshiba_rbtx4927_irq_ioc_enable,
 };
-#define TOSHIBA_RBTX4927_IOC_INTR_ENAB (void __iomem *)0xbc002000UL
-#define TOSHIBA_RBTX4927_IOC_INTR_STAT (void __iomem *)0xbc002006UL
 
 static int toshiba_rbtx4927_irq_nested(int sw_irq)
 {
 	u8 level3;
 
-	level3 = readb(TOSHIBA_RBTX4927_IOC_INTR_STAT) & 0x1f;
+	level3 = readb(rbtx4927_imstat_addr) & 0x1f;
 	if (level3)
 		sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1;
 	return (sw_irq);
@@ -154,18 +152,18 @@
 {
 	unsigned char v;
 
-	v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB);
+	v = readb(rbtx4927_imask_addr);
 	v |= (1 << (irq - RBTX4927_IRQ_IOC));
-	writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB);
+	writeb(v, rbtx4927_imask_addr);
 }
 
 static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq)
 {
 	unsigned char v;
 
-	v = readb(TOSHIBA_RBTX4927_IOC_INTR_ENAB);
+	v = readb(rbtx4927_imask_addr);
 	v &= ~(1 << (irq - RBTX4927_IRQ_IOC));
-	writeb(v, TOSHIBA_RBTX4927_IOC_INTR_ENAB);
+	writeb(v, rbtx4927_imask_addr);
 	mmiowb();
 }
 
diff --git a/arch/mips/txx9/rbtx4927/prom.c b/arch/mips/txx9/rbtx4927/prom.c
index 942e627..5c0de54 100644
--- a/arch/mips/txx9/rbtx4927/prom.c
+++ b/arch/mips/txx9/rbtx4927/prom.c
@@ -36,10 +36,6 @@
 
 void __init rbtx4927_prom_init(void)
 {
-	extern int tx4927_get_mem_size(void);
-	int msize;
-
 	prom_init_cmdline();
-	msize = tx4927_get_mem_size();
-	add_memory_region(0, msize << 20, BOOT_MEM_RAM);
+	add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM);
 }
diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c
index 1657fd9..3da20ea 100644
--- a/arch/mips/txx9/rbtx4927/setup.c
+++ b/arch/mips/txx9/rbtx4927/setup.c
@@ -53,17 +53,10 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/reboot.h>
-#include <asm/time.h>
-#include <asm/txx9tmr.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/pci.h>
 #include <asm/txx9/rbtx4927.h>
 #include <asm/txx9/tx4938.h>	/* for TX4937 */
-#ifdef CONFIG_SERIAL_TXX9
-#include <linux/serial_core.h>
-#endif
-
-static int tx4927_ccfg_toeon = 1;
 
 #ifdef CONFIG_PCI
 static void __init tx4927_pci_setup(void)
@@ -184,14 +177,14 @@
 	printk(KERN_NOTICE "System Rebooting...\n");
 
 	/* enable the s/w reset register */
-	writeb(RBTX4927_SW_RESET_ENABLE_SET, RBTX4927_SW_RESET_ENABLE);
+	writeb(1, rbtx4927_softresetlock_addr);
 
 	/* wait for enable to be seen */
-	while ((readb(RBTX4927_SW_RESET_ENABLE) &
-		RBTX4927_SW_RESET_ENABLE_SET) == 0x00);
+	while (!(readb(rbtx4927_softresetlock_addr) & 1))
+		;
 
 	/* do a s/w reset */
-	writeb(RBTX4927_SW_RESET_DO_SET, RBTX4927_SW_RESET_DO);
+	writeb(1, rbtx4927_softreset_addr);
 
 	/* do something passive while waiting for reset */
 	local_irq_disable();
@@ -213,9 +206,11 @@
 	/* no return */
 }
 
+static void __init rbtx4927_clock_init(void);
+static void __init rbtx4937_clock_init(void);
+
 static void __init rbtx4927_mem_setup(void)
 {
-	int i;
 	u32 cp0_config;
 	char *argptr;
 
@@ -227,16 +222,18 @@
 	cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC);
 	write_c0_config(cp0_config);
 
-	ioport_resource.end = 0xffffffff;
-	iomem_resource.end = 0xffffffff;
+	if (TX4927_REV_PCODE() == 0x4927) {
+		rbtx4927_clock_init();
+		tx4927_setup();
+	} else {
+		rbtx4937_clock_init();
+		tx4938_setup();
+	}
 
 	_machine_restart = toshiba_rbtx4927_restart;
 	_machine_halt = toshiba_rbtx4927_halt;
 	pm_power_off = toshiba_rbtx4927_power_off;
 
-	for (i = 0; i < TX4927_NR_TMR; i++)
-		txx9_tmr_init(TX4927_TMR_REG(0) & 0xfffffffffULL);
-
 #ifdef CONFIG_PCI
 	txx9_alloc_pci_controller(&txx9_primary_pcic,
 				  RBTX4927_PCIMEM, RBTX4927_PCIMEM_SIZE,
@@ -245,36 +242,13 @@
 	set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET);
 #endif
 
-	/* CCFG */
-	/* do reset on watchdog */
-	tx4927_ccfg_set(TX4927_CCFG_WR);
-	/* enable Timeout BusError */
-	if (tx4927_ccfg_toeon)
-		tx4927_ccfg_set(TX4927_CCFG_TOE);
-
-#ifdef CONFIG_SERIAL_TXX9
-	{
-		extern int early_serial_txx9_setup(struct uart_port *port);
-		struct uart_port req;
-		for(i = 0; i < 2; i++) {
-			memset(&req, 0, sizeof(req));
-			req.line = i;
-			req.iotype = UPIO_MEM;
-			req.membase = (char *)(0xff1ff300 + i * 0x100);
-			req.mapbase = 0xff1ff300 + i * 0x100;
-			req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i);
-			req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
-			req.uartclk = 50000000;
-			early_serial_txx9_setup(&req);
-		}
-	}
+	tx4927_setup_serial();
 #ifdef CONFIG_SERIAL_TXX9_CONSOLE
         argptr = prom_getcmdline();
         if (strstr(argptr, "console=") == NULL) {
                 strcat(argptr, " console=ttyS0,38400");
         }
 #endif
-#endif
 
 #ifdef CONFIG_ROOT_NFS
         argptr = prom_getcmdline();
@@ -291,19 +265,7 @@
 #endif
 }
 
-static void __init rbtx49x7_common_time_init(void)
-{
-	/* change default value to udelay/mdelay take reasonable time */
-	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
-
-	mips_hpt_frequency = txx9_cpu_clock / 2;
-	if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_TINTDIS)
-		txx9_clockevent_init(TX4927_TMR_REG(0) & 0xfffffffffULL,
-				     TXX9_IRQ_BASE + 17,
-				     50000000);
-}
-
-static void __init rbtx4927_time_init(void)
+static void __init rbtx4927_clock_init(void)
 {
 	/*
 	 * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz.
@@ -325,11 +287,9 @@
 	default:
 		txx9_cpu_clock = 200000000;	/* 200MHz */
 	}
-
-	rbtx49x7_common_time_init();
 }
 
-static void __init rbtx4937_time_init(void)
+static void __init rbtx4937_clock_init(void)
 {
 	/*
 	 * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz.
@@ -357,15 +317,18 @@
 	default:
 		txx9_cpu_clock = 333333333;	/* 333MHz */
 	}
+}
 
-	rbtx49x7_common_time_init();
+static void __init rbtx4927_time_init(void)
+{
+	tx4927_time_init(0);
 }
 
 static int __init toshiba_rbtx4927_rtc_init(void)
 {
-	static struct resource __initdata res = {
-		.start	= 0x1c010000,
-		.end	= 0x1c010000 + 0x800 - 1,
+	struct resource res = {
+		.start	= RBTX4927_BRAMRTC_BASE - IO_BASE,
+		.end	= RBTX4927_BRAMRTC_BASE - IO_BASE + 0x800 - 1,
 		.flags	= IORESOURCE_MEM,
 	};
 	struct platform_device *dev =
@@ -375,7 +338,7 @@
 
 static int __init rbtx4927_ne_init(void)
 {
-	static struct resource __initdata res[] = {
+	struct resource res[] = {
 		{
 			.start	= RBTX4927_RTL_8019_BASE,
 			.end	= RBTX4927_RTL_8019_BASE + 0x20 - 1,
@@ -434,7 +397,7 @@
 	.prom_init = rbtx4927_prom_init,
 	.mem_setup = rbtx4927_mem_setup,
 	.irq_setup = rbtx4927_irq_setup,
-	.time_init = rbtx4937_time_init,
+	.time_init = rbtx4927_time_init,
 	.device_init = rbtx4927_device_init,
 	.arch_init = rbtx4937_arch_init,
 #ifdef CONFIG_PCI
diff --git a/arch/mips/txx9/rbtx4938/prom.c b/arch/mips/txx9/rbtx4938/prom.c
index fbb3745..ee18951 100644
--- a/arch/mips/txx9/rbtx4938/prom.c
+++ b/arch/mips/txx9/rbtx4938/prom.c
@@ -18,12 +18,8 @@
 
 void __init rbtx4938_prom_init(void)
 {
-	extern int tx4938_get_mem_size(void);
-	int msize;
 #ifndef CONFIG_TX4938_NAND_BOOT
 	prom_init_cmdline();
 #endif
-
-	msize = tx4938_get_mem_size();
-	add_memory_region(0, msize << 20, BOOT_MEM_RAM);
+	add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM);
 }
diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c
index aaa987a..6c2b99b 100644
--- a/arch/mips/txx9/rbtx4938/setup.c
+++ b/arch/mips/txx9/rbtx4938/setup.c
@@ -20,21 +20,14 @@
 #include <linux/gpio.h>
 
 #include <asm/reboot.h>
-#include <asm/time.h>
-#include <asm/txx9tmr.h>
 #include <asm/io.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/pci.h>
 #include <asm/txx9/rbtx4938.h>
-#ifdef CONFIG_SERIAL_TXX9
-#include <linux/serial_core.h>
-#endif
 #include <linux/spi/spi.h>
 #include <asm/txx9/spi.h>
 #include <asm/txx9pio.h>
 
-static int tx4938_ccfg_toeon = 1;
-
 static void rbtx4938_machine_halt(void)
 {
         printk(KERN_NOTICE "System Halted\n");
@@ -182,188 +175,10 @@
 }
 
 static struct resource rbtx4938_fpga_resource;
-static struct resource tx4938_sdram_resource[4];
-static struct resource tx4938_sram_resource;
-
-void __init tx4938_board_setup(void)
-{
-	int i;
-	unsigned long divmode;
-	int cpuclk = 0;
-	unsigned long pcode = TX4938_REV_PCODE();
-
-	ioport_resource.start = 0;
-	ioport_resource.end = 0xffffffff;
-	iomem_resource.start = 0;
-	iomem_resource.end = 0xffffffff;	/* expand to 4GB */
-
-	txx9_reg_res_init(pcode, TX4938_REG_BASE,
-			  TX4938_REG_SIZE);
-	/* SDRAMC,EBUSC are configured by PROM */
-	for (i = 0; i < 8; i++) {
-		if (!(TX4938_EBUSC_CR(i) & 0x8))
-			continue;	/* disabled */
-		txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i);
-		txx9_ce_res[i].end =
-			txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1;
-		request_resource(&iomem_resource, &txx9_ce_res[i]);
-	}
-
-	/* clocks */
-	if (txx9_master_clock) {
-		u64 ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg);
-		/* calculate gbus_clock and cpu_clock_freq from master_clock */
-		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
-		switch (divmode) {
-		case TX4938_CCFG_DIVMODE_8:
-		case TX4938_CCFG_DIVMODE_10:
-		case TX4938_CCFG_DIVMODE_12:
-		case TX4938_CCFG_DIVMODE_16:
-		case TX4938_CCFG_DIVMODE_18:
-			txx9_gbus_clock = txx9_master_clock * 4; break;
-		default:
-			txx9_gbus_clock = txx9_master_clock;
-		}
-		switch (divmode) {
-		case TX4938_CCFG_DIVMODE_2:
-		case TX4938_CCFG_DIVMODE_8:
-			cpuclk = txx9_gbus_clock * 2; break;
-		case TX4938_CCFG_DIVMODE_2_5:
-		case TX4938_CCFG_DIVMODE_10:
-			cpuclk = txx9_gbus_clock * 5 / 2; break;
-		case TX4938_CCFG_DIVMODE_3:
-		case TX4938_CCFG_DIVMODE_12:
-			cpuclk = txx9_gbus_clock * 3; break;
-		case TX4938_CCFG_DIVMODE_4:
-		case TX4938_CCFG_DIVMODE_16:
-			cpuclk = txx9_gbus_clock * 4; break;
-		case TX4938_CCFG_DIVMODE_4_5:
-		case TX4938_CCFG_DIVMODE_18:
-			cpuclk = txx9_gbus_clock * 9 / 2; break;
-		}
-		txx9_cpu_clock = cpuclk;
-	} else {
-		u64 ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg);
-		if (txx9_cpu_clock == 0) {
-			txx9_cpu_clock = 300000000;	/* 300MHz */
-		}
-		/* calculate gbus_clock and master_clock from cpu_clock_freq */
-		cpuclk = txx9_cpu_clock;
-		divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK;
-		switch (divmode) {
-		case TX4938_CCFG_DIVMODE_2:
-		case TX4938_CCFG_DIVMODE_8:
-			txx9_gbus_clock = cpuclk / 2; break;
-		case TX4938_CCFG_DIVMODE_2_5:
-		case TX4938_CCFG_DIVMODE_10:
-			txx9_gbus_clock = cpuclk * 2 / 5; break;
-		case TX4938_CCFG_DIVMODE_3:
-		case TX4938_CCFG_DIVMODE_12:
-			txx9_gbus_clock = cpuclk / 3; break;
-		case TX4938_CCFG_DIVMODE_4:
-		case TX4938_CCFG_DIVMODE_16:
-			txx9_gbus_clock = cpuclk / 4; break;
-		case TX4938_CCFG_DIVMODE_4_5:
-		case TX4938_CCFG_DIVMODE_18:
-			txx9_gbus_clock = cpuclk * 2 / 9; break;
-		}
-		switch (divmode) {
-		case TX4938_CCFG_DIVMODE_8:
-		case TX4938_CCFG_DIVMODE_10:
-		case TX4938_CCFG_DIVMODE_12:
-		case TX4938_CCFG_DIVMODE_16:
-		case TX4938_CCFG_DIVMODE_18:
-			txx9_master_clock = txx9_gbus_clock / 4; break;
-		default:
-			txx9_master_clock = txx9_gbus_clock;
-		}
-	}
-	/* change default value to udelay/mdelay take reasonable time */
-	loops_per_jiffy = txx9_cpu_clock / HZ / 2;
-
-	/* CCFG */
-	/* clear WatchDogReset,BusErrorOnWrite flag (W1C) */
-	tx4938_ccfg_set(TX4938_CCFG_WDRST | TX4938_CCFG_BEOW);
-	/* do reset on watchdog */
-	tx4938_ccfg_set(TX4938_CCFG_WR);
-	/* clear PCIC1 reset */
-	txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST);
-
-	/* enable Timeout BusError */
-	if (tx4938_ccfg_toeon)
-		tx4938_ccfg_set(TX4938_CCFG_TOE);
-
-	/* DMA selection */
-	txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL);
-
-	/* Use external clock for external arbiter */
-	if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB))
-		txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL);
-
-	printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
-	       txx9_pcode_str,
-	       (cpuclk + 500000) / 1000000,
-	       (txx9_master_clock + 500000) / 1000000,
-	       (__u32)____raw_readq(&tx4938_ccfgptr->crir),
-	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
-	       (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg));
-
-	printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str);
-	for (i = 0; i < 4; i++) {
-		unsigned long long cr = tx4938_sdramcptr->cr[i];
-		unsigned long ram_base, ram_size;
-		if (!((unsigned long)cr & 0x00000400))
-			continue;	/* disabled */
-		ram_base = (unsigned long)(cr >> 49) << 21;
-		ram_size = ((unsigned long)(cr >> 33) + 1) << 21;
-		if (ram_base >= 0x20000000)
-			continue;	/* high memory (ignore) */
-		printk(" CR%d:%016Lx", i, cr);
-		tx4938_sdram_resource[i].name = "SDRAM";
-		tx4938_sdram_resource[i].start = ram_base;
-		tx4938_sdram_resource[i].end = ram_base + ram_size - 1;
-		tx4938_sdram_resource[i].flags = IORESOURCE_MEM;
-		request_resource(&iomem_resource, &tx4938_sdram_resource[i]);
-	}
-	printk(" TR:%09Lx\n", tx4938_sdramcptr->tr);
-
-	/* SRAM */
-	if (tx4938_sramcptr->cr & 1) {
-		unsigned int size = 0x800;
-		unsigned long base =
-			(tx4938_sramcptr->cr >> (39-11)) & ~(size - 1);
-		tx4938_sram_resource.name = "SRAM";
-		tx4938_sram_resource.start = base;
-		tx4938_sram_resource.end = base + size - 1;
-		tx4938_sram_resource.flags = IORESOURCE_MEM;
-		request_resource(&iomem_resource, &tx4938_sram_resource);
-	}
-
-	/* TMR */
-	for (i = 0; i < TX4938_NR_TMR; i++)
-		txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL);
-
-	/* enable DMA */
-	for (i = 0; i < 2; i++)
-		____raw_writeq(TX4938_DMA_MCR_MSTEN,
-			       (void __iomem *)(TX4938_DMA_REG(i) + 0x50));
-
-	/* PIO */
-	__raw_writel(0, &tx4938_pioptr->maskcpu);
-	__raw_writel(0, &tx4938_pioptr->maskext);
-
-#ifdef CONFIG_PCI
-	txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0);
-#endif
-}
 
 static void __init rbtx4938_time_init(void)
 {
-	mips_hpt_frequency = txx9_cpu_clock / 2;
-	if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS)
-		txx9_clockevent_init(TX4938_TMR_REG(0) & 0xfffffffffULL,
-				     TXX9_IRQ_BASE + TX4938_IR_TMR(0),
-				     txx9_gbus_clock / 2);
+	tx4938_time_init(0);
 }
 
 static void __init rbtx4938_mem_setup(void)
@@ -371,39 +186,24 @@
 	unsigned long long pcfg;
 	char *argptr;
 
-	iomem_resource.end = 0xffffffff;	/* 4GB */
-
 	if (txx9_master_clock == 0)
 		txx9_master_clock = 25000000; /* 25MHz */
-	tx4938_board_setup();
-#ifndef CONFIG_PCI
+
+	tx4938_setup();
+
+#ifdef CONFIG_PCI
+	txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0);
+#else
 	set_io_port_base(RBTX4938_ETHER_BASE);
 #endif
 
-#ifdef CONFIG_SERIAL_TXX9
-	{
-		extern int early_serial_txx9_setup(struct uart_port *port);
-		int i;
-		struct uart_port req;
-		for(i = 0; i < 2; i++) {
-			memset(&req, 0, sizeof(req));
-			req.line = i;
-			req.iotype = UPIO_MEM;
-			req.membase = (char *)(0xff1ff300 + i * 0x100);
-			req.mapbase = 0xff1ff300 + i * 0x100;
-			req.irq = RBTX4938_IRQ_IRC_SIO(i);
-			req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
-			req.uartclk = 50000000;
-			early_serial_txx9_setup(&req);
-		}
-	}
+	tx4938_setup_serial();
 #ifdef CONFIG_SERIAL_TXX9_CONSOLE
         argptr = prom_getcmdline();
         if (strstr(argptr, "console=") == NULL) {
                 strcat(argptr, " console=ttyS0,38400");
         }
 #endif
-#endif
 
 #ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61
 	printk("PIOSEL: disabling both ata and nand selection\n");
@@ -457,7 +257,7 @@
 	rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR);
 	rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff;
 	rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-	if (request_resource(&iomem_resource, &rbtx4938_fpga_resource))
+	if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource))
 		printk("request resource for fpga failed\n");
 
 	_machine_restart = rbtx4938_machine_restart;
@@ -488,18 +288,6 @@
 	return IS_ERR(dev) ? PTR_ERR(dev) : 0;
 }
 
-/* GPIO support */
-
-int gpio_to_irq(unsigned gpio)
-{
-	return -EINVAL;
-}
-
-int irq_to_gpio(unsigned irq)
-{
-	return -EINVAL;
-}
-
 static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock);
 
 static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset,
@@ -579,7 +367,6 @@
 
 static void __init rbtx4938_arch_init(void)
 {
-	txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, 16);
 	gpiochip_add(&rbtx4938_spi_gpio_chip);
 	rbtx4938_pci_setup();
 	rbtx4938_spi_init();
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index b9c268c..8b054e7 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -392,7 +392,7 @@
 static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
 {
 	struct uart_icount *icount = &port->uart.icount;
-	struct tty_struct *tty = port->uart.info->tty;
+	struct tty_struct *tty = port->uart.info->port.tty;
 	unsigned ix;
 	int count;
 	u8 st, ch, push, status, overrun;
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index d0d358d..04e3449 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -4,7 +4,7 @@
 
 EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
 
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
 
 kvm-objs := $(common-objs) powerpc.o emulate.o booke_guest.o
 obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 777e0f3..53826a5 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -145,6 +145,9 @@
 	case KVM_CAP_USER_MEMORY:
 		r = 1;
 		break;
+	case KVM_CAP_COALESCED_MMIO:
+		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
+		break;
 	default:
 		r = 0;
 		break;
@@ -167,6 +170,10 @@
 	return 0;
 }
 
+void kvm_arch_flush_shadow(struct kvm *kvm)
+{
+}
+
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
 	struct kvm_vcpu *vcpu;
@@ -240,10 +247,6 @@
 {
 }
 
-void decache_vcpus_on_cpu(int cpu)
-{
-}
-
 int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
                                     struct kvm_debug_guest *dbg)
 {
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 84a7fed..11230b0 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -31,7 +31,7 @@
 }
 
 static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
-				      struct interrupt_info *inti)
+				      struct kvm_s390_interrupt_info *inti)
 {
 	switch (inti->type) {
 	case KVM_S390_INT_EMERGENCY:
@@ -91,7 +91,7 @@
 }
 
 static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
-				      struct interrupt_info *inti)
+				      struct kvm_s390_interrupt_info *inti)
 {
 	switch (inti->type) {
 	case KVM_S390_INT_EMERGENCY:
@@ -111,7 +111,7 @@
 }
 
 static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
-				   struct interrupt_info *inti)
+				   struct kvm_s390_interrupt_info *inti)
 {
 	const unsigned short table[] = { 2, 4, 4, 6 };
 	int rc, exception = 0;
@@ -290,9 +290,9 @@
 
 int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
 {
-	struct local_interrupt *li = &vcpu->arch.local_int;
-	struct float_interrupt *fi = vcpu->arch.local_int.float_int;
-	struct interrupt_info  *inti;
+	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+	struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
+	struct kvm_s390_interrupt_info  *inti;
 	int rc = 0;
 
 	if (atomic_read(&li->active)) {
@@ -408,9 +408,9 @@
 
 void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 {
-	struct local_interrupt *li = &vcpu->arch.local_int;
-	struct float_interrupt *fi = vcpu->arch.local_int.float_int;
-	struct interrupt_info  *n, *inti = NULL;
+	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+	struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
+	struct kvm_s390_interrupt_info  *n, *inti = NULL;
 	int deliver;
 
 	__reset_intercept_indicators(vcpu);
@@ -465,8 +465,8 @@
 
 int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
 {
-	struct local_interrupt *li = &vcpu->arch.local_int;
-	struct interrupt_info *inti;
+	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+	struct kvm_s390_interrupt_info *inti;
 
 	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
 	if (!inti)
@@ -487,9 +487,9 @@
 int kvm_s390_inject_vm(struct kvm *kvm,
 		       struct kvm_s390_interrupt *s390int)
 {
-	struct local_interrupt *li;
-	struct float_interrupt *fi;
-	struct interrupt_info *inti;
+	struct kvm_s390_local_interrupt *li;
+	struct kvm_s390_float_interrupt *fi;
+	struct kvm_s390_interrupt_info *inti;
 	int sigcpu;
 
 	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -544,8 +544,8 @@
 int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 			 struct kvm_s390_interrupt *s390int)
 {
-	struct local_interrupt *li;
-	struct interrupt_info *inti;
+	struct kvm_s390_local_interrupt *li;
+	struct kvm_s390_interrupt_info *inti;
 
 	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
 	if (!inti)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 6558b09..1782cbc 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -79,10 +79,6 @@
 {
 }
 
-void decache_vcpus_on_cpu(int cpu)
-{
-}
-
 int kvm_arch_hardware_setup(void)
 {
 	return 0;
@@ -198,6 +194,7 @@
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
 	debug_unregister(kvm->arch.dbf);
+	kvm_free_physmem(kvm);
 	free_page((unsigned long)(kvm->arch.sca));
 	kfree(kvm);
 	module_put(THIS_MODULE);
@@ -250,11 +247,16 @@
 	vcpu->arch.sie_block->gbea = 1;
 }
 
+/* The current code can have up to 256 pages for virtio */
+#define VIRTIODESCSPACE (256ul * 4096ul)
+
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
 	atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
-	vcpu->arch.sie_block->gmslm = 0xffffffffffUL;
-	vcpu->arch.sie_block->gmsor = 0x000000000000;
+	vcpu->arch.sie_block->gmslm = vcpu->kvm->arch.guest_memsize +
+				      vcpu->kvm->arch.guest_origin +
+				      VIRTIODESCSPACE - 1ul;
+	vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
 	vcpu->arch.sie_block->ecb   = 2;
 	vcpu->arch.sie_block->eca   = 0xC1002001U;
 	setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,
@@ -273,7 +275,8 @@
 	if (!vcpu)
 		goto out_nomem;
 
-	vcpu->arch.sie_block = (struct sie_block *) get_zeroed_page(GFP_KERNEL);
+	vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
+					get_zeroed_page(GFP_KERNEL);
 
 	if (!vcpu->arch.sie_block)
 		goto out_free_cpu;
@@ -672,6 +675,10 @@
 	return 0;
 }
 
+void kvm_arch_flush_shadow(struct kvm *kvm)
+{
+}
+
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
 {
 	return gfn;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index c02286c..2e2d2ff 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -199,7 +199,7 @@
 
 static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
 {
-	struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	int cpus = 0;
 	int n;
 
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 0a236ac..5a55611 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -45,7 +45,7 @@
 
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg)
 {
-	struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	int rc;
 
 	if (cpu_addr >= KVM_MAX_VCPUS)
@@ -71,9 +71,9 @@
 
 static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
 {
-	struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
-	struct local_interrupt *li;
-	struct interrupt_info *inti;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_local_interrupt *li;
+	struct kvm_s390_interrupt_info *inti;
 	int rc;
 
 	if (cpu_addr >= KVM_MAX_VCPUS)
@@ -108,9 +108,9 @@
 
 static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store)
 {
-	struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
-	struct local_interrupt *li;
-	struct interrupt_info *inti;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_local_interrupt *li;
+	struct kvm_s390_interrupt_info *inti;
 	int rc;
 
 	if (cpu_addr >= KVM_MAX_VCPUS)
@@ -169,9 +169,9 @@
 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 			     u64 *reg)
 {
-	struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
-	struct local_interrupt *li;
-	struct interrupt_info *inti;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_local_interrupt *li;
+	struct kvm_s390_interrupt_info *inti;
 	int rc;
 	u8 tmp;
 
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 87edf1c..d02def0 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -113,7 +113,7 @@
 #endif
 
 #ifdef CONFIG_SMP
-void __init kvm_smp_prepare_boot_cpu(void)
+static void __init kvm_smp_prepare_boot_cpu(void)
 {
 	WARN_ON(kvm_register_clock("primary cpu clock"));
 	native_smp_prepare_boot_cpu();
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index c97d35c..d0e940b 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -2,7 +2,8 @@
 # Makefile for Kernel-based Virtual Machine module
 #
 
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
+                coalesced_mmio.o)
 ifeq ($(CONFIG_KVM_TRACE),y)
 common-objs += $(addprefix ../../../virt/kvm/, kvm_trace.o)
 endif
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 3829aa7..c0f7872 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -91,7 +91,7 @@
 	c->gate = val;
 }
 
-int pit_get_gate(struct kvm *kvm, int channel)
+static int pit_get_gate(struct kvm *kvm, int channel)
 {
 	WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
 
@@ -193,19 +193,16 @@
 	}
 }
 
-int __pit_timer_fn(struct kvm_kpit_state *ps)
+static int __pit_timer_fn(struct kvm_kpit_state *ps)
 {
 	struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0];
 	struct kvm_kpit_timer *pt = &ps->pit_timer;
 
-	atomic_inc(&pt->pending);
-	smp_mb__after_atomic_inc();
-	if (vcpu0) {
+	if (!atomic_inc_and_test(&pt->pending))
 		set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
-		if (waitqueue_active(&vcpu0->wq)) {
-			vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
-			wake_up_interruptible(&vcpu0->wq);
-		}
+	if (vcpu0 && waitqueue_active(&vcpu0->wq)) {
+		vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+		wake_up_interruptible(&vcpu0->wq);
 	}
 
 	pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
@@ -308,6 +305,7 @@
 		create_pit_timer(&ps->pit_timer, val, 0);
 		break;
 	case 2:
+	case 3:
 		create_pit_timer(&ps->pit_timer, val, 1);
 		break;
 	default:
@@ -459,7 +457,8 @@
 	mutex_unlock(&pit_state->lock);
 }
 
-static int pit_in_range(struct kvm_io_device *this, gpa_t addr)
+static int pit_in_range(struct kvm_io_device *this, gpa_t addr,
+			int len, int is_write)
 {
 	return ((addr >= KVM_PIT_BASE_ADDRESS) &&
 		(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
@@ -500,7 +499,8 @@
 	mutex_unlock(&pit_state->lock);
 }
 
-static int speaker_in_range(struct kvm_io_device *this, gpa_t addr)
+static int speaker_in_range(struct kvm_io_device *this, gpa_t addr,
+			    int len, int is_write)
 {
 	return (addr == KVM_SPEAKER_BASE_ADDRESS);
 }
@@ -575,7 +575,7 @@
 	}
 }
 
-void __inject_pit_timer_intr(struct kvm *kvm)
+static void __inject_pit_timer_intr(struct kvm *kvm)
 {
 	mutex_lock(&kvm->lock);
 	kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1);
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index ab29cf2..c31164e 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -130,8 +130,10 @@
 {
 	struct kvm_pic *s = opaque;
 
-	pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
-	pic_update_irq(s);
+	if (irq >= 0 && irq < PIC_NUM_PINS) {
+		pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+		pic_update_irq(s);
+	}
 }
 
 /*
@@ -346,7 +348,8 @@
 	return s->elcr;
 }
 
-static int picdev_in_range(struct kvm_io_device *this, gpa_t addr)
+static int picdev_in_range(struct kvm_io_device *this, gpa_t addr,
+			   int len, int is_write)
 {
 	switch (addr) {
 	case 0x20:
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 2a15be2..7ca47cb 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -30,6 +30,8 @@
 #include "ioapic.h"
 #include "lapic.h"
 
+#define PIC_NUM_PINS 16
+
 struct kvm;
 struct kvm_vcpu;
 
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ebc03f5..73f43de 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -356,8 +356,9 @@
 	case APIC_DM_SMI:
 		printk(KERN_DEBUG "Ignoring guest SMI\n");
 		break;
+
 	case APIC_DM_NMI:
-		printk(KERN_DEBUG "Ignoring guest NMI\n");
+		kvm_inject_nmi(vcpu);
 		break;
 
 	case APIC_DM_INIT:
@@ -572,6 +573,8 @@
 {
 	u32 val = 0;
 
+	KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler);
+
 	if (offset >= LAPIC_MMIO_LENGTH)
 		return 0;
 
@@ -695,6 +698,8 @@
 
 	offset &= 0xff0;
 
+	KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler);
+
 	switch (offset) {
 	case APIC_ID:		/* Local APIC ID */
 		apic_set_reg(apic, APIC_ID, val);
@@ -780,7 +785,8 @@
 
 }
 
-static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
+static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr,
+			   int len, int size)
 {
 	struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
 	int ret = 0;
@@ -939,8 +945,8 @@
 	int result = 0;
 	wait_queue_head_t *q = &apic->vcpu->wq;
 
-	atomic_inc(&apic->timer.pending);
-	set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
+	if(!atomic_inc_and_test(&apic->timer.pending))
+		set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
 	if (waitqueue_active(q)) {
 		apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 		wake_up_interruptible(q);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 676c396..8185888 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -31,6 +31,7 @@
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
 void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
+u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 7e7c396..b0e4ddc 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -66,7 +66,8 @@
 #endif
 
 #if defined(MMU_DEBUG) || defined(AUDIT)
-static int dbg = 1;
+static int dbg = 0;
+module_param(dbg, bool, 0644);
 #endif
 
 #ifndef MMU_DEBUG
@@ -776,6 +777,15 @@
 	BUG();
 }
 
+static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
+				    struct kvm_mmu_page *sp)
+{
+	int i;
+
+	for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
+		sp->spt[i] = shadow_trap_nonpresent_pte;
+}
+
 static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
 {
 	unsigned index;
@@ -841,7 +851,10 @@
 	hlist_add_head(&sp->hash_link, bucket);
 	if (!metaphysical)
 		rmap_write_protect(vcpu->kvm, gfn);
-	vcpu->arch.mmu.prefetch_page(vcpu, sp);
+	if (shadow_trap_nonpresent_pte != shadow_notrap_nonpresent_pte)
+		vcpu->arch.mmu.prefetch_page(vcpu, sp);
+	else
+		nonpaging_prefetch_page(vcpu, sp);
 	return sp;
 }
 
@@ -917,14 +930,17 @@
 	}
 	kvm_mmu_page_unlink_children(kvm, sp);
 	if (!sp->root_count) {
-		if (!sp->role.metaphysical)
+		if (!sp->role.metaphysical && !sp->role.invalid)
 			unaccount_shadowed(kvm, sp->gfn);
 		hlist_del(&sp->hash_link);
 		kvm_mmu_free_page(kvm, sp);
 	} else {
+		int invalid = sp->role.invalid;
 		list_move(&sp->link, &kvm->arch.active_mmu_pages);
 		sp->role.invalid = 1;
 		kvm_reload_remote_mmus(kvm);
+		if (!sp->role.metaphysical && !invalid)
+			unaccount_shadowed(kvm, sp->gfn);
 	}
 	kvm_mmu_reset_last_pte_updated(kvm);
 }
@@ -1103,7 +1119,7 @@
 		mark_page_dirty(vcpu->kvm, gfn);
 
 	pgprintk("%s: setting spte %llx\n", __func__, spte);
-	pgprintk("instantiating %s PTE (%s) at %d (%llx) addr %llx\n",
+	pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n",
 		 (spte&PT_PAGE_SIZE_MASK)? "2MB" : "4kB",
 		 (spte&PT_WRITABLE_MASK)?"RW":"R", gfn, spte, shadow_pte);
 	set_shadow_pte(shadow_pte, spte);
@@ -1122,8 +1138,10 @@
 		else
 			kvm_release_pfn_clean(pfn);
 	}
-	if (!ptwrite || !*ptwrite)
+	if (speculative) {
 		vcpu->arch.last_pte_updated = shadow_pte;
+		vcpu->arch.last_pte_gfn = gfn;
+	}
 }
 
 static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
@@ -1171,9 +1189,10 @@
 				return -ENOMEM;
 			}
 
-			table[index] = __pa(new_table->spt)
-				| PT_PRESENT_MASK | PT_WRITABLE_MASK
-				| shadow_user_mask | shadow_x_mask;
+			set_shadow_pte(&table[index],
+				       __pa(new_table->spt)
+				       | PT_PRESENT_MASK | PT_WRITABLE_MASK
+				       | shadow_user_mask | shadow_x_mask);
 		}
 		table_addr = table[index] & PT64_BASE_ADDR_MASK;
 	}
@@ -1211,15 +1230,6 @@
 }
 
 
-static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
-				    struct kvm_mmu_page *sp)
-{
-	int i;
-
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
-		sp->spt[i] = shadow_trap_nonpresent_pte;
-}
-
 static void mmu_free_roots(struct kvm_vcpu *vcpu)
 {
 	int i;
@@ -1671,6 +1681,18 @@
 	vcpu->arch.update_pte.pfn = pfn;
 }
 
+static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+	u64 *spte = vcpu->arch.last_pte_updated;
+
+	if (spte
+	    && vcpu->arch.last_pte_gfn == gfn
+	    && shadow_accessed_mask
+	    && !(*spte & shadow_accessed_mask)
+	    && is_shadow_present_pte(*spte))
+		set_bit(PT_ACCESSED_SHIFT, (unsigned long *)spte);
+}
+
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
 		       const u8 *new, int bytes)
 {
@@ -1694,6 +1716,7 @@
 	pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
 	mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes);
 	spin_lock(&vcpu->kvm->mmu_lock);
+	kvm_mmu_access_page(vcpu, gfn);
 	kvm_mmu_free_some_pages(vcpu);
 	++vcpu->kvm->stat.mmu_pte_write;
 	kvm_mmu_audit(vcpu, "pre pte write");
@@ -1948,7 +1971,7 @@
 	kvm_flush_remote_tlbs(kvm);
 }
 
-void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm)
+static void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm)
 {
 	struct kvm_mmu_page *page;
 
@@ -1968,6 +1991,8 @@
 	list_for_each_entry(kvm, &vm_list, vm_list) {
 		int npages;
 
+		if (!down_read_trylock(&kvm->slots_lock))
+			continue;
 		spin_lock(&kvm->mmu_lock);
 		npages = kvm->arch.n_alloc_mmu_pages -
 			 kvm->arch.n_free_mmu_pages;
@@ -1980,6 +2005,7 @@
 		nr_to_scan--;
 
 		spin_unlock(&kvm->mmu_lock);
+		up_read(&kvm->slots_lock);
 	}
 	if (kvm_freed)
 		list_move_tail(&kvm_freed->vm_list, &vm_list);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 1730757..258e5d5 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -15,7 +15,8 @@
 #define PT_USER_MASK (1ULL << 2)
 #define PT_PWT_MASK (1ULL << 3)
 #define PT_PCD_MASK (1ULL << 4)
-#define PT_ACCESSED_MASK (1ULL << 5)
+#define PT_ACCESSED_SHIFT 5
+#define PT_ACCESSED_MASK (1ULL << PT_ACCESSED_SHIFT)
 #define PT_DIRTY_MASK (1ULL << 6)
 #define PT_PAGE_SIZE_MASK (1ULL << 7)
 #define PT_PAT_MASK (1ULL << 7)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 934c7b6..4d91822 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -460,8 +460,9 @@
 static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu,
 				 struct kvm_mmu_page *sp)
 {
-	int i, offset = 0, r = 0;
-	pt_element_t pt;
+	int i, j, offset, r;
+	pt_element_t pt[256 / sizeof(pt_element_t)];
+	gpa_t pte_gpa;
 
 	if (sp->role.metaphysical
 	    || (PTTYPE == 32 && sp->role.level > PT_PAGE_TABLE_LEVEL)) {
@@ -469,19 +470,20 @@
 		return;
 	}
 
-	if (PTTYPE == 32)
+	pte_gpa = gfn_to_gpa(sp->gfn);
+	if (PTTYPE == 32) {
 		offset = sp->role.quadrant << PT64_LEVEL_BITS;
+		pte_gpa += offset * sizeof(pt_element_t);
+	}
 
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-		gpa_t pte_gpa = gfn_to_gpa(sp->gfn);
-		pte_gpa += (i+offset) * sizeof(pt_element_t);
-
-		r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &pt,
-					  sizeof(pt_element_t));
-		if (r || is_present_pte(pt))
-			sp->spt[i] = shadow_trap_nonpresent_pte;
-		else
-			sp->spt[i] = shadow_notrap_nonpresent_pte;
+	for (i = 0; i < PT64_ENT_PER_PAGE; i += ARRAY_SIZE(pt)) {
+		r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, pt, sizeof pt);
+		pte_gpa += ARRAY_SIZE(pt) * sizeof(pt_element_t);
+		for (j = 0; j < ARRAY_SIZE(pt); ++j)
+			if (r || is_present_pte(pt[j]))
+				sp->spt[i+j] = shadow_trap_nonpresent_pte;
+			else
+				sp->spt[i+j] = shadow_notrap_nonpresent_pte;
 	}
 }
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 6b0d5fa..b756e87 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -27,6 +27,8 @@
 
 #include <asm/desc.h>
 
+#define __ex(x) __kvm_handle_fault_on_reboot(x)
+
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
@@ -129,17 +131,17 @@
 
 static inline void clgi(void)
 {
-	asm volatile (SVM_CLGI);
+	asm volatile (__ex(SVM_CLGI));
 }
 
 static inline void stgi(void)
 {
-	asm volatile (SVM_STGI);
+	asm volatile (__ex(SVM_STGI));
 }
 
 static inline void invlpga(unsigned long addr, u32 asid)
 {
-	asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid));
+	asm volatile (__ex(SVM_INVLPGA) :: "a"(addr), "c"(asid));
 }
 
 static inline unsigned long kvm_read_cr2(void)
@@ -270,19 +272,11 @@
 
 static void svm_hardware_disable(void *garbage)
 {
-	struct svm_cpu_data *svm_data
-		= per_cpu(svm_data, raw_smp_processor_id());
+	uint64_t efer;
 
-	if (svm_data) {
-		uint64_t efer;
-
-		wrmsrl(MSR_VM_HSAVE_PA, 0);
-		rdmsrl(MSR_EFER, efer);
-		wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
-		per_cpu(svm_data, raw_smp_processor_id()) = NULL;
-		__free_page(svm_data->save_area);
-		kfree(svm_data);
-	}
+	wrmsrl(MSR_VM_HSAVE_PA, 0);
+	rdmsrl(MSR_EFER, efer);
+	wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
 }
 
 static void svm_hardware_enable(void *garbage)
@@ -321,6 +315,19 @@
 	       page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
 }
 
+static void svm_cpu_uninit(int cpu)
+{
+	struct svm_cpu_data *svm_data
+		= per_cpu(svm_data, raw_smp_processor_id());
+
+	if (!svm_data)
+		return;
+
+	per_cpu(svm_data, raw_smp_processor_id()) = NULL;
+	__free_page(svm_data->save_area);
+	kfree(svm_data);
+}
+
 static int svm_cpu_init(int cpu)
 {
 	struct svm_cpu_data *svm_data;
@@ -458,6 +465,11 @@
 
 static __exit void svm_hardware_unsetup(void)
 {
+	int cpu;
+
+	for_each_online_cpu(cpu)
+		svm_cpu_uninit(cpu);
+
 	__free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
 	iopm_base = 0;
 }
@@ -707,10 +719,6 @@
 	rdtscll(vcpu->arch.host_tsc);
 }
 
-static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
-{
-}
-
 static void svm_cache_regs(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -949,7 +957,9 @@
 
 static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
 {
-	return to_svm(vcpu)->db_regs[dr];
+	unsigned long val = to_svm(vcpu)->db_regs[dr];
+	KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
+	return val;
 }
 
 static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
@@ -1004,6 +1014,16 @@
 
 	fault_address  = svm->vmcb->control.exit_info_2;
 	error_code = svm->vmcb->control.exit_info_1;
+
+	if (!npt_enabled)
+		KVMTRACE_3D(PAGE_FAULT, &svm->vcpu, error_code,
+			    (u32)fault_address, (u32)(fault_address >> 32),
+			    handler);
+	else
+		KVMTRACE_3D(TDP_FAULT, &svm->vcpu, error_code,
+			    (u32)fault_address, (u32)(fault_address >> 32),
+			    handler);
+
 	return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 }
 
@@ -1081,6 +1101,19 @@
 	return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
 }
 
+static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+	KVMTRACE_0D(NMI, &svm->vcpu, handler);
+	return 1;
+}
+
+static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+	++svm->vcpu.stat.irq_exits;
+	KVMTRACE_0D(INTR, &svm->vcpu, handler);
+	return 1;
+}
+
 static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 {
 	return 1;
@@ -1219,6 +1252,9 @@
 	if (svm_get_msr(&svm->vcpu, ecx, &data))
 		kvm_inject_gp(&svm->vcpu, 0);
 	else {
+		KVMTRACE_3D(MSR_READ, &svm->vcpu, ecx, (u32)data,
+			    (u32)(data >> 32), handler);
+
 		svm->vmcb->save.rax = data & 0xffffffff;
 		svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32;
 		svm->next_rip = svm->vmcb->save.rip + 2;
@@ -1284,16 +1320,19 @@
 	case MSR_K7_EVNTSEL1:
 	case MSR_K7_EVNTSEL2:
 	case MSR_K7_EVNTSEL3:
+	case MSR_K7_PERFCTR0:
+	case MSR_K7_PERFCTR1:
+	case MSR_K7_PERFCTR2:
+	case MSR_K7_PERFCTR3:
 		/*
-		 * only support writing 0 to the performance counters for now
-		 * to make Windows happy. Should be replaced by a real
-		 * performance counter emulation later.
+		 * Just discard all writes to the performance counters; this
+		 * should keep both older linux and windows 64-bit guests
+		 * happy
 		 */
-		if (data != 0)
-			goto unhandled;
+		pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", ecx, data);
+
 		break;
 	default:
-	unhandled:
 		return kvm_set_msr_common(vcpu, ecx, data);
 	}
 	return 0;
@@ -1304,6 +1343,10 @@
 	u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
 	u64 data = (svm->vmcb->save.rax & -1u)
 		| ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32);
+
+	KVMTRACE_3D(MSR_WRITE, &svm->vcpu, ecx, (u32)data, (u32)(data >> 32),
+		    handler);
+
 	svm->next_rip = svm->vmcb->save.rip + 2;
 	if (svm_set_msr(&svm->vcpu, ecx, data))
 		kvm_inject_gp(&svm->vcpu, 0);
@@ -1323,6 +1366,8 @@
 static int interrupt_window_interception(struct vcpu_svm *svm,
 				   struct kvm_run *kvm_run)
 {
+	KVMTRACE_0D(PEND_INTR, &svm->vcpu, handler);
+
 	svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
 	svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
 	/*
@@ -1364,8 +1409,8 @@
 	[SVM_EXIT_EXCP_BASE + PF_VECTOR] 	= pf_interception,
 	[SVM_EXIT_EXCP_BASE + NM_VECTOR] 	= nm_interception,
 	[SVM_EXIT_EXCP_BASE + MC_VECTOR] 	= mc_interception,
-	[SVM_EXIT_INTR] 			= nop_on_interception,
-	[SVM_EXIT_NMI]				= nop_on_interception,
+	[SVM_EXIT_INTR] 			= intr_interception,
+	[SVM_EXIT_NMI]				= nmi_interception,
 	[SVM_EXIT_SMI]				= nop_on_interception,
 	[SVM_EXIT_INIT]				= nop_on_interception,
 	[SVM_EXIT_VINTR]			= interrupt_window_interception,
@@ -1397,6 +1442,9 @@
 	struct vcpu_svm *svm = to_svm(vcpu);
 	u32 exit_code = svm->vmcb->control.exit_code;
 
+	KVMTRACE_3D(VMEXIT, vcpu, exit_code, (u32)svm->vmcb->save.rip,
+		    (u32)((u64)svm->vmcb->save.rip >> 32), entryexit);
+
 	if (npt_enabled) {
 		int mmu_reload = 0;
 		if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) {
@@ -1470,6 +1518,8 @@
 {
 	struct vmcb_control_area *control;
 
+	KVMTRACE_1D(INJ_VIRQ, &svm->vcpu, (u32)irq, handler);
+
 	control = &svm->vmcb->control;
 	control->int_vector = irq;
 	control->int_ctl &= ~V_INTR_PRIO_MASK;
@@ -1660,9 +1710,9 @@
 	sync_lapic_to_cr8(vcpu);
 
 	save_host_msrs(vcpu);
-	fs_selector = read_fs();
-	gs_selector = read_gs();
-	ldt_selector = read_ldt();
+	fs_selector = kvm_read_fs();
+	gs_selector = kvm_read_gs();
+	ldt_selector = kvm_read_ldt();
 	svm->host_cr2 = kvm_read_cr2();
 	svm->host_dr6 = read_dr6();
 	svm->host_dr7 = read_dr7();
@@ -1716,17 +1766,17 @@
 		/* Enter guest mode */
 		"push %%rax \n\t"
 		"mov %c[vmcb](%[svm]), %%rax \n\t"
-		SVM_VMLOAD "\n\t"
-		SVM_VMRUN "\n\t"
-		SVM_VMSAVE "\n\t"
+		__ex(SVM_VMLOAD) "\n\t"
+		__ex(SVM_VMRUN) "\n\t"
+		__ex(SVM_VMSAVE) "\n\t"
 		"pop %%rax \n\t"
 #else
 		/* Enter guest mode */
 		"push %%eax \n\t"
 		"mov %c[vmcb](%[svm]), %%eax \n\t"
-		SVM_VMLOAD "\n\t"
-		SVM_VMRUN "\n\t"
-		SVM_VMSAVE "\n\t"
+		__ex(SVM_VMLOAD) "\n\t"
+		__ex(SVM_VMRUN) "\n\t"
+		__ex(SVM_VMSAVE) "\n\t"
 		"pop %%eax \n\t"
 #endif
 
@@ -1795,9 +1845,9 @@
 	write_dr7(svm->host_dr7);
 	kvm_write_cr2(svm->host_cr2);
 
-	load_fs(fs_selector);
-	load_gs(gs_selector);
-	load_ldt(ldt_selector);
+	kvm_load_fs(fs_selector);
+	kvm_load_gs(gs_selector);
+	kvm_load_ldt(ldt_selector);
 	load_host_msrs(vcpu);
 
 	reload_tss(vcpu);
@@ -1889,7 +1939,6 @@
 	.prepare_guest_switch = svm_prepare_guest_switch,
 	.vcpu_load = svm_vcpu_load,
 	.vcpu_put = svm_vcpu_put,
-	.vcpu_decache = svm_vcpu_decache,
 
 	.set_guest_debug = svm_guest_debug,
 	.get_msr = svm_get_msr,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 10ce6ee..0cac637 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <asm/desc.h>
 
+#define __ex(x) __kvm_handle_fault_on_reboot(x)
+
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
@@ -53,6 +55,7 @@
 
 struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
+	struct list_head      local_vcpus_link;
 	int                   launched;
 	u8                    fail;
 	u32                   idt_vectoring_info;
@@ -88,9 +91,11 @@
 }
 
 static int init_rmode(struct kvm *kvm);
+static u64 construct_eptp(unsigned long root_hpa);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
+static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
 
 static struct page *vmx_io_bitmap_a;
 static struct page *vmx_io_bitmap_b;
@@ -260,6 +265,11 @@
 		SECONDARY_EXEC_ENABLE_VPID);
 }
 
+static inline int cpu_has_virtual_nmis(void)
+{
+	return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
+}
+
 static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
 {
 	int i;
@@ -278,7 +288,7 @@
 	u64 gva;
     } operand = { vpid, 0, gva };
 
-    asm volatile (ASM_VMX_INVVPID
+    asm volatile (__ex(ASM_VMX_INVVPID)
 		  /* CF==1 or ZF==1 --> rc = -1 */
 		  "; ja 1f ; ud2 ; 1:"
 		  : : "a"(&operand), "c"(ext) : "cc", "memory");
@@ -290,7 +300,7 @@
 		u64 eptp, gpa;
 	} operand = {eptp, gpa};
 
-	asm volatile (ASM_VMX_INVEPT
+	asm volatile (__ex(ASM_VMX_INVEPT)
 			/* CF==1 or ZF==1 --> rc = -1 */
 			"; ja 1f ; ud2 ; 1:\n"
 			: : "a" (&operand), "c" (ext) : "cc", "memory");
@@ -311,7 +321,7 @@
 	u64 phys_addr = __pa(vmcs);
 	u8 error;
 
-	asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0"
+	asm volatile (__ex(ASM_VMX_VMCLEAR_RAX) "; setna %0"
 		      : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
 		      : "cc", "memory");
 	if (error)
@@ -329,6 +339,9 @@
 	if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
 		per_cpu(current_vmcs, cpu) = NULL;
 	rdtscll(vmx->vcpu.arch.host_tsc);
+	list_del(&vmx->local_vcpus_link);
+	vmx->vcpu.cpu = -1;
+	vmx->launched = 0;
 }
 
 static void vcpu_clear(struct vcpu_vmx *vmx)
@@ -336,7 +349,6 @@
 	if (vmx->vcpu.cpu == -1)
 		return;
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1);
-	vmx->launched = 0;
 }
 
 static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx)
@@ -378,7 +390,7 @@
 {
 	unsigned long value;
 
-	asm volatile (ASM_VMX_VMREAD_RDX_RAX
+	asm volatile (__ex(ASM_VMX_VMREAD_RDX_RAX)
 		      : "=a"(value) : "d"(field) : "cc");
 	return value;
 }
@@ -413,7 +425,7 @@
 {
 	u8 error;
 
-	asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
+	asm volatile (__ex(ASM_VMX_VMWRITE_RAX_RDX) "; setna %0"
 		       : "=q"(error) : "a"(value), "d"(field) : "cc");
 	if (unlikely(error))
 		vmwrite_error(field, value);
@@ -431,10 +443,8 @@
 
 static void vmcs_write64(unsigned long field, u64 value)
 {
-#ifdef CONFIG_X86_64
 	vmcs_writel(field, value);
-#else
-	vmcs_writel(field, value);
+#ifndef CONFIG_X86_64
 	asm volatile ("");
 	vmcs_writel(field+1, value >> 32);
 #endif
@@ -474,7 +484,7 @@
 	struct descriptor_table gdt;
 	struct desc_struct *descs;
 
-	get_gdt(&gdt);
+	kvm_get_gdt(&gdt);
 	descs = (void *)gdt.base;
 	descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
 	load_TR_desc();
@@ -530,9 +540,9 @@
 	 * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
 	 * allow segment selectors with cpl > 0 or ti == 1.
 	 */
-	vmx->host_state.ldt_sel = read_ldt();
+	vmx->host_state.ldt_sel = kvm_read_ldt();
 	vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
-	vmx->host_state.fs_sel = read_fs();
+	vmx->host_state.fs_sel = kvm_read_fs();
 	if (!(vmx->host_state.fs_sel & 7)) {
 		vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
 		vmx->host_state.fs_reload_needed = 0;
@@ -540,7 +550,7 @@
 		vmcs_write16(HOST_FS_SELECTOR, 0);
 		vmx->host_state.fs_reload_needed = 1;
 	}
-	vmx->host_state.gs_sel = read_gs();
+	vmx->host_state.gs_sel = kvm_read_gs();
 	if (!(vmx->host_state.gs_sel & 7))
 		vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
 	else {
@@ -576,15 +586,15 @@
 	++vmx->vcpu.stat.host_state_reload;
 	vmx->host_state.loaded = 0;
 	if (vmx->host_state.fs_reload_needed)
-		load_fs(vmx->host_state.fs_sel);
+		kvm_load_fs(vmx->host_state.fs_sel);
 	if (vmx->host_state.gs_ldt_reload_needed) {
-		load_ldt(vmx->host_state.ldt_sel);
+		kvm_load_ldt(vmx->host_state.ldt_sel);
 		/*
 		 * If we have to reload gs, we must take care to
 		 * preserve our gs base.
 		 */
 		local_irq_save(flags);
-		load_gs(vmx->host_state.gs_sel);
+		kvm_load_gs(vmx->host_state.gs_sel);
 #ifdef CONFIG_X86_64
 		wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
 #endif
@@ -617,13 +627,17 @@
 		vcpu_clear(vmx);
 		kvm_migrate_timers(vcpu);
 		vpid_sync_vcpu_all(vmx);
+		local_irq_disable();
+		list_add(&vmx->local_vcpus_link,
+			 &per_cpu(vcpus_on_cpu, cpu));
+		local_irq_enable();
 	}
 
 	if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
 		u8 error;
 
 		per_cpu(current_vmcs, cpu) = vmx->vmcs;
-		asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
+		asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0"
 			      : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
 			      : "cc");
 		if (error)
@@ -640,8 +654,8 @@
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
 		 * processors.
 		 */
-		vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */
-		get_gdt(&dt);
+		vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */
+		kvm_get_gdt(&dt);
 		vmcs_writel(HOST_GDTR_BASE, dt.base);   /* 22.2.4 */
 
 		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
@@ -684,11 +698,6 @@
 	update_exception_bitmap(vcpu);
 }
 
-static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
-{
-	vcpu_clear(to_vmx(vcpu));
-}
-
 static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 {
 	return vmcs_readl(GUEST_RFLAGS);
@@ -913,6 +922,18 @@
 	case MSR_IA32_TIME_STAMP_COUNTER:
 		guest_write_tsc(data);
 		break;
+	case MSR_P6_PERFCTR0:
+	case MSR_P6_PERFCTR1:
+	case MSR_P6_EVNTSEL0:
+	case MSR_P6_EVNTSEL1:
+		/*
+		 * Just discard all writes to the performance counters; this
+		 * should keep both older linux and windows 64-bit guests
+		 * happy
+		 */
+		pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", msr_index, data);
+
+		break;
 	default:
 		vmx_load_host_state(vmx);
 		msr = find_msr_entry(vmx, msr_index);
@@ -1022,6 +1043,7 @@
 	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
 	u64 old;
 
+	INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
 	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
 	if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED |
 		    MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
@@ -1032,13 +1054,25 @@
 		       MSR_IA32_FEATURE_CONTROL_LOCKED |
 		       MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED);
 	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
-	asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
+	asm volatile (ASM_VMX_VMXON_RAX
+		      : : "a"(&phys_addr), "m"(phys_addr)
 		      : "memory", "cc");
 }
 
+static void vmclear_local_vcpus(void)
+{
+	int cpu = raw_smp_processor_id();
+	struct vcpu_vmx *vmx, *n;
+
+	list_for_each_entry_safe(vmx, n, &per_cpu(vcpus_on_cpu, cpu),
+				 local_vcpus_link)
+		__vcpu_clear(vmx);
+}
+
 static void hardware_disable(void *garbage)
 {
-	asm volatile (ASM_VMX_VMXOFF : : : "cc");
+	vmclear_local_vcpus();
+	asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
 	write_cr4(read_cr4() & ~X86_CR4_VMXE);
 }
 
@@ -1072,7 +1106,7 @@
 	u32 _vmentry_control = 0;
 
 	min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
-	opt = 0;
+	opt = PIN_BASED_VIRTUAL_NMIS;
 	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
 				&_pin_based_exec_control) < 0)
 		return -EIO;
@@ -1389,6 +1423,8 @@
 static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 {
 	vpid_sync_vcpu_all(to_vmx(vcpu));
+	if (vm_need_ept())
+		ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa));
 }
 
 static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
@@ -1420,7 +1456,7 @@
 	if (!(cr0 & X86_CR0_PG)) {
 		/* From paging/starting to nonpaging */
 		vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
-			     vmcs_config.cpu_based_exec_ctrl |
+			     vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) |
 			     (CPU_BASED_CR3_LOAD_EXITING |
 			      CPU_BASED_CR3_STORE_EXITING));
 		vcpu->arch.cr0 = cr0;
@@ -1430,7 +1466,7 @@
 	} else if (!is_paging(vcpu)) {
 		/* From nonpaging to paging */
 		vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
-			     vmcs_config.cpu_based_exec_ctrl &
+			     vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) &
 			     ~(CPU_BASED_CR3_LOAD_EXITING |
 			       CPU_BASED_CR3_STORE_EXITING));
 		vcpu->arch.cr0 = cr0;
@@ -1821,7 +1857,7 @@
 	spin_unlock(&vmx_vpid_lock);
 }
 
-void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
+static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
 {
 	void *va;
 
@@ -1907,8 +1943,8 @@
 	vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS);  /* 22.2.4 */
 	vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
 	vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
-	vmcs_write16(HOST_FS_SELECTOR, read_fs());    /* 22.2.4 */
-	vmcs_write16(HOST_GS_SELECTOR, read_gs());    /* 22.2.4 */
+	vmcs_write16(HOST_FS_SELECTOR, kvm_read_fs());    /* 22.2.4 */
+	vmcs_write16(HOST_GS_SELECTOR, kvm_read_gs());    /* 22.2.4 */
 	vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
 #ifdef CONFIG_X86_64
 	rdmsrl(MSR_FS_BASE, a);
@@ -1922,7 +1958,7 @@
 
 	vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
 
-	get_idt(&dt);
+	kvm_get_idt(&dt);
 	vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
 
 	asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
@@ -2114,6 +2150,13 @@
 			irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
+static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
+{
+	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+			INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR);
+	vcpu->arch.nmi_pending = 0;
+}
+
 static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
 {
 	int word_index = __ffs(vcpu->arch.irq_summary);
@@ -2554,8 +2597,6 @@
 	exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
 	offset = exit_qualification & 0xffful;
 
-	KVMTRACE_1D(APIC_ACCESS, vcpu, (u32)offset, handler);
-
 	er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
 
 	if (er !=  EMULATE_DONE) {
@@ -2639,6 +2680,19 @@
 	return 1;
 }
 
+static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	u32 cpu_based_vm_exec_control;
+
+	/* clear pending NMI */
+	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+	cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
+	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+	++vcpu->stat.nmi_window_exits;
+
+	return 1;
+}
+
 /*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
@@ -2649,6 +2703,7 @@
 	[EXIT_REASON_EXCEPTION_NMI]           = handle_exception,
 	[EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt,
 	[EXIT_REASON_TRIPLE_FAULT]            = handle_triple_fault,
+	[EXIT_REASON_NMI_WINDOW]	      = handle_nmi_window,
 	[EXIT_REASON_IO_INSTRUCTION]          = handle_io,
 	[EXIT_REASON_CR_ACCESS]               = handle_cr,
 	[EXIT_REASON_DR_ACCESS]               = handle_dr,
@@ -2736,17 +2791,52 @@
 	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
 }
 
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
+{
+	u32 cpu_based_vm_exec_control;
+
+	if (!cpu_has_virtual_nmis())
+		return;
+
+	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+	cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING;
+	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
+static int vmx_nmi_enabled(struct kvm_vcpu *vcpu)
+{
+	u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+	return !(guest_intr & (GUEST_INTR_STATE_NMI |
+			       GUEST_INTR_STATE_MOV_SS |
+			       GUEST_INTR_STATE_STI));
+}
+
+static int vmx_irq_enabled(struct kvm_vcpu *vcpu)
+{
+	u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+	return (!(guest_intr & (GUEST_INTR_STATE_MOV_SS |
+			       GUEST_INTR_STATE_STI)) &&
+		(vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
+}
+
+static void enable_intr_window(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.nmi_pending)
+		enable_nmi_window(vcpu);
+	else if (kvm_cpu_has_interrupt(vcpu))
+		enable_irq_window(vcpu);
+}
+
 static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u32 idtv_info_field, intr_info_field;
-	int has_ext_irq, interrupt_window_open;
+	u32 idtv_info_field, intr_info_field, exit_intr_info_field;
 	int vector;
 
 	update_tpr_threshold(vcpu);
 
-	has_ext_irq = kvm_cpu_has_interrupt(vcpu);
 	intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+	exit_intr_info_field = vmcs_read32(VM_EXIT_INTR_INFO);
 	idtv_info_field = vmx->idt_vectoring_info;
 	if (intr_info_field & INTR_INFO_VALID_MASK) {
 		if (idtv_info_field & INTR_INFO_VALID_MASK) {
@@ -2754,8 +2844,7 @@
 			if (printk_ratelimit())
 				printk(KERN_ERR "Fault when IDT_Vectoring\n");
 		}
-		if (has_ext_irq)
-			enable_irq_window(vcpu);
+		enable_intr_window(vcpu);
 		return;
 	}
 	if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
@@ -2765,30 +2854,56 @@
 			u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK;
 
 			vmx_inject_irq(vcpu, vect);
-			if (unlikely(has_ext_irq))
-				enable_irq_window(vcpu);
+			enable_intr_window(vcpu);
 			return;
 		}
 
 		KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler);
 
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+		/*
+		 * SDM 3: 25.7.1.2
+		 * Clear bit "block by NMI" before VM entry if a NMI delivery
+		 * faulted.
+		 */
+		if ((idtv_info_field & VECTORING_INFO_TYPE_MASK)
+		    == INTR_TYPE_NMI_INTR && cpu_has_virtual_nmis())
+			vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+				vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+				~GUEST_INTR_STATE_NMI);
+
+		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field
+				& ~INTR_INFO_RESVD_BITS_MASK);
 		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
 				vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
 
 		if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK))
 			vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
 				vmcs_read32(IDT_VECTORING_ERROR_CODE));
-		if (unlikely(has_ext_irq))
-			enable_irq_window(vcpu);
+		enable_intr_window(vcpu);
 		return;
 	}
-	if (!has_ext_irq)
+	if (cpu_has_virtual_nmis()) {
+		/*
+		 * SDM 3: 25.7.1.2
+		 * Re-set bit "block by NMI" before VM entry if vmexit caused by
+		 * a guest IRET fault.
+		 */
+		if ((exit_intr_info_field & INTR_INFO_UNBLOCK_NMI) &&
+		    (exit_intr_info_field & INTR_INFO_VECTOR_MASK) != 8)
+			vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+				vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) |
+				GUEST_INTR_STATE_NMI);
+		else if (vcpu->arch.nmi_pending) {
+			if (vmx_nmi_enabled(vcpu))
+				vmx_inject_nmi(vcpu);
+			enable_intr_window(vcpu);
+			return;
+		}
+
+	}
+	if (!kvm_cpu_has_interrupt(vcpu))
 		return;
-	interrupt_window_open =
-		((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
-		 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-	if (interrupt_window_open) {
+	if (vmx_irq_enabled(vcpu)) {
 		vector = kvm_cpu_get_interrupt(vcpu);
 		vmx_inject_irq(vcpu, vector);
 		kvm_timer_intr_post(vcpu, vector);
@@ -2838,7 +2953,7 @@
 		"push %%edx; push %%ebp;"
 		"push %%ecx \n\t"
 #endif
-		ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+		__ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
 		/* Check if vmlaunch of vmresume is needed */
 		"cmpl $0, %c[launched](%0) \n\t"
 		/* Load guest registers.  Don't clobber flags. */
@@ -2873,9 +2988,9 @@
 #endif
 		/* Enter guest mode */
 		"jne .Llaunched \n\t"
-		ASM_VMX_VMLAUNCH "\n\t"
+		__ex(ASM_VMX_VMLAUNCH) "\n\t"
 		"jmp .Lkvm_vmx_return \n\t"
-		".Llaunched: " ASM_VMX_VMRESUME "\n\t"
+		".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t"
 		".Lkvm_vmx_return: "
 		/* Save guest registers, load host registers, keep flags */
 #ifdef CONFIG_X86_64
@@ -2949,7 +3064,8 @@
 		fixup_rmode_irq(vmx);
 
 	vcpu->arch.interrupt_window_open =
-		(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
+		(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+		 (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) == 0;
 
 	asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 	vmx->launched = 1;
@@ -2957,7 +3073,8 @@
 	intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
 	/* We need to handle NMIs before interrupts are enabled */
-	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
+	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200 &&
+	    (intr_info & INTR_INFO_VALID_MASK)) {
 		KVMTRACE_0D(NMI, vcpu, handler);
 		asm("int $2");
 	}
@@ -2968,7 +3085,7 @@
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 
 	if (vmx->vmcs) {
-		on_each_cpu(__vcpu_clear, vmx, 1);
+		vcpu_clear(vmx);
 		free_vmcs(vmx->vmcs);
 		vmx->vmcs = NULL;
 	}
@@ -3095,7 +3212,6 @@
 	.prepare_guest_switch = vmx_save_host_state,
 	.vcpu_load = vmx_vcpu_load,
 	.vcpu_put = vmx_vcpu_put,
-	.vcpu_decache = vmx_vcpu_decache,
 
 	.set_guest_debug = set_guest_debug,
 	.guest_debug_pre = kvm_guest_debug_pre,
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h
index 79d94c6..425a134 100644
--- a/arch/x86/kvm/vmx.h
+++ b/arch/x86/kvm/vmx.h
@@ -40,6 +40,7 @@
 #define CPU_BASED_CR8_LOAD_EXITING              0x00080000
 #define CPU_BASED_CR8_STORE_EXITING             0x00100000
 #define CPU_BASED_TPR_SHADOW                    0x00200000
+#define CPU_BASED_VIRTUAL_NMI_PENDING		0x00400000
 #define CPU_BASED_MOV_DR_EXITING                0x00800000
 #define CPU_BASED_UNCOND_IO_EXITING             0x01000000
 #define CPU_BASED_USE_IO_BITMAPS                0x02000000
@@ -216,7 +217,7 @@
 #define EXIT_REASON_TRIPLE_FAULT        2
 
 #define EXIT_REASON_PENDING_INTERRUPT   7
-
+#define EXIT_REASON_NMI_WINDOW		8
 #define EXIT_REASON_TASK_SWITCH         9
 #define EXIT_REASON_CPUID               10
 #define EXIT_REASON_HLT                 12
@@ -251,7 +252,9 @@
 #define INTR_INFO_VECTOR_MASK           0xff            /* 7:0 */
 #define INTR_INFO_INTR_TYPE_MASK        0x700           /* 10:8 */
 #define INTR_INFO_DELIVER_CODE_MASK     0x800           /* 11 */
+#define INTR_INFO_UNBLOCK_NMI		0x1000		/* 12 */
 #define INTR_INFO_VALID_MASK            0x80000000      /* 31 */
+#define INTR_INFO_RESVD_BITS_MASK       0x7ffff000
 
 #define VECTORING_INFO_VECTOR_MASK           	INTR_INFO_VECTOR_MASK
 #define VECTORING_INFO_TYPE_MASK        	INTR_INFO_INTR_TYPE_MASK
@@ -259,9 +262,16 @@
 #define VECTORING_INFO_VALID_MASK       	INTR_INFO_VALID_MASK
 
 #define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
+#define INTR_TYPE_NMI_INTR		(2 << 8) /* NMI */
 #define INTR_TYPE_EXCEPTION             (3 << 8) /* processor exception */
 #define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
 
+/* GUEST_INTERRUPTIBILITY_INFO flags. */
+#define GUEST_INTR_STATE_STI		0x00000001
+#define GUEST_INTR_STATE_MOV_SS		0x00000002
+#define GUEST_INTR_STATE_SMI		0x00000004
+#define GUEST_INTR_STATE_NMI		0x00000008
+
 /*
  * Exit Qualifications for MOV for Control Register Access
  */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0faa254..9f1cdb0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -72,6 +72,7 @@
 	{ "mmio_exits", VCPU_STAT(mmio_exits) },
 	{ "signal_exits", VCPU_STAT(signal_exits) },
 	{ "irq_window", VCPU_STAT(irq_window_exits) },
+	{ "nmi_window", VCPU_STAT(nmi_window_exits) },
 	{ "halt_exits", VCPU_STAT(halt_exits) },
 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
 	{ "hypercalls", VCPU_STAT(hypercalls) },
@@ -173,6 +174,12 @@
 	kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
 }
 
+void kvm_inject_nmi(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.nmi_pending = 1;
+}
+EXPORT_SYMBOL_GPL(kvm_inject_nmi);
+
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
 {
 	WARN_ON(vcpu->arch.exception.pending);
@@ -604,6 +611,38 @@
 	mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT);
 }
 
+static bool msr_mtrr_valid(unsigned msr)
+{
+	switch (msr) {
+	case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1:
+	case MSR_MTRRfix64K_00000:
+	case MSR_MTRRfix16K_80000:
+	case MSR_MTRRfix16K_A0000:
+	case MSR_MTRRfix4K_C0000:
+	case MSR_MTRRfix4K_C8000:
+	case MSR_MTRRfix4K_D0000:
+	case MSR_MTRRfix4K_D8000:
+	case MSR_MTRRfix4K_E0000:
+	case MSR_MTRRfix4K_E8000:
+	case MSR_MTRRfix4K_F0000:
+	case MSR_MTRRfix4K_F8000:
+	case MSR_MTRRdefType:
+	case MSR_IA32_CR_PAT:
+		return true;
+	case 0x2f8:
+		return true;
+	}
+	return false;
+}
+
+static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+	if (!msr_mtrr_valid(msr))
+		return 1;
+
+	vcpu->arch.mtrr[msr - 0x200] = data;
+	return 0;
+}
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
@@ -625,8 +664,9 @@
 		break;
 	case MSR_IA32_UCODE_REV:
 	case MSR_IA32_UCODE_WRITE:
-	case 0x200 ... 0x2ff: /* MTRRs */
 		break;
+	case 0x200 ... 0x2ff:
+		return set_msr_mtrr(vcpu, msr, data);
 	case MSR_IA32_APICBASE:
 		kvm_set_apic_base(vcpu, data);
 		break;
@@ -684,6 +724,15 @@
 	return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
 }
 
+static int get_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+{
+	if (!msr_mtrr_valid(msr))
+		return 1;
+
+	*pdata = vcpu->arch.mtrr[msr - 0x200];
+	return 0;
+}
+
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 {
 	u64 data;
@@ -705,11 +754,13 @@
 	case MSR_IA32_MC0_MISC+16:
 	case MSR_IA32_UCODE_REV:
 	case MSR_IA32_EBL_CR_POWERON:
-		/* MTRR registers */
-	case 0xfe:
-	case 0x200 ... 0x2ff:
 		data = 0;
 		break;
+	case MSR_MTRRcap:
+		data = 0x500 | KVM_NR_VAR_MTRR;
+		break;
+	case 0x200 ... 0x2ff:
+		return get_msr_mtrr(vcpu, msr, pdata);
 	case 0xcd: /* fsb frequency */
 		data = 3;
 		break;
@@ -817,41 +868,6 @@
 	return r;
 }
 
-/*
- * Make sure that a cpu that is being hot-unplugged does not have any vcpus
- * cached on it.
- */
-void decache_vcpus_on_cpu(int cpu)
-{
-	struct kvm *vm;
-	struct kvm_vcpu *vcpu;
-	int i;
-
-	spin_lock(&kvm_lock);
-	list_for_each_entry(vm, &vm_list, vm_list)
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			vcpu = vm->vcpus[i];
-			if (!vcpu)
-				continue;
-			/*
-			 * If the vcpu is locked, then it is running on some
-			 * other cpu and therefore it is not cached on the
-			 * cpu in question.
-			 *
-			 * If it's not locked, check the last cpu it executed
-			 * on.
-			 */
-			if (mutex_trylock(&vcpu->mutex)) {
-				if (vcpu->cpu == cpu) {
-					kvm_x86_ops->vcpu_decache(vcpu);
-					vcpu->cpu = -1;
-				}
-				mutex_unlock(&vcpu->mutex);
-			}
-		}
-	spin_unlock(&kvm_lock);
-}
-
 int kvm_dev_ioctl_check_extension(long ext)
 {
 	int r;
@@ -869,6 +885,9 @@
 	case KVM_CAP_MP_STATE:
 		r = 1;
 		break;
+	case KVM_CAP_COALESCED_MMIO:
+		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
+		break;
 	case KVM_CAP_VAPIC:
 		r = !kvm_x86_ops->cpu_has_accelerated_tpr();
 		break;
@@ -1781,13 +1800,14 @@
  * Only apic need an MMIO device hook, so shortcut now..
  */
 static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
-						gpa_t addr)
+						gpa_t addr, int len,
+						int is_write)
 {
 	struct kvm_io_device *dev;
 
 	if (vcpu->arch.apic) {
 		dev = &vcpu->arch.apic->dev;
-		if (dev->in_range(dev, addr))
+		if (dev->in_range(dev, addr, len, is_write))
 			return dev;
 	}
 	return NULL;
@@ -1795,13 +1815,15 @@
 
 
 static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
-						gpa_t addr)
+						gpa_t addr, int len,
+						int is_write)
 {
 	struct kvm_io_device *dev;
 
-	dev = vcpu_find_pervcpu_dev(vcpu, addr);
+	dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write);
 	if (dev == NULL)
-		dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+		dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len,
+					  is_write);
 	return dev;
 }
 
@@ -1869,7 +1891,7 @@
 	 * Is this MMIO handled locally?
 	 */
 	mutex_lock(&vcpu->kvm->lock);
-	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0);
 	if (mmio_dev) {
 		kvm_iodevice_read(mmio_dev, gpa, bytes, val);
 		mutex_unlock(&vcpu->kvm->lock);
@@ -1924,7 +1946,7 @@
 	 * Is this MMIO handled locally?
 	 */
 	mutex_lock(&vcpu->kvm->lock);
-	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1);
 	if (mmio_dev) {
 		kvm_iodevice_write(mmio_dev, gpa, bytes, val);
 		mutex_unlock(&vcpu->kvm->lock);
@@ -2020,6 +2042,7 @@
 
 int emulate_clts(struct kvm_vcpu *vcpu)
 {
+	KVMTRACE_0D(CLTS, vcpu, handler);
 	kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS);
 	return X86EMUL_CONTINUE;
 }
@@ -2053,21 +2076,19 @@
 
 void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
 {
-	static int reported;
 	u8 opcodes[4];
 	unsigned long rip = vcpu->arch.rip;
 	unsigned long rip_linear;
 
-	rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
-
-	if (reported)
+	if (!printk_ratelimit())
 		return;
 
+	rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
+
 	emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
 
 	printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
 	       context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
-	reported = 1;
 }
 EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
 
@@ -2105,27 +2126,6 @@
 			? X86EMUL_MODE_PROT64 :	cs_db
 			? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
 
-		if (vcpu->arch.emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
-			vcpu->arch.emulate_ctxt.cs_base = 0;
-			vcpu->arch.emulate_ctxt.ds_base = 0;
-			vcpu->arch.emulate_ctxt.es_base = 0;
-			vcpu->arch.emulate_ctxt.ss_base = 0;
-		} else {
-			vcpu->arch.emulate_ctxt.cs_base =
-					get_segment_base(vcpu, VCPU_SREG_CS);
-			vcpu->arch.emulate_ctxt.ds_base =
-					get_segment_base(vcpu, VCPU_SREG_DS);
-			vcpu->arch.emulate_ctxt.es_base =
-					get_segment_base(vcpu, VCPU_SREG_ES);
-			vcpu->arch.emulate_ctxt.ss_base =
-					get_segment_base(vcpu, VCPU_SREG_SS);
-		}
-
-		vcpu->arch.emulate_ctxt.gs_base =
-					get_segment_base(vcpu, VCPU_SREG_GS);
-		vcpu->arch.emulate_ctxt.fs_base =
-					get_segment_base(vcpu, VCPU_SREG_FS);
-
 		r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
 
 		/* Reject the instructions other than VMCALL/VMMCALL when
@@ -2300,9 +2300,10 @@
 }
 
 static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
-					       gpa_t addr)
+					       gpa_t addr, int len,
+					       int is_write)
 {
-	return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
+	return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr, len, is_write);
 }
 
 int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
@@ -2331,11 +2332,10 @@
 
 	kvm_x86_ops->cache_regs(vcpu);
 	memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4);
-	kvm_x86_ops->decache_regs(vcpu);
 
 	kvm_x86_ops->skip_emulated_instruction(vcpu);
 
-	pio_dev = vcpu_find_pio_dev(vcpu, port);
+	pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in);
 	if (pio_dev) {
 		kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data);
 		complete_pio(vcpu);
@@ -2417,7 +2417,9 @@
 		}
 	}
 
-	pio_dev = vcpu_find_pio_dev(vcpu, port);
+	pio_dev = vcpu_find_pio_dev(vcpu, port,
+				    vcpu->arch.pio.cur_count,
+				    !vcpu->arch.pio.in);
 	if (!vcpu->arch.pio.in) {
 		/* string PIO write */
 		ret = pio_copy_data(vcpu);
@@ -2600,27 +2602,41 @@
 
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
 {
+	unsigned long value;
+
 	kvm_x86_ops->decache_cr4_guest_bits(vcpu);
 	switch (cr) {
 	case 0:
-		return vcpu->arch.cr0;
+		value = vcpu->arch.cr0;
+		break;
 	case 2:
-		return vcpu->arch.cr2;
+		value = vcpu->arch.cr2;
+		break;
 	case 3:
-		return vcpu->arch.cr3;
+		value = vcpu->arch.cr3;
+		break;
 	case 4:
-		return vcpu->arch.cr4;
+		value = vcpu->arch.cr4;
+		break;
 	case 8:
-		return kvm_get_cr8(vcpu);
+		value = kvm_get_cr8(vcpu);
+		break;
 	default:
 		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
 		return 0;
 	}
+	KVMTRACE_3D(CR_READ, vcpu, (u32)cr, (u32)value,
+		    (u32)((u64)value >> 32), handler);
+
+	return value;
 }
 
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
 		     unsigned long *rflags)
 {
+	KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)val,
+		    (u32)((u64)val >> 32), handler);
+
 	switch (cr) {
 	case 0:
 		kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
@@ -2771,8 +2787,10 @@
 	if (!apic || !apic->vapic_addr)
 		return;
 
+	down_read(&vcpu->kvm->slots_lock);
 	kvm_release_page_dirty(apic->vapic_page);
 	mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
+	up_read(&vcpu->kvm->slots_lock);
 }
 
 static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -2928,9 +2946,7 @@
 
 	post_kvm_run_save(vcpu, kvm_run);
 
-	down_read(&vcpu->kvm->slots_lock);
 	vapic_exit(vcpu);
-	up_read(&vcpu->kvm->slots_lock);
 
 	return r;
 }
@@ -2942,15 +2958,15 @@
 
 	vcpu_load(vcpu);
 
-	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
-		kvm_vcpu_block(vcpu);
-		vcpu_put(vcpu);
-		return -EAGAIN;
-	}
-
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
+	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
+		kvm_vcpu_block(vcpu);
+		r = -EAGAIN;
+		goto out;
+	}
+
 	/* re-sync apic's tpr */
 	if (!irqchip_in_kernel(vcpu->kvm))
 		kvm_set_cr8(vcpu, kvm_run->cr8);
@@ -3070,8 +3086,8 @@
 	return 0;
 }
 
-static void get_segment(struct kvm_vcpu *vcpu,
-			struct kvm_segment *var, int seg)
+void kvm_get_segment(struct kvm_vcpu *vcpu,
+		     struct kvm_segment *var, int seg)
 {
 	kvm_x86_ops->get_segment(vcpu, var, seg);
 }
@@ -3080,7 +3096,7 @@
 {
 	struct kvm_segment cs;
 
-	get_segment(vcpu, &cs, VCPU_SREG_CS);
+	kvm_get_segment(vcpu, &cs, VCPU_SREG_CS);
 	*db = cs.db;
 	*l = cs.l;
 }
@@ -3094,15 +3110,15 @@
 
 	vcpu_load(vcpu);
 
-	get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
-	get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
-	get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
-	get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
-	get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
-	get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+	kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+	kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+	kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+	kvm_get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+	kvm_get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+	kvm_get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
 
-	get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
-	get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+	kvm_get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+	kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
 	kvm_x86_ops->get_idt(vcpu, &dt);
 	sregs->idt.limit = dt.limit;
@@ -3154,7 +3170,7 @@
 	return 0;
 }
 
-static void set_segment(struct kvm_vcpu *vcpu,
+static void kvm_set_segment(struct kvm_vcpu *vcpu,
 			struct kvm_segment *var, int seg)
 {
 	kvm_x86_ops->set_segment(vcpu, var, seg);
@@ -3191,7 +3207,7 @@
 	if (selector & 1 << 2) {
 		struct kvm_segment kvm_seg;
 
-		get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
+		kvm_get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
 
 		if (kvm_seg.unusable)
 			dtable->limit = 0;
@@ -3297,7 +3313,7 @@
 {
 	struct kvm_segment kvm_seg;
 
-	get_segment(vcpu, &kvm_seg, seg);
+	kvm_get_segment(vcpu, &kvm_seg, seg);
 	return kvm_seg.selector;
 }
 
@@ -3313,8 +3329,8 @@
 	return 0;
 }
 
-static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
-				   int type_bits, int seg)
+int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+				int type_bits, int seg)
 {
 	struct kvm_segment kvm_seg;
 
@@ -3327,7 +3343,7 @@
 		if (!kvm_seg.s)
 			kvm_seg.unusable = 1;
 
-	set_segment(vcpu, &kvm_seg, seg);
+	kvm_set_segment(vcpu, &kvm_seg, seg);
 	return 0;
 }
 
@@ -3373,25 +3389,25 @@
 	vcpu->arch.regs[VCPU_REGS_RSI] = tss->esi;
 	vcpu->arch.regs[VCPU_REGS_RDI] = tss->edi;
 
-	if (load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
+	if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
+	if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
+	if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
+	if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
+	if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
+	if (kvm_load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
+	if (kvm_load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
 		return 1;
 	return 0;
 }
@@ -3432,24 +3448,24 @@
 	vcpu->arch.regs[VCPU_REGS_RSI] = tss->si;
 	vcpu->arch.regs[VCPU_REGS_RDI] = tss->di;
 
-	if (load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
+	if (kvm_load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
+	if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
+	if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
+	if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
 		return 1;
 
-	if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
+	if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
 		return 1;
 	return 0;
 }
 
-int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
+static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
 		       struct desc_struct *cseg_desc,
 		       struct desc_struct *nseg_desc)
 {
@@ -3472,7 +3488,7 @@
 	return ret;
 }
 
-int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
+static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
 		       struct desc_struct *cseg_desc,
 		       struct desc_struct *nseg_desc)
 {
@@ -3502,7 +3518,7 @@
 	struct desc_struct nseg_desc;
 	int ret = 0;
 
-	get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
+	kvm_get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
 
 	if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
 		goto out;
@@ -3561,7 +3577,7 @@
 	kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS);
 	seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
 	tr_seg.type = 11;
-	set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
+	kvm_set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
 out:
 	kvm_x86_ops->decache_regs(vcpu);
 	return ret;
@@ -3628,15 +3644,15 @@
 		}
 	}
 
-	set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
-	set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
-	set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
-	set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
-	set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
-	set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+	kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+	kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+	kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+	kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+	kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+	kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
 
-	set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
-	set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+	kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+	kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
 
 	vcpu_put(vcpu);
 
@@ -3751,14 +3767,14 @@
 	 * allocate ram with GFP_KERNEL.
 	 */
 	if (!used_math())
-		fx_save(&vcpu->arch.host_fx_image);
+		kvm_fx_save(&vcpu->arch.host_fx_image);
 
 	/* Initialize guest FPU by resetting ours and saving into guest's */
 	preempt_disable();
-	fx_save(&vcpu->arch.host_fx_image);
-	fx_finit();
-	fx_save(&vcpu->arch.guest_fx_image);
-	fx_restore(&vcpu->arch.host_fx_image);
+	kvm_fx_save(&vcpu->arch.host_fx_image);
+	kvm_fx_finit();
+	kvm_fx_save(&vcpu->arch.guest_fx_image);
+	kvm_fx_restore(&vcpu->arch.host_fx_image);
 	preempt_enable();
 
 	vcpu->arch.cr0 |= X86_CR0_ET;
@@ -3775,8 +3791,8 @@
 		return;
 
 	vcpu->guest_fpu_loaded = 1;
-	fx_save(&vcpu->arch.host_fx_image);
-	fx_restore(&vcpu->arch.guest_fx_image);
+	kvm_fx_save(&vcpu->arch.host_fx_image);
+	kvm_fx_restore(&vcpu->arch.guest_fx_image);
 }
 EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
 
@@ -3786,8 +3802,8 @@
 		return;
 
 	vcpu->guest_fpu_loaded = 0;
-	fx_save(&vcpu->arch.guest_fx_image);
-	fx_restore(&vcpu->arch.host_fx_image);
+	kvm_fx_save(&vcpu->arch.guest_fx_image);
+	kvm_fx_restore(&vcpu->arch.host_fx_image);
 	++vcpu->stat.fpu_reload;
 }
 EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
@@ -4016,6 +4032,11 @@
 	return 0;
 }
 
+void kvm_arch_flush_shadow(struct kvm *kvm)
+{
+	kvm_mmu_zap_all(kvm);
+}
+
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c
index 932f216..f2f9046 100644
--- a/arch/x86/kvm/x86_emulate.c
+++ b/arch/x86/kvm/x86_emulate.c
@@ -121,7 +121,7 @@
 	0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
 	0, 0, 0, 0,
 	/* 0x68 - 0x6F */
-	0, 0, ImplicitOps | Mov | Stack, 0,
+	SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
 	SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* insb, insw/insd */
 	SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* outsb, outsw/outsd */
 	/* 0x70 - 0x77 */
@@ -138,9 +138,11 @@
 	/* 0x88 - 0x8F */
 	ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
 	ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	0, ModRM | DstReg, 0, Group | Group1A,
-	/* 0x90 - 0x9F */
-	0, 0, 0, 0, 0, 0, 0, 0,
+	DstMem | SrcReg | ModRM | Mov, ModRM | DstReg,
+	DstReg | SrcMem | ModRM | Mov, Group | Group1A,
+	/* 0x90 - 0x97 */
+	DstReg, DstReg, DstReg, DstReg,	DstReg, DstReg, DstReg, DstReg,
+	/* 0x98 - 0x9F */
 	0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
 	/* 0xA0 - 0xA7 */
 	ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
@@ -152,7 +154,8 @@
 	ByteOp | ImplicitOps | Mov | String, ImplicitOps | Mov | String,
 	ByteOp | ImplicitOps | String, ImplicitOps | String,
 	/* 0xB0 - 0xBF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	DstReg | SrcImm | Mov, 0, 0, 0, 0, 0, 0, 0,
 	/* 0xC0 - 0xC7 */
 	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
 	0, ImplicitOps | Stack, 0, 0,
@@ -168,7 +171,8 @@
 	/* 0xE0 - 0xE7 */
 	0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0xE8 - 0xEF */
-	ImplicitOps | Stack, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps,
+	ImplicitOps | Stack, SrcImm | ImplicitOps,
+	ImplicitOps, SrcImmByte | ImplicitOps,
 	0, 0, 0, 0,
 	/* 0xF0 - 0xF7 */
 	0, 0, 0, 0,
@@ -215,7 +219,7 @@
 	/* 0xA0 - 0xA7 */
 	0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
 	/* 0xA8 - 0xAF */
-	0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
+	0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, ModRM, 0,
 	/* 0xB0 - 0xB7 */
 	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0,
 	    DstMem | SrcReg | ModRM | BitOp,
@@ -518,6 +522,39 @@
 	register_address_increment(c, &c->eip, rel);
 }
 
+static void set_seg_override(struct decode_cache *c, int seg)
+{
+	c->has_seg_override = true;
+	c->seg_override = seg;
+}
+
+static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
+{
+	if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
+		return 0;
+
+	return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg);
+}
+
+static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt,
+				       struct decode_cache *c)
+{
+	if (!c->has_seg_override)
+		return 0;
+
+	return seg_base(ctxt, c->seg_override);
+}
+
+static unsigned long es_base(struct x86_emulate_ctxt *ctxt)
+{
+	return seg_base(ctxt, VCPU_SREG_ES);
+}
+
+static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
+{
+	return seg_base(ctxt, VCPU_SREG_SS);
+}
+
 static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
 			      struct x86_emulate_ops *ops,
 			      unsigned long linear, u8 *dest)
@@ -660,7 +697,7 @@
 {
 	struct decode_cache *c = &ctxt->decode;
 	u8 sib;
-	int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
+	int index_reg = 0, base_reg = 0, scale;
 	int rc = 0;
 
 	if (c->rex_prefix) {
@@ -731,47 +768,28 @@
 		}
 		if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
 		    (c->modrm_rm == 6 && c->modrm_mod != 0))
-			if (!c->override_base)
-				c->override_base = &ctxt->ss_base;
+			if (!c->has_seg_override)
+				set_seg_override(c, VCPU_SREG_SS);
 		c->modrm_ea = (u16)c->modrm_ea;
 	} else {
 		/* 32/64-bit ModR/M decode. */
-		switch (c->modrm_rm) {
-		case 4:
-		case 12:
+		if ((c->modrm_rm & 7) == 4) {
 			sib = insn_fetch(u8, 1, c->eip);
 			index_reg |= (sib >> 3) & 7;
 			base_reg |= sib & 7;
 			scale = sib >> 6;
 
-			switch (base_reg) {
-			case 5:
-				if (c->modrm_mod != 0)
-					c->modrm_ea += c->regs[base_reg];
-				else
-					c->modrm_ea +=
-						insn_fetch(s32, 4, c->eip);
-				break;
-			default:
+			if ((base_reg & 7) == 5 && c->modrm_mod == 0)
+				c->modrm_ea += insn_fetch(s32, 4, c->eip);
+			else
 				c->modrm_ea += c->regs[base_reg];
-			}
-			switch (index_reg) {
-			case 4:
-				break;
-			default:
+			if (index_reg != 4)
 				c->modrm_ea += c->regs[index_reg] << scale;
-			}
-			break;
-		case 5:
-			if (c->modrm_mod != 0)
-				c->modrm_ea += c->regs[c->modrm_rm];
-			else if (ctxt->mode == X86EMUL_MODE_PROT64)
-				rip_relative = 1;
-			break;
-		default:
+		} else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) {
+			if (ctxt->mode == X86EMUL_MODE_PROT64)
+				c->rip_relative = 1;
+		} else
 			c->modrm_ea += c->regs[c->modrm_rm];
-			break;
-		}
 		switch (c->modrm_mod) {
 		case 0:
 			if (c->modrm_rm == 5)
@@ -785,22 +803,6 @@
 			break;
 		}
 	}
-	if (rip_relative) {
-		c->modrm_ea += c->eip;
-		switch (c->d & SrcMask) {
-		case SrcImmByte:
-			c->modrm_ea += 1;
-			break;
-		case SrcImm:
-			if (c->d & ByteOp)
-				c->modrm_ea += 1;
-			else
-				if (c->op_bytes == 8)
-					c->modrm_ea += 4;
-				else
-					c->modrm_ea += c->op_bytes;
-		}
-	}
 done:
 	return rc;
 }
@@ -838,6 +840,7 @@
 
 	memset(c, 0, sizeof(struct decode_cache));
 	c->eip = ctxt->vcpu->arch.rip;
+	ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
 	memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
 
 	switch (mode) {
@@ -876,23 +879,15 @@
 				/* switch between 2/4 bytes */
 				c->ad_bytes = def_ad_bytes ^ 6;
 			break;
-		case 0x2e:	/* CS override */
-			c->override_base = &ctxt->cs_base;
-			break;
-		case 0x3e:	/* DS override */
-			c->override_base = &ctxt->ds_base;
-			break;
 		case 0x26:	/* ES override */
-			c->override_base = &ctxt->es_base;
+		case 0x2e:	/* CS override */
+		case 0x36:	/* SS override */
+		case 0x3e:	/* DS override */
+			set_seg_override(c, (c->b >> 3) & 3);
 			break;
 		case 0x64:	/* FS override */
-			c->override_base = &ctxt->fs_base;
-			break;
 		case 0x65:	/* GS override */
-			c->override_base = &ctxt->gs_base;
-			break;
-		case 0x36:	/* SS override */
-			c->override_base = &ctxt->ss_base;
+			set_seg_override(c, c->b & 7);
 			break;
 		case 0x40 ... 0x4f: /* REX */
 			if (mode != X86EMUL_MODE_PROT64)
@@ -964,15 +959,11 @@
 	if (rc)
 		goto done;
 
-	if (!c->override_base)
-		c->override_base = &ctxt->ds_base;
-	if (mode == X86EMUL_MODE_PROT64 &&
-	    c->override_base != &ctxt->fs_base &&
-	    c->override_base != &ctxt->gs_base)
-		c->override_base = NULL;
+	if (!c->has_seg_override)
+		set_seg_override(c, VCPU_SREG_DS);
 
-	if (c->override_base)
-		c->modrm_ea += *c->override_base;
+	if (!(!c->twobyte && c->b == 0x8d))
+		c->modrm_ea += seg_override_base(ctxt, c);
 
 	if (c->ad_bytes != 8)
 		c->modrm_ea = (u32)c->modrm_ea;
@@ -1049,6 +1040,7 @@
 		break;
 	case DstMem:
 		if ((c->d & ModRM) && c->modrm_mod == 3) {
+			c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 			c->dst.type = OP_REG;
 			c->dst.val = c->dst.orig_val = c->modrm_val;
 			c->dst.ptr = c->modrm_ptr;
@@ -1058,6 +1050,9 @@
 		break;
 	}
 
+	if (c->rip_relative)
+		c->modrm_ea += c->eip;
+
 done:
 	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
 }
@@ -1070,7 +1065,7 @@
 	c->dst.bytes = c->op_bytes;
 	c->dst.val = c->src.val;
 	register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
-	c->dst.ptr = (void *) register_address(c, ctxt->ss_base,
+	c->dst.ptr = (void *) register_address(c, ss_base(ctxt),
 					       c->regs[VCPU_REGS_RSP]);
 }
 
@@ -1080,7 +1075,7 @@
 	struct decode_cache *c = &ctxt->decode;
 	int rc;
 
-	rc = ops->read_std(register_address(c, ctxt->ss_base,
+	rc = ops->read_std(register_address(c, ss_base(ctxt),
 					    c->regs[VCPU_REGS_RSP]),
 			   &c->dst.val, c->dst.bytes, ctxt->vcpu);
 	if (rc != 0)
@@ -1402,11 +1397,11 @@
 		register_address_increment(c, &c->regs[VCPU_REGS_RSP],
 					   -c->op_bytes);
 		c->dst.ptr = (void *) register_address(
-			c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
+			c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]);
 		break;
 	case 0x58 ... 0x5f: /* pop reg */
 	pop_instruction:
-		if ((rc = ops->read_std(register_address(c, ctxt->ss_base,
+		if ((rc = ops->read_std(register_address(c, ss_base(ctxt),
 			c->regs[VCPU_REGS_RSP]), c->dst.ptr,
 			c->op_bytes, ctxt->vcpu)) != 0)
 			goto done;
@@ -1420,9 +1415,8 @@
 			goto cannot_emulate;
 		c->dst.val = (s32) c->src.val;
 		break;
+	case 0x68: /* push imm */
 	case 0x6a: /* push imm8 */
-		c->src.val = 0L;
-		c->src.val = insn_fetch(s8, 1, c->eip);
 		emulate_push(ctxt);
 		break;
 	case 0x6c:		/* insb */
@@ -1433,7 +1427,7 @@
 				c->rep_prefix ?
 				address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
 				(ctxt->eflags & EFLG_DF),
-				register_address(c, ctxt->es_base,
+				register_address(c, es_base(ctxt),
 						 c->regs[VCPU_REGS_RDI]),
 				c->rep_prefix,
 				c->regs[VCPU_REGS_RDX]) == 0) {
@@ -1449,9 +1443,8 @@
 				c->rep_prefix ?
 				address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
 				(ctxt->eflags & EFLG_DF),
-				register_address(c, c->override_base ?
-							*c->override_base :
-							ctxt->ds_base,
+					 register_address(c,
+					  seg_override_base(ctxt, c),
 						 c->regs[VCPU_REGS_RSI]),
 				c->rep_prefix,
 				c->regs[VCPU_REGS_RDX]) == 0) {
@@ -1490,6 +1483,7 @@
 		emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x86 ... 0x87:	/* xchg */
+	xchg:
 		/* Write back the register source. */
 		switch (c->dst.bytes) {
 		case 1:
@@ -1514,14 +1508,60 @@
 		break;
 	case 0x88 ... 0x8b:	/* mov */
 		goto mov;
+	case 0x8c: { /* mov r/m, sreg */
+		struct kvm_segment segreg;
+
+		if (c->modrm_reg <= 5)
+			kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
+		else {
+			printk(KERN_INFO "0x8c: Invalid segreg in modrm byte 0x%02x\n",
+			       c->modrm);
+			goto cannot_emulate;
+		}
+		c->dst.val = segreg.selector;
+		break;
+	}
 	case 0x8d: /* lea r16/r32, m */
 		c->dst.val = c->modrm_ea;
 		break;
+	case 0x8e: { /* mov seg, r/m16 */
+		uint16_t sel;
+		int type_bits;
+		int err;
+
+		sel = c->src.val;
+		if (c->modrm_reg <= 5) {
+			type_bits = (c->modrm_reg == 1) ? 9 : 1;
+			err = kvm_load_segment_descriptor(ctxt->vcpu, sel,
+							  type_bits, c->modrm_reg);
+		} else {
+			printk(KERN_INFO "Invalid segreg in modrm byte 0x%02x\n",
+					c->modrm);
+			goto cannot_emulate;
+		}
+
+		if (err < 0)
+			goto cannot_emulate;
+
+		c->dst.type = OP_NONE;  /* Disable writeback. */
+		break;
+	}
 	case 0x8f:		/* pop (sole member of Grp1a) */
 		rc = emulate_grp1a(ctxt, ops);
 		if (rc != 0)
 			goto done;
 		break;
+	case 0x90: /* nop / xchg r8,rax */
+		if (!(c->rex_prefix & 1)) { /* nop */
+			c->dst.type = OP_NONE;
+			break;
+		}
+	case 0x91 ... 0x97: /* xchg reg,rax */
+		c->src.type = c->dst.type = OP_REG;
+		c->src.bytes = c->dst.bytes = c->op_bytes;
+		c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
+		c->src.val = *(c->src.ptr);
+		goto xchg;
 	case 0x9c: /* pushf */
 		c->src.val =  (unsigned long) ctxt->eflags;
 		emulate_push(ctxt);
@@ -1540,11 +1580,10 @@
 		c->dst.type = OP_MEM;
 		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->dst.ptr = (unsigned long *)register_address(c,
-						   ctxt->es_base,
+						   es_base(ctxt),
 						   c->regs[VCPU_REGS_RDI]);
 		if ((rc = ops->read_emulated(register_address(c,
-		      c->override_base ? *c->override_base :
-					ctxt->ds_base,
+					   seg_override_base(ctxt, c),
 					c->regs[VCPU_REGS_RSI]),
 					&c->dst.val,
 					c->dst.bytes, ctxt->vcpu)) != 0)
@@ -1560,8 +1599,7 @@
 		c->src.type = OP_NONE; /* Disable writeback. */
 		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->src.ptr = (unsigned long *)register_address(c,
-				c->override_base ? *c->override_base :
-						   ctxt->ds_base,
+				       seg_override_base(ctxt, c),
 						   c->regs[VCPU_REGS_RSI]);
 		if ((rc = ops->read_emulated((unsigned long)c->src.ptr,
 						&c->src.val,
@@ -1572,7 +1610,7 @@
 		c->dst.type = OP_NONE; /* Disable writeback. */
 		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->dst.ptr = (unsigned long *)register_address(c,
-						   ctxt->es_base,
+						   es_base(ctxt),
 						   c->regs[VCPU_REGS_RDI]);
 		if ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
 						&c->dst.val,
@@ -1596,7 +1634,7 @@
 		c->dst.type = OP_MEM;
 		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->dst.ptr = (unsigned long *)register_address(c,
-						   ctxt->es_base,
+						   es_base(ctxt),
 						   c->regs[VCPU_REGS_RDI]);
 		c->dst.val = c->regs[VCPU_REGS_RAX];
 		register_address_increment(c, &c->regs[VCPU_REGS_RDI],
@@ -1608,8 +1646,7 @@
 		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
 		if ((rc = ops->read_emulated(register_address(c,
-				c->override_base ? *c->override_base :
-						   ctxt->ds_base,
+						 seg_override_base(ctxt, c),
 						 c->regs[VCPU_REGS_RSI]),
 						 &c->dst.val,
 						 c->dst.bytes,
@@ -1622,6 +1659,8 @@
 	case 0xae ... 0xaf:	/* scas */
 		DPRINTF("Urk! I don't handle SCAS.\n");
 		goto cannot_emulate;
+	case 0xb8: /* mov r, imm */
+		goto mov;
 	case 0xc0 ... 0xc1:
 		emulate_grp2(ctxt);
 		break;
@@ -1660,13 +1699,39 @@
 		break;
 	}
 	case 0xe9: /* jmp rel */
-	case 0xeb: /* jmp rel short */
+		goto jmp;
+	case 0xea: /* jmp far */ {
+		uint32_t eip;
+		uint16_t sel;
+
+		switch (c->op_bytes) {
+		case 2:
+			eip = insn_fetch(u16, 2, c->eip);
+			break;
+		case 4:
+			eip = insn_fetch(u32, 4, c->eip);
+			break;
+		default:
+			DPRINTF("jmp far: Invalid op_bytes\n");
+			goto cannot_emulate;
+		}
+		sel = insn_fetch(u16, 2, c->eip);
+		if (kvm_load_segment_descriptor(ctxt->vcpu, sel, 9, VCPU_SREG_CS) < 0) {
+			DPRINTF("jmp far: Failed to load CS descriptor\n");
+			goto cannot_emulate;
+		}
+
+		c->eip = eip;
+		break;
+	}
+	case 0xeb:
+	      jmp:		/* jmp rel short */
 		jmp_rel(c, c->src.val);
 		c->dst.type = OP_NONE; /* Disable writeback. */
 		break;
 	case 0xf4:              /* hlt */
 		ctxt->vcpu->arch.halt_request = 1;
-		goto done;
+		break;
 	case 0xf5:	/* cmc */
 		/* complement carry flag from eflags reg */
 		ctxt->eflags ^= EFLG_CF;
@@ -1882,6 +1947,8 @@
 		c->src.val &= (c->dst.bytes << 3) - 1;
 		emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags);
 		break;
+	case 0xae:              /* clflush */
+		break;
 	case 0xb0 ... 0xb1:	/* cmpxchg */
 		/*
 		 * Save real source value, then compare EAX against
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index e6caf5d..61b6c5b 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -380,9 +380,6 @@
 	if (acpi_disabled)
 		return -ENODEV;
 
-	if (acpi_disabled)
-		return -ENODEV;
-
 	/* look for dockable drive bays */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 		ACPI_UINT32_MAX, find_bay, &bays, NULL);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 1e872e7..bb7c51f 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -920,9 +920,6 @@
 	if (acpi_disabled)
 		return 0;
 
-	if (acpi_disabled)
-		return 0;
-
 	/* look for a dock station */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 			    ACPI_UINT32_MAX, find_dock, &num, NULL);
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 0f2dd81..2f173e8 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -338,9 +338,6 @@
 	if (acpi_disabled)
 		return 0;
 
-	if (acpi_disabled)
-		return 0;
-
 	if (dev) {
 		rtc_wake_setup();
 		rtc_info.wake_on = rtc_wake_on;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 4249950..49f2741 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1880,11 +1880,11 @@
 
 	if (!MACH_IS_ATARI)
 		/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
-		return -ENXIO;
+		return -ENODEV;
 
 	if (MACH_IS_HADES)
 		/* Hades doesn't have Atari-compatible floppy */
-		return -ENXIO;
+		return -ENODEV;
 
 	if (register_blkdev(FLOPPY_MAJOR,"fd"))
 		return -EBUSY;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index e5cd856..69df187 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -282,8 +282,8 @@
 	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
 	   open path is before the ldisc is referencable */
 
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	if (tty->ldisc.ops->flush_buffer)
+		tty->ldisc.ops->flush_buffer(tty);
 	tty_driver_flush_buffer(tty);
 
 	return 0;
@@ -514,7 +514,7 @@
 
 static int __init hci_uart_init(void)
 {
-	static struct tty_ldisc hci_uart_ldisc;
+	static struct tty_ldisc_ops hci_uart_ldisc;
 	int err;
 
 	BT_INFO("HCI UART driver ver %s", VERSION);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 6bff9d8..e991dc8 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -762,7 +762,7 @@
 /*
  * This is used to look up the divisor speeds and the timeouts
  * We're normally limited to 15 distinct baud rates.  The extra
- * are accessed via settings in info->flags.
+ * are accessed via settings in info->port.flags.
  *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
  *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
  *                                               HI            VHI
@@ -1003,7 +1003,7 @@
 	cy_writeb(base_addr + (CyCAR << index), save_xir);
 
 	/* if there is nowhere to put the data, discard it */
-	if (info->tty == NULL) {
+	if (info->port.tty == NULL) {
 		if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
 				CyIVRRxEx) {	/* exception */
 			data = readb(base_addr + (CyRDSR << index));
@@ -1015,7 +1015,7 @@
 		goto end;
 	}
 	/* there is an open port for this data */
-	tty = info->tty;
+	tty = info->port.tty;
 	if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
 			CyIVRRxEx) {	/* exception */
 		data = readb(base_addr + (CyRDSR << index));
@@ -1041,7 +1041,7 @@
 						readb(base_addr + (CyRDSR <<
 							index)), TTY_BREAK);
 					info->icount.rx++;
-					if (info->flags & ASYNC_SAK)
+					if (info->port.flags & ASYNC_SAK)
 						do_SAK(tty);
 				} else if (data & CyFRAME) {
 					tty_insert_flip_char(tty,
@@ -1145,7 +1145,7 @@
 		goto end;
 	}
 	info = &cinfo->ports[channel + chip * 4];
-	if (info->tty == NULL) {
+	if (info->port.tty == NULL) {
 		cy_writeb(base_addr + (CySRER << index),
 			  readb(base_addr + (CySRER << index)) & ~CyTxRdy);
 		goto end;
@@ -1190,13 +1190,13 @@
 			}
 			goto done;
 		}
-		if (info->xmit_buf == NULL) {
+		if (info->port.xmit_buf == NULL) {
 			cy_writeb(base_addr + (CySRER << index),
 				readb(base_addr + (CySRER << index)) &
 					~CyTxRdy);
 			goto done;
 		}
-		if (info->tty->stopped || info->tty->hw_stopped) {
+		if (info->port.tty->stopped || info->port.tty->hw_stopped) {
 			cy_writeb(base_addr + (CySRER << index),
 				readb(base_addr + (CySRER << index)) &
 					~CyTxRdy);
@@ -1211,7 +1211,7 @@
 		 * character. This is necessary because there may not be room
 		 * for the two chars needed to send a NULL.)
 		 */
-		outch = info->xmit_buf[info->xmit_tail];
+		outch = info->port.xmit_buf[info->xmit_tail];
 		if (outch) {
 			info->xmit_cnt--;
 			info->xmit_tail = (info->xmit_tail + 1) &
@@ -1232,7 +1232,7 @@
 	}
 
 done:
-	tty_wakeup(info->tty);
+	tty_wakeup(info->port.tty);
 end:
 	/* end of service */
 	cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
@@ -1256,7 +1256,7 @@
 	mdm_change = readb(base_addr + (CyMISR << index));
 	mdm_status = readb(base_addr + (CyMSVR1 << index));
 
-	if (!info->tty)
+	if (!info->port.tty)
 		goto end;
 
 	if (mdm_change & CyANY_DELTA) {
@@ -1273,29 +1273,29 @@
 		wake_up_interruptible(&info->delta_msr_wait);
 	}
 
-	if ((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)) {
+	if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
 		if (!(mdm_status & CyDCD)) {
-			tty_hangup(info->tty);
-			info->flags &= ~ASYNC_NORMAL_ACTIVE;
+			tty_hangup(info->port.tty);
+			info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
-	if ((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)) {
-		if (info->tty->hw_stopped) {
+	if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
+		if (info->port.tty->hw_stopped) {
 			if (mdm_status & CyCTS) {
 				/* cy_start isn't used
 				   because... !!! */
-				info->tty->hw_stopped = 0;
+				info->port.tty->hw_stopped = 0;
 				cy_writeb(base_addr + (CySRER << index),
 					readb(base_addr + (CySRER << index)) |
 						CyTxRdy);
-				tty_wakeup(info->tty);
+				tty_wakeup(info->port.tty);
 			}
 		} else {
 			if (!(mdm_status & CyCTS)) {
 				/* cy_stop isn't used
 				   because ... !!! */
-				info->tty->hw_stopped = 1;
+				info->port.tty->hw_stopped = 1;
 				cy_writeb(base_addr + (CySRER << index),
 					readb(base_addr + (CySRER << index)) &
 						~CyTxRdy);
@@ -1449,7 +1449,7 @@
 		struct BUF_CTRL __iomem *buf_ctrl)
 {
 	struct cyclades_card *cinfo = info->card;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	unsigned int char_count;
 	int len;
 #ifdef BLOCKMOVE
@@ -1542,7 +1542,7 @@
 		struct BUF_CTRL __iomem *buf_ctrl)
 {
 	struct cyclades_card *cinfo = info->card;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	u8 data;
 	unsigned int char_count;
 #ifdef BLOCKMOVE
@@ -1585,7 +1585,7 @@
 
 			memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
 					tx_put),
-					&info->xmit_buf[info->xmit_tail],
+					&info->port.xmit_buf[info->xmit_tail],
 					small_count);
 
 			tx_put = (tx_put + small_count) & (tx_bufsize - 1);
@@ -1597,7 +1597,7 @@
 		}
 #else
 		while (info->xmit_cnt && char_count) {
-			data = info->xmit_buf[info->xmit_tail];
+			data = info->port.xmit_buf[info->xmit_tail];
 			info->xmit_cnt--;
 			info->xmit_tail = (info->xmit_tail + 1) &
 					(SERIAL_XMIT_SIZE - 1);
@@ -1642,7 +1642,7 @@
 		special_count = 0;
 		delta_count = 0;
 		info = &cinfo->ports[channel];
-		tty = info->tty;
+		tty = info->port.tty;
 		if (tty == NULL)
 			continue;
 
@@ -1668,15 +1668,15 @@
 		case C_CM_MDCD:
 			info->icount.dcd++;
 			delta_count++;
-			if (info->flags & ASYNC_CHECK_CD) {
+			if (info->port.flags & ASYNC_CHECK_CD) {
 				if ((fw_ver > 241 ? ((u_long) param) :
 						readl(&ch_ctrl->rs_status)) &
 						C_RS_DCD) {
-					wake_up_interruptible(&info->open_wait);
+					wake_up_interruptible(&info->port.open_wait);
 				} else {
-					tty_hangup(info->tty);
-					wake_up_interruptible(&info->open_wait);
-					info->flags &= ~ASYNC_NORMAL_ACTIVE;
+					tty_hangup(info->port.tty);
+					wake_up_interruptible(&info->port.open_wait);
+					info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 				}
 			}
 			break;
@@ -1814,7 +1814,7 @@
 
 		for (port = 0; port < cinfo->nports; port++) {
 			info = &cinfo->ports[port];
-			tty = info->tty;
+			tty = info->port.tty;
 			buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
 
 			if (!info->throttle)
@@ -1853,22 +1853,22 @@
 
 	spin_lock_irqsave(&card->card_lock, flags);
 
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
 		free_page(page);
 		goto errout;
 	}
 
 	if (!info->type) {
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		free_page(page);
 		goto errout;
 	}
 
-	if (info->xmit_buf)
+	if (info->port.xmit_buf)
 		free_page(page);
 	else
-		info->xmit_buf = (unsigned char *)page;
+		info->port.xmit_buf = (unsigned char *)page;
 
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -1909,10 +1909,10 @@
 
 		cy_writeb(base_addr + (CySRER << index),
 			readb(base_addr + (CySRER << index)) | CyRxData);
-		info->flags |= ASYNC_INITIALIZED;
+		info->port.flags |= ASYNC_INITIALIZED;
 
-		if (info->tty)
-			clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 		info->breakon = info->breakoff = 0;
 		memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -1994,9 +1994,9 @@
 
 		/* enable send, recv, modem !!! */
 
-		info->flags |= ASYNC_INITIALIZED;
-		if (info->tty)
-			clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		info->port.flags |= ASYNC_INITIALIZED;
+		if (info->port.tty)
+			clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 		info->breakon = info->breakoff = 0;
 		memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -2065,7 +2065,7 @@
 	void __iomem *base_addr;
 	int chip, channel, index;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	card = info->card;
@@ -2087,14 +2087,14 @@
 		/* Clear delta_msr_wait queue to avoid mem leaks. */
 		wake_up_interruptible(&info->delta_msr_wait);
 
-		if (info->xmit_buf) {
+		if (info->port.xmit_buf) {
 			unsigned char *temp;
-			temp = info->xmit_buf;
-			info->xmit_buf = NULL;
+			temp = info->port.xmit_buf;
+			info->port.xmit_buf = NULL;
 			free_page((unsigned long)temp);
 		}
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
-		if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
 			cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
 			cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
 #ifdef CY_DEBUG_DTR
@@ -2108,9 +2108,9 @@
 		/* it may be appropriate to clear _XMIT at
 		   some later date (after testing)!!! */
 
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
-		info->flags &= ~ASYNC_INITIALIZED;
+		if (info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+		info->port.flags &= ~ASYNC_INITIALIZED;
 		spin_unlock_irqrestore(&card->card_lock, flags);
 	} else {
 		struct FIRM_ID __iomem *firm_id;
@@ -2136,14 +2136,14 @@
 
 		spin_lock_irqsave(&card->card_lock, flags);
 
-		if (info->xmit_buf) {
+		if (info->port.xmit_buf) {
 			unsigned char *temp;
-			temp = info->xmit_buf;
-			info->xmit_buf = NULL;
+			temp = info->port.xmit_buf;
+			info->port.xmit_buf = NULL;
 			free_page((unsigned long)temp);
 		}
 
-		if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
 			cy_writel(&ch_ctrl[channel].rs_control,
 				(__u32)(readl(&ch_ctrl[channel].rs_control) &
 					~(C_RS_RTS | C_RS_DTR)));
@@ -2158,9 +2158,9 @@
 #endif
 		}
 
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
-		info->flags &= ~ASYNC_INITIALIZED;
+		if (info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+		info->port.flags &= ~ASYNC_INITIALIZED;
 
 		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
@@ -2194,10 +2194,10 @@
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
 	 */
-	if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible(info->close_wait,
-				!(info->flags & ASYNC_CLOSING));
-		return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
+		wait_event_interruptible(info->port.close_wait,
+				!(info->port.flags & ASYNC_CLOSING));
+		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
 
 	/*
@@ -2206,32 +2206,32 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 					(tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
+	 * this loop, info->port.count is dropped by one, so that
 	 * cy_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 #ifdef CY_DEBUG_OPEN
 	printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
-		"count = %d\n", info->line, info->count);
+		"count = %d\n", info->line, info->port.count);
 #endif
 	spin_lock_irqsave(&cinfo->card_lock, flags);
 	if (!tty_hung_up_p(filp))
-		info->count--;
+		info->port.count--;
 	spin_unlock_irqrestore(&cinfo->card_lock, flags);
 #ifdef CY_DEBUG_COUNT
 	printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
-		"%d\n", current->pid, info->count);
+		"%d\n", current->pid, info->port.count);
 #endif
-	info->blocked_open++;
+	info->port.blocked_open++;
 
 	if (!IS_CYC_Z(*cinfo)) {
 		chip = channel >> 2;
@@ -2260,8 +2260,8 @@
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (tty_hung_up_p(filp) ||
-					!(info->flags & ASYNC_INITIALIZED)) {
-				retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+					!(info->port.flags & ASYNC_INITIALIZED)) {
+				retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
 					  -EAGAIN : -ERESTARTSYS);
 				break;
 			}
@@ -2269,7 +2269,7 @@
 			spin_lock_irqsave(&cinfo->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
-			if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+			if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
 					(readb(base_addr +
 						(CyMSVR1 << index)) & CyDCD))) {
 				spin_unlock_irqrestore(&cinfo->card_lock, flags);
@@ -2284,7 +2284,7 @@
 #ifdef CY_DEBUG_OPEN
 			printk(KERN_DEBUG "cyc block_til_ready blocking: "
 				"ttyC%d, count = %d\n",
-				info->line, info->count);
+				info->line, info->port.count);
 #endif
 			schedule();
 		}
@@ -2298,7 +2298,7 @@
 		firm_id = base_addr + ID_ADDRESS;
 		if (!ISZLOADED(*cinfo)) {
 			__set_current_state(TASK_RUNNING);
-			remove_wait_queue(&info->open_wait, &wait);
+			remove_wait_queue(&info->port.open_wait, &wait);
 			return -EINVAL;
 		}
 
@@ -2327,12 +2327,12 @@
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (tty_hung_up_p(filp) ||
-					!(info->flags & ASYNC_INITIALIZED)) {
-				retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+					!(info->port.flags & ASYNC_INITIALIZED)) {
+				retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
 					  -EAGAIN : -ERESTARTSYS);
 				break;
 			}
-			if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+			if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
 					(readl(&ch_ctrl[channel].rs_status) &
 						C_RS_DCD))) {
 				break;
@@ -2344,28 +2344,28 @@
 #ifdef CY_DEBUG_OPEN
 			printk(KERN_DEBUG "cyc block_til_ready blocking: "
 				"ttyC%d, count = %d\n",
-				info->line, info->count);
+				info->line, info->port.count);
 #endif
 			schedule();
 		}
 	}
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp)) {
-		info->count++;
+		info->port.count++;
 #ifdef CY_DEBUG_COUNT
 		printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
-			"count to %d\n", current->pid, info->count);
+			"count to %d\n", current->pid, info->port.count);
 #endif
 	}
-	info->blocked_open--;
+	info->port.blocked_open--;
 #ifdef CY_DEBUG_OPEN
 	printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
-		"count = %d\n", info->line, info->count);
+		"count = %d\n", info->line, info->port.count);
 #endif
 	if (retval)
 		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
+	info->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }				/* block_til_ready */
 
@@ -2456,27 +2456,27 @@
 	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
 #endif
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 	if (serial_paranoia_check(info, tty->name, "cy_open"))
 		return -ENODEV;
 
 #ifdef CY_DEBUG_OPEN
 	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
-			info->count);
+			info->port.count);
 #endif
-	info->count++;
+	info->port.count++;
 #ifdef CY_DEBUG_COUNT
 	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
-		current->pid, info->count);
+		current->pid, info->port.count);
 #endif
 
 	/*
 	 * If the port is the middle of closing, bail out now
 	 */
-	if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible(info->close_wait,
-				!(info->flags & ASYNC_CLOSING));
-		return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
+		wait_event_interruptible(info->port.close_wait,
+				!(info->port.flags & ASYNC_CLOSING));
+		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
 
 	/*
@@ -2641,9 +2641,9 @@
 	}
 #ifdef CY_DEBUG_OPEN
 	printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
-		info->count);
+		info->port.count);
 #endif
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -2652,24 +2652,24 @@
 		 * serial port won't be shutdown.
 		 */
 		printk(KERN_ERR "cyc:cy_close: bad serial port count; "
-			"tty->count is 1, info->count is %d\n", info->count);
-		info->count = 1;
+			"tty->count is 1, info->port.count is %d\n", info->port.count);
+		info->port.count = 1;
 	}
 #ifdef CY_DEBUG_COUNT
 	printk(KERN_DEBUG  "cyc:cy_close at (%d): decrementing count to %d\n",
-		current->pid, info->count - 1);
+		current->pid, info->port.count - 1);
 #endif
-	if (--info->count < 0) {
+	if (--info->port.count < 0) {
 #ifdef CY_DEBUG_COUNT
 		printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
 #endif
-		info->count = 0;
+		info->port.count = 0;
 	}
-	if (info->count) {
+	if (info->port.count) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
 		return;
 	}
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
@@ -2677,8 +2677,8 @@
 	 */
 	tty->closing = 1;
 	spin_unlock_irqrestore(&card->card_lock, flags);
-	if (info->closing_wait != CY_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (info->port.closing_wait != CY_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->port.closing_wait);
 
 	spin_lock_irqsave(&card->card_lock, flags);
 
@@ -2692,7 +2692,7 @@
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 		cy_writeb(base_addr + (CySRER << index),
 			  readb(base_addr + (CySRER << index)) & ~CyRxData);
-		if (info->flags & ASYNC_INITIALIZED) {
+		if (info->port.flags & ASYNC_INITIALIZED) {
 			/* Waiting for on-board buffers to be empty before
 			   closing the port */
 			spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2731,18 +2731,18 @@
 	spin_lock_irqsave(&card->card_lock, flags);
 
 	tty->closing = 0;
-	info->tty = NULL;
-	if (info->blocked_open) {
+	info->port.tty = NULL;
+	if (info->port.blocked_open) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
-		if (info->close_delay) {
+		if (info->port.close_delay) {
 			msleep_interruptible(jiffies_to_msecs
-						(info->close_delay));
+						(info->port.close_delay));
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 		spin_lock_irqsave(&card->card_lock, flags);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+	wake_up_interruptible(&info->port.close_wait);
 
 #ifdef CY_DEBUG_OTHER
 	printk(KERN_DEBUG "cyc:cy_close done\n");
@@ -2777,7 +2777,7 @@
 	if (serial_paranoia_check(info, tty->name, "cy_write"))
 		return 0;
 
-	if (!info->xmit_buf)
+	if (!info->port.xmit_buf)
 		return 0;
 
 	spin_lock_irqsave(&info->card->card_lock, flags);
@@ -2788,7 +2788,7 @@
 		if (c <= 0)
 			break;
 
-		memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
 		info->xmit_head = (info->xmit_head + c) &
 			(SERIAL_XMIT_SIZE - 1);
 		info->xmit_cnt += c;
@@ -2826,7 +2826,7 @@
 	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
 		return 0;
 
-	if (!info->xmit_buf)
+	if (!info->port.xmit_buf)
 		return 0;
 
 	spin_lock_irqsave(&info->card->card_lock, flags);
@@ -2835,7 +2835,7 @@
 		return 0;
 	}
 
-	info->xmit_buf[info->xmit_head++] = ch;
+	info->port.xmit_buf[info->xmit_head++] = ch;
 	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
 	info->xmit_cnt++;
 	info->idle_stats.xmit_bytes++;
@@ -2860,7 +2860,7 @@
 		return;
 
 	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-			!info->xmit_buf)
+			!info->port.xmit_buf)
 		return;
 
 	start_xmit(info);
@@ -2988,27 +2988,27 @@
 	int baud, baud_rate = 0;
 	int i;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
 
 	if (info->line == -1)
 		return;
 
-	cflag = info->tty->termios->c_cflag;
-	iflag = info->tty->termios->c_iflag;
+	cflag = info->port.tty->termios->c_cflag;
+	iflag = info->port.tty->termios->c_iflag;
 
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
+	if (info->port.tty) {
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->port.tty->alt_speed = 57600;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->port.tty->alt_speed = 115200;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->port.tty->alt_speed = 230400;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->port.tty->alt_speed = 460800;
 	}
 
 	card = info->card;
@@ -3020,8 +3020,8 @@
 		index = card->bus_index;
 
 		/* baud rate */
-		baud = tty_get_baud_rate(info->tty);
-		if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+		baud = tty_get_baud_rate(info->port.tty);
+		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
 				ASYNC_SPD_CUST) {
 			if (info->custom_divisor)
 				baud_rate = info->baud / info->custom_divisor;
@@ -3038,7 +3038,7 @@
 		if (i == 20)
 			i = 19;	/* CD1400_MAX_SPEED */
 
-		if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
 				ASYNC_SPD_CUST) {
 			cyy_baud_calc(info, baud_rate);
 		} else {
@@ -3059,7 +3059,7 @@
 			/* get it right for 134.5 baud */
 			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
 					2;
-		} else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
 				ASYNC_SPD_CUST) {
 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
 					baud_rate) + 2;
@@ -3108,16 +3108,16 @@
 
 		/* CTS flow control flag */
 		if (cflag & CRTSCTS) {
-			info->flags |= ASYNC_CTS_FLOW;
+			info->port.flags |= ASYNC_CTS_FLOW;
 			info->cor2 |= CyCtsAE;
 		} else {
-			info->flags &= ~ASYNC_CTS_FLOW;
+			info->port.flags &= ~ASYNC_CTS_FLOW;
 			info->cor2 &= ~CyCtsAE;
 		}
 		if (cflag & CLOCAL)
-			info->flags &= ~ASYNC_CHECK_CD;
+			info->port.flags &= ~ASYNC_CHECK_CD;
 		else
-			info->flags |= ASYNC_CHECK_CD;
+			info->port.flags |= ASYNC_CHECK_CD;
 
 	 /***********************************************
 	    The hardware option, CyRtsAO, presents RTS when
@@ -3146,8 +3146,8 @@
 		/* set line characteristics  according configuration */
 
 		cy_writeb(base_addr + (CySCHR1 << index),
-			  START_CHAR(info->tty));
-		cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty));
+			  START_CHAR(info->port.tty));
+		cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty));
 		cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
 		cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
 		cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
@@ -3163,7 +3163,7 @@
 			(info->default_timeout ? info->default_timeout : 0x02));
 		/* 10ms rx timeout */
 
-		if (C_CLOCAL(info->tty)) {
+		if (C_CLOCAL(info->port.tty)) {
 			/* without modem intr */
 			cy_writeb(base_addr + (CySRER << index),
 				readb(base_addr + (CySRER << index)) | CyMdmCh);
@@ -3226,8 +3226,8 @@
 #endif
 		}
 
-		if (info->tty)
-			clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		spin_unlock_irqrestore(&card->card_lock, flags);
 
 	} else {
@@ -3250,8 +3250,8 @@
 		buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
 
 		/* baud rate */
-		baud = tty_get_baud_rate(info->tty);
-		if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+		baud = tty_get_baud_rate(info->port.tty);
+		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
 				ASYNC_SPD_CUST) {
 			if (info->custom_divisor)
 				baud_rate = info->baud / info->custom_divisor;
@@ -3266,7 +3266,7 @@
 			/* get it right for 134.5 baud */
 			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
 					2;
-		} else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
 				ASYNC_SPD_CUST) {
 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
 					baud_rate) + 2;
@@ -3318,7 +3318,7 @@
 		}
 		/* As the HW flow control is done in firmware, the driver
 		   doesn't need to care about it */
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 
 		/* XON/XOFF/XANY flow control flags */
 		sw_flow = 0;
@@ -3337,9 +3337,9 @@
 
 		/* CD sensitivity */
 		if (cflag & CLOCAL)
-			info->flags &= ~ASYNC_CHECK_CD;
+			info->port.flags &= ~ASYNC_CHECK_CD;
 		else
-			info->flags |= ASYNC_CHECK_CD;
+			info->port.flags |= ASYNC_CHECK_CD;
 
 		if (baud == 0) {	/* baud rate is zero, turn off line */
 			cy_writel(&ch_ctrl->rs_control,
@@ -3361,8 +3361,8 @@
 				"was %x\n", info->line, retval);
 		}
 
-		if (info->tty)
-			clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	}
 }				/* set_line_char */
 
@@ -3381,9 +3381,9 @@
 	tmp.port = (info->card - cy_card) * 0x100 + info->line -
 		cinfo->first_line;
 	tmp.irq = cinfo->irq;
-	tmp.flags = info->flags;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
+	tmp.flags = info->port.flags;
+	tmp.close_delay = info->port.close_delay;
+	tmp.closing_wait = info->port.closing_wait;
 	tmp.baud_base = info->baud;
 	tmp.custom_divisor = info->custom_divisor;
 	tmp.hub6 = 0;		/*!!! */
@@ -3402,13 +3402,13 @@
 	old_info = *info;
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if (new_serial.close_delay != info->close_delay ||
+		if (new_serial.close_delay != info->port.close_delay ||
 				new_serial.baud_base != info->baud ||
 				(new_serial.flags & ASYNC_FLAGS &
 					~ASYNC_USR_MASK) !=
-				(info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
+				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
 			return -EPERM;
-		info->flags = (info->flags & ~ASYNC_USR_MASK) |
+		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
 				(new_serial.flags & ASYNC_USR_MASK);
 		info->baud = new_serial.baud_base;
 		info->custom_divisor = new_serial.custom_divisor;
@@ -3422,13 +3422,13 @@
 
 	info->baud = new_serial.baud_base;
 	info->custom_divisor = new_serial.custom_divisor;
-	info->flags = (info->flags & ~ASYNC_FLAGS) |
+	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
 			(new_serial.flags & ASYNC_FLAGS);
-	info->close_delay = new_serial.close_delay * HZ / 100;
-	info->closing_wait = new_serial.closing_wait * HZ / 100;
+	info->port.close_delay = new_serial.close_delay * HZ / 100;
+	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
 
 check_and_exit:
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
 		set_line_char(info);
 		return 0;
 	} else {
@@ -3971,11 +3971,11 @@
 		break;
 #endif				/* CONFIG_CYZ_INTR */
 	case CYSETWAIT:
-		info->closing_wait = (unsigned short)arg * HZ / 100;
+		info->port.closing_wait = (unsigned short)arg * HZ / 100;
 		ret_val = 0;
 		break;
 	case CYGETWAIT:
-		ret_val = info->closing_wait / (HZ / 100);
+		ret_val = info->port.closing_wait / (HZ / 100);
 		break;
 	case TIOCGSERIAL:
 		ret_val = get_serial_info(info, argp);
@@ -4097,7 +4097,7 @@
 	 */
 	if (!(old_termios->c_cflag & CLOCAL) &&
 	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 #endif
 }				/* cy_set_termios */
 
@@ -4326,14 +4326,14 @@
 
 	cy_flush_buffer(tty);
 	shutdown(info);
-	info->count = 0;
+	info->port.count = 0;
 #ifdef CY_DEBUG_COUNT
 	printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
 		current->pid);
 #endif
-	info->tty = NULL;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	wake_up_interruptible(&info->open_wait);
+	info->port.tty = NULL;
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	wake_up_interruptible(&info->port.open_wait);
 }				/* cy_hangup */
 
 /*
@@ -4376,15 +4376,14 @@
 	for (port = cinfo->first_line; port < cinfo->first_line + nports;
 			port++) {
 		info = &cinfo->ports[port - cinfo->first_line];
+		tty_port_init(&info->port);
 		info->magic = CYCLADES_MAGIC;
 		info->card = cinfo;
 		info->line = port;
-		info->flags = STD_COM_FLAGS;
-		info->closing_wait = CLOSING_WAIT_DELAY;
-		info->close_delay = 5 * HZ / 10;
 
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
+		info->port.closing_wait = CLOSING_WAIT_DELAY;
+		info->port.close_delay = 5 * HZ / 10;
+		info->port.flags = STD_COM_FLAGS;
 		init_completion(&info->shutdown_wait);
 		init_waitqueue_head(&info->delta_msr_wait);
 
@@ -5237,7 +5236,7 @@
 		for (j = 0; j < cy_card[i].nports; j++) {
 			info = &cy_card[i].ports[j];
 
-			if (info->count)
+			if (info->port.count)
 				size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
 					"%10lu %8lu %9lu %6ld\n", info->line,
 					(cur_jifs - info->idle_stats.in_use) /
@@ -5246,7 +5245,8 @@
 					HZ, info->idle_stats.recv_bytes,
 					(cur_jifs - info->idle_stats.recv_idle)/
 					HZ, info->idle_stats.overruns,
-					(long)info->tty->ldisc.num);
+					/* FIXME: double check locking */
+					(long)info->port.tty->ldisc.ops->num);
 			else
 				size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
 					"%10lu %8lu %9lu %6ld\n",
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 60a4df7..ac9995f 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -432,7 +432,7 @@
 			spin_unlock_irqrestore(&epca_lock, flags);
 			return;
 		}
-		if (ch->count-- > 1)  {
+		if (ch->port.count-- > 1)  {
 			/* Begin channel is open more than once */
 			/*
 			 * Return without doing anything. Someone might still
@@ -442,19 +442,19 @@
 			return;
 		}
 		/* Port open only once go ahead with shutdown & reset */
-		BUG_ON(ch->count < 0);
+		BUG_ON(ch->port.count < 0);
 
 		/*
 		 * Let the rest of the driver know the channel is being closed.
 		 * This becomes important if an open is attempted before close
 		 * is finished.
 		 */
-		ch->asyncflags |= ASYNC_CLOSING;
+		ch->port.flags |= ASYNC_CLOSING;
 		tty->closing = 1;
 
 		spin_unlock_irqrestore(&epca_lock, flags);
 
-		if (ch->asyncflags & ASYNC_INITIALIZED)  {
+		if (ch->port.flags & ASYNC_INITIALIZED)  {
 			/* Setup an event to indicate when the
 			   transmit buffer empties */
 			setup_empty_event(tty, ch);
@@ -469,17 +469,17 @@
 		spin_lock_irqsave(&epca_lock, flags);
 		tty->closing = 0;
 		ch->event = 0;
-		ch->tty = NULL;
+		ch->port.tty = NULL;
 		spin_unlock_irqrestore(&epca_lock, flags);
 
-		if (ch->blocked_open) {
+		if (ch->port.blocked_open) {
 			if (ch->close_delay)
 				msleep_interruptible(jiffies_to_msecs(ch->close_delay));
-			wake_up_interruptible(&ch->open_wait);
+			wake_up_interruptible(&ch->port.open_wait);
 		}
-		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
+		ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
 					ASYNC_CLOSING);
-		wake_up_interruptible(&ch->close_wait);
+		wake_up_interruptible(&ch->port.close_wait);
 	}
 }
 
@@ -489,7 +489,7 @@
 	struct tty_struct *tty;
 	struct board_chan __iomem *bc;
 
-	if (!(ch->asyncflags & ASYNC_INITIALIZED))
+	if (!(ch->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	spin_lock_irqsave(&epca_lock, flags);
@@ -504,7 +504,7 @@
 	 */
 	if (bc)
 		writeb(0, &bc->idata);
-	tty = ch->tty;
+	tty = ch->port.tty;
 
 	/* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
 	if (tty->termios->c_cflag & HUPCL)  {
@@ -518,7 +518,7 @@
 	 * will have to reinitialized. Set a flag to indicate this.
 	 */
 	/* Prevent future Digi programmed interrupts from coming active */
-	ch->asyncflags &= ~ASYNC_INITIALIZED;
+	ch->port.flags &= ~ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&epca_lock, flags);
 }
 
@@ -538,12 +538,12 @@
 		shutdown(ch);
 
 		spin_lock_irqsave(&epca_lock, flags);
-		ch->tty   = NULL;
+		ch->port.tty   = NULL;
 		ch->event = 0;
-		ch->count = 0;
-		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
+		ch->port.count = 0;
+		ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
 		spin_unlock_irqrestore(&epca_lock, flags);
-		wake_up_interruptible(&ch->open_wait);
+		wake_up_interruptible(&ch->port.open_wait);
 	}
 }
 
@@ -795,7 +795,7 @@
 	unsigned long flags;
 
 	if (tty_hung_up_p(filp)) {
-		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+		if (ch->port.flags & ASYNC_HUP_NOTIFY)
 			retval = -EAGAIN;
 		else
 			retval = -ERESTARTSYS;
@@ -806,10 +806,10 @@
 	 * If the device is in the middle of being closed, then block until
 	 * it's done, and then try again.
 	 */
-	if (ch->asyncflags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&ch->close_wait);
+	if (ch->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&ch->port.close_wait);
 
-		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+		if (ch->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
 			return -ERESTARTSYS;
@@ -820,7 +820,7 @@
 		 * If non-blocking mode is set, then make the check up front
 		 * and then exit.
 		 */
-		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+		ch->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 	if (tty->termios->c_cflag & CLOCAL)
@@ -828,24 +828,24 @@
 	/* Block waiting for the carrier detect and the line to become free */
 
 	retval = 0;
-	add_wait_queue(&ch->open_wait, &wait);
+	add_wait_queue(&ch->port.open_wait, &wait);
 
 	spin_lock_irqsave(&epca_lock, flags);
 	/* We dec count so that pc_close will know when to free things */
 	if (!tty_hung_up_p(filp))
-		ch->count--;
-	ch->blocked_open++;
+		ch->port.count--;
+	ch->port.blocked_open++;
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
-				!(ch->asyncflags & ASYNC_INITIALIZED)) {
-			if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+				!(ch->port.flags & ASYNC_INITIALIZED)) {
+			if (ch->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(ch->asyncflags & ASYNC_CLOSING) &&
+		if (!(ch->port.flags & ASYNC_CLOSING) &&
 			  (do_clocal || (ch->imodem & ch->dcd)))
 			break;
 		if (signal_pending(current)) {
@@ -864,17 +864,17 @@
 	}
 
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&ch->open_wait, &wait);
+	remove_wait_queue(&ch->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp))
-		ch->count++;
-	ch->blocked_open--;
+		ch->port.count++;
+	ch->port.blocked_open--;
 
 	spin_unlock_irqrestore(&epca_lock, flags);
 
 	if (retval)
 		return retval;
 
-	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+	ch->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -933,7 +933,7 @@
 	 * necessary because we do not wish to flush and shutdown the channel
 	 * until the last app holding the channel open, closes it.
 	 */
-	ch->count++;
+	ch->port.count++;
 	/*
 	 * Set a kernel structures pointer to our local channel structure. This
 	 * way we can get to it when passed only a tty struct.
@@ -957,14 +957,14 @@
 	writew(head, &bc->rout);
 
 	/* Set the channels associated tty structure */
-	ch->tty = tty;
+	ch->port.tty = tty;
 
 	/*
 	 * The below routine generally sets up parity, baud, flow control
 	 * issues, etc.... It effect both control flags and input flags.
 	 */
 	epcaparam(tty, ch);
-	ch->asyncflags |= ASYNC_INITIALIZED;
+	ch->port.flags |= ASYNC_INITIALIZED;
 	memoff(ch);
 	spin_unlock_irqrestore(&epca_lock, flags);
 
@@ -976,7 +976,7 @@
 	 * waiting for the line...
 	 */
 	spin_lock_irqsave(&epca_lock, flags);
-	ch->tty = tty;
+	ch->port.tty = tty;
 	globalwinon(ch);
 	/* Enable Digi Data events */
 	writeb(1, &bc->idata);
@@ -1017,8 +1017,8 @@
 		}
 		ch = card_ptr[crd];
 		for (count = 0; count < bd->numports; count++, ch++) {
-			if (ch && ch->tty)
-				tty_hangup(ch->tty);
+			if (ch && ch->port.tty)
+				tty_hangup(ch->port.tty);
 		}
 	}
 	pci_unregister_driver(&epca_driver);
@@ -1427,7 +1427,7 @@
 		ch->boardnum   = crd;
 		ch->channelnum = i;
 		ch->magic      = EPCA_MAGIC;
-		ch->tty        = NULL;
+		ch->port.tty        = NULL;
 
 		if (shrinkmem) {
 			fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
@@ -1510,10 +1510,10 @@
 		ch->fepstopca = 0;
 
 		ch->close_delay = 50;
-		ch->count = 0;
-		ch->blocked_open = 0;
-		init_waitqueue_head(&ch->open_wait);
-		init_waitqueue_head(&ch->close_wait);
+		ch->port.count = 0;
+		ch->port.blocked_open = 0;
+		init_waitqueue_head(&ch->port.open_wait);
+		init_waitqueue_head(&ch->port.close_wait);
 
 		spin_unlock_irqrestore(&epca_lock, flags);
 	}
@@ -1633,15 +1633,15 @@
 		if (event & MODEMCHG_IND) {
 			/* A modem signal change has been indicated */
 			ch->imodem = mstat;
-			if (ch->asyncflags & ASYNC_CHECK_CD) {
+			if (ch->port.flags & ASYNC_CHECK_CD) {
 				/* We are now receiving dcd */
 				if (mstat & ch->dcd)
-					wake_up_interruptible(&ch->open_wait);
+					wake_up_interruptible(&ch->port.open_wait);
 				else	/* No dcd; hangup */
 					pc_sched_event(ch, EPCA_EVENT_HANGUP);
 			}
 		}
-		tty = ch->tty;
+		tty = ch->port.tty;
 		if (tty) {
 			if (event & BREAK_IND) {
 				/* A break has been indicated */
@@ -1880,9 +1880,9 @@
 		 * that the driver will wait on carrier detect.
 		 */
 		if (ts->c_cflag & CLOCAL)
-			ch->asyncflags &= ~ASYNC_CHECK_CD;
+			ch->port.flags &= ~ASYNC_CHECK_CD;
 		else
-			ch->asyncflags |= ASYNC_CHECK_CD;
+			ch->port.flags |= ASYNC_CHECK_CD;
 		mval = ch->m_dtr | ch->m_rts;
 	} /* End CBAUD not detected */
 	iflag = termios2digi_i(ch, ts->c_iflag);
@@ -1972,7 +1972,7 @@
 	globalwinon(ch);
 	if (ch->statusflags & RXSTOPPED)
 		return;
-	tty = ch->tty;
+	tty = ch->port.tty;
 	if (tty)
 		ts = tty->termios;
 	bc = ch->brdchan;
@@ -2032,7 +2032,7 @@
 	globalwinon(ch);
 	writew(tail, &bc->rout);
 	/* Must be called with global data */
-	tty_schedule_flip(ch->tty);
+	tty_schedule_flip(ch->port.tty);
 }
 
 static int info_ioctl(struct tty_struct *tty, struct file *file,
@@ -2262,8 +2262,8 @@
 			tty_wait_until_sent(tty, 0);
 		} else {
 			/* ldisc lock already held in ioctl */
-			if (tty->ldisc.flush_buffer)
-				tty->ldisc.flush_buffer(tty);
+			if (tty->ldisc.ops->flush_buffer)
+				tty->ldisc.ops->flush_buffer(tty);
 		}
 		unlock_kernel();
 		/* Fall Thru */
@@ -2376,7 +2376,7 @@
 
 		if (!(old_termios->c_cflag & CLOCAL) &&
 			 (tty->termios->c_cflag & CLOCAL))
-			wake_up_interruptible(&ch->open_wait);
+			wake_up_interruptible(&ch->port.open_wait);
 
 	} /* End if channel valid */
 }
@@ -2386,13 +2386,13 @@
 	struct channel *ch = container_of(work, struct channel, tqueue);
 	/* Called in response to a modem change event */
 	if (ch && ch->magic == EPCA_MAGIC) {
-		struct tty_struct *tty = ch->tty;
+		struct tty_struct *tty = ch->port.tty;
 
 		if (tty && tty->driver_data) {
 			if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
 				tty_hangup(tty);
-				wake_up_interruptible(&ch->open_wait);
-				ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
+				wake_up_interruptible(&ch->port.open_wait);
+				ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 			}
 		}
 	}
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 3c77c02..d414bf2 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -84,6 +84,7 @@
 struct channel 
 {
 	long   magic;
+	struct tty_port port;
 	unsigned char boardnum;
 	unsigned char channelnum;
 	unsigned char omodem;         /* FEP output modem status     */
@@ -117,10 +118,7 @@
 	unsigned short rxbufhead;
 	unsigned short rxbufsize;
 	int    close_delay;
-	int    count;
-	int    blocked_open;
 	unsigned long  event;
-	int    asyncflags;
 	uint   dev;
 	unsigned long  statusflags;
 	unsigned long  c_iflag;
@@ -132,9 +130,6 @@
 	struct board_info           *board;
 	struct board_chan	    __iomem *brdchan;
 	struct digi_struct          digiext;
-	struct tty_struct           *tty;
-	wait_queue_head_t           open_wait;
-	wait_queue_head_t           close_wait;
 	struct work_struct          tqueue;
 	struct global_data 	    __iomem *mailbox;
 };
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 84840ba..2eaf09f 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -128,9 +128,9 @@
 
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
-				tty->name, info->flags, \
+				tty->name, info->port.flags, \
 				serial_driver.refcount, \
-				info->count, tty->count, s)
+				info->port.count, tty->count, s)
 #else
 #define DBG_CNT(s)
 #endif
@@ -172,13 +172,13 @@
 
 static inline unsigned int serial_in(struct esp_struct *info, int offset)
 {
-	return inb(info->port + offset);
+	return inb(info->io_port + offset);
 }
 
 static inline void serial_out(struct esp_struct *info, int offset,
 			      unsigned char value)
 {
-	outb(value, info->port+offset);
+	outb(value, info->io_port+offset);
 }
 
 /*
@@ -273,7 +273,7 @@
 
 static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	int i;
 	struct esp_pio_buffer *pio_buf;
 	struct esp_pio_buffer *err_buf;
@@ -295,7 +295,7 @@
 
 	for (i = 0; i < num_bytes - 1; i += 2) {
 		*((unsigned short *)(pio_buf->data + i)) =
-			inw(info->port + UART_ESI_RX);
+			inw(info->io_port + UART_ESI_RX);
 		err_buf->data[i] = serial_in(info, UART_ESI_RWS);
 		err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask;
 		err_buf->data[i] &= status_mask;
@@ -308,7 +308,7 @@
 	}
 
 	/* make sure everything is still ok since interrupts were enabled */
-	tty = info->tty;
+	tty = info->port.tty;
 
 	if (!tty) {
 		release_pio_buffer(pio_buf);
@@ -325,7 +325,7 @@
 
 			if (err_buf->data[i] & 0x04) {
 				flag = TTY_BREAK;
-				if (info->flags & ASYNC_SAK)
+				if (info->port.flags & ASYNC_SAK)
 					do_SAK(tty);
 			} else if (err_buf->data[i] & 0x02)
 				flag = TTY_FRAME;
@@ -370,7 +370,7 @@
 static inline void receive_chars_dma_done(struct esp_struct *info,
 					    int status)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	int num_bytes;
 	unsigned long flags;
 
@@ -396,7 +396,7 @@
 			if (status & 0x10) {
 				statflag = TTY_BREAK;
 				(info->icount.brk)++;
-				if (info->flags & ASYNC_SAK)
+				if (info->port.flags & ASYNC_SAK)
 					do_SAK(tty);
 			} else if (status & 0x08) {
 				statflag = TTY_FRAME;
@@ -451,7 +451,7 @@
 
 		for (i = 0; i < space_avail - 1; i += 2) {
 			outw(*((unsigned short *)(pio_buf->data + i)),
-			     info->port + UART_ESI_TX);
+			     info->io_port + UART_ESI_TX);
 		}
 
 		if (space_avail & 0x0001)
@@ -470,8 +470,8 @@
 	}
 
 	if (info->xmit_cnt < WAKEUP_CHARS) {
-		if (info->tty)
-			tty_wakeup(info->tty);
+		if (info->port.tty)
+			tty_wakeup(info->port.tty);
 
 #ifdef SERIAL_DEBUG_INTR
 		printk("THRE...");
@@ -507,8 +507,8 @@
 	info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1);
 
 	if (info->xmit_cnt < WAKEUP_CHARS) {
-		if (info->tty)
-			tty_wakeup(info->tty);
+		if (info->port.tty)
+			tty_wakeup(info->port.tty);
 
 #ifdef SERIAL_DEBUG_INTR
 		printk("THRE...");
@@ -575,18 +575,18 @@
 		wake_up_interruptible(&info->delta_msr_wait);
 	}
 
-	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+	if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
 		printk("ttys%d CD now %s...", info->line,
 		       (status & UART_MSR_DCD) ? "on" : "off");
 #endif
 		if (status & UART_MSR_DCD)
-			wake_up_interruptible(&info->open_wait);
+			wake_up_interruptible(&info->port.open_wait);
 		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
-			tty_hangup(info->tty);
+			tty_hangup(info->port.tty);
 		}
 	}
 }
@@ -609,7 +609,7 @@
 
 	spin_lock(&info->lock);
 
-	if (!info->tty) {
+	if (!info->port.tty) {
 		spin_unlock(&info->lock);
 		return IRQ_NONE;
 	}
@@ -647,7 +647,7 @@
 		num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
 		num_bytes |= serial_in(info, UART_ESI_STAT2);
 
-		num_bytes = tty_buffer_request_room(info->tty, num_bytes);
+		num_bytes = tty_buffer_request_room(info->port.tty, num_bytes);
 
 		if (num_bytes) {
 			if (dma_bytes ||
@@ -661,7 +661,7 @@
 
 	if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
 	    (scratch & 0x02) && (info->IER & UART_IER_THRI)) {
-		if ((info->xmit_cnt <= 0) || info->tty->stopped) {
+		if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
 			info->IER &= ~UART_IER_THRI;
 			serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 			serial_out(info, UART_ESI_CMD2, info->IER);
@@ -782,7 +782,7 @@
 
 	spin_lock_irqsave(&info->lock, flags);
 
-	if (info->flags & ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		goto out;
 
 	if (!info->xmit_buf) {
@@ -806,7 +806,7 @@
 	num_chars |= serial_in(info, UART_ESI_STAT2);
 
 	while (num_chars > 1) {
-		inw(info->port + UART_ESI_RX);
+		inw(info->io_port + UART_ESI_RX);
 		num_chars -= 2;
 	}
 
@@ -834,9 +834,9 @@
 
 	if (retval) {
 		if (capable(CAP_SYS_ADMIN)) {
-			if (info->tty)
+			if (info->port.tty)
 				set_bit(TTY_IO_ERROR,
-					&info->tty->flags);
+					&info->port.tty->flags);
 			retval = 0;
 		}
 		goto out_unlocked;
@@ -874,30 +874,30 @@
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, info->IER);
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	spin_unlock_irqrestore(&info->lock, flags);
 
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
+	if (info->port.tty) {
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->port.tty->alt_speed = 57600;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->port.tty->alt_speed = 115200;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->port.tty->alt_speed = 230400;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->port.tty->alt_speed = 460800;
 	}
 
 	/*
 	 * set the speed of the serial port
 	 */
 	change_speed(info);
-	info->flags |= ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 	return 0;
 
 out:
@@ -914,7 +914,7 @@
 {
 	unsigned long	flags, f;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 #ifdef SERIAL_DEBUG_OPEN
@@ -951,7 +951,7 @@
 
 		while (current_port) {
 			if ((current_port != info) &&
-			    (current_port->flags & ASYNC_INITIALIZED))
+			    (current_port->port.flags & ASYNC_INITIALIZED))
 				break;
 
 			current_port = current_port->next_port;
@@ -974,7 +974,7 @@
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, 0x00);
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
 
 	info->MCR &= ~UART_MCR_OUT2;
@@ -982,10 +982,10 @@
 	serial_out(info, UART_ESI_CMD2, UART_MCR);
 	serial_out(info, UART_ESI_CMD2, info->MCR);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&info->lock, flags);
 }
 
@@ -1002,10 +1002,10 @@
 	unsigned char flow1 = 0, flow2 = 0;
 	unsigned long flags;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
-	cflag = info->tty->termios->c_cflag;
-	port = info->port;
+	cflag = info->port.tty->termios->c_cflag;
+	port = info->io_port;
 
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
@@ -1029,9 +1029,9 @@
 	if (cflag & CMSPAR)
 		cval |= UART_LCR_SPAR;
 #endif
-	baud = tty_get_baud_rate(info->tty);
+	baud = tty_get_baud_rate(info->port.tty);
 	if (baud == 38400 &&
-		((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
 		quot = info->custom_divisor;
 	else {
 		if (baud == 134) /* Special case since 134 is really 134.5 */
@@ -1046,49 +1046,49 @@
 	if (baud) {
 		/* Actual rate */
 		baud = BASE_BAUD/quot;
-		tty_encode_baud_rate(info->tty, baud, baud);
+		tty_encode_baud_rate(info->port.tty, baud, baud);
 	}
 	info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
 
 	/* CTS flow control flag and modem status interrupts */
 	/* info->IER &= ~UART_IER_MSI; */
 	if (cflag & CRTSCTS) {
-		info->flags |= ASYNC_CTS_FLOW;
+		info->port.flags |= ASYNC_CTS_FLOW;
 		/* info->IER |= UART_IER_MSI; */
 		flow1 = 0x04;
 		flow2 = 0x10;
 	} else
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
+		info->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		info->flags |= ASYNC_CHECK_CD;
+		info->port.flags |= ASYNC_CHECK_CD;
 
 	/*
 	 * Set up parity check flag
 	 */
 	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
 		info->read_status_mask |= UART_LSR_BI;
 
 	info->ignore_status_mask = 0;
 #if 0
 	/* This should be safe, but for some broken bits of hardware... */
-	if (I_IGNPAR(info->tty)) {
+	if (I_IGNPAR(info->port.tty)) {
 		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
 		info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
 	}
 #endif
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		info->read_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty)) {
+		if (I_IGNPAR(info->port.tty)) {
 			info->ignore_status_mask |= UART_LSR_OE | \
 				UART_LSR_PE | UART_LSR_FE;
 			info->read_status_mask |= UART_LSR_OE | \
@@ -1096,7 +1096,7 @@
 		}
 	}
 
-	if (I_IXOFF(info->tty))
+	if (I_IXOFF(info->port.tty))
 		flow1 |= 0x81;
 
 	spin_lock_irqsave(&info->lock, flags);
@@ -1116,10 +1116,10 @@
 	serial_out(info, UART_ESI_CMD2, flow2);
 
 	/* set flow control characters (XON/XOFF only) */
-	if (I_IXOFF(info->tty)) {
+	if (I_IXOFF(info->port.tty)) {
 		serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CHARS);
-		serial_out(info, UART_ESI_CMD2, START_CHAR(info->tty));
-		serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->tty));
+		serial_out(info, UART_ESI_CMD2, START_CHAR(info->port.tty));
+		serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->port.tty));
 		serial_out(info, UART_ESI_CMD2, 0x10);
 		serial_out(info, UART_ESI_CMD2, 0x21);
 		switch (cflag & CSIZE) {
@@ -1355,9 +1355,9 @@
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = PORT_16550A;
 	tmp.line = info->line;
-	tmp.port = info->port;
+	tmp.port = info->io_port;
 	tmp.irq = info->irq;
-	tmp.flags = info->flags;
+	tmp.flags = info->port.flags;
 	tmp.xmit_fifo_size = 1024;
 	tmp.baud_base = BASE_BAUD;
 	tmp.close_delay = info->close_delay;
@@ -1407,7 +1407,7 @@
 
 	if ((new_serial.type != PORT_16550A) ||
 	    (new_serial.hub6) ||
-	    (info->port != new_serial.port) ||
+	    (info->io_port != new_serial.port) ||
 	    (new_serial.baud_base != BASE_BAUD) ||
 	    (new_serial.irq > 15) ||
 	    (new_serial.irq < 2) ||
@@ -1425,9 +1425,9 @@
 		if (change_irq ||
 		    (new_serial.close_delay != info->close_delay) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (info->flags & ~ASYNC_USR_MASK)))
+		     (info->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+		info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
 			       (new_serial.flags & ASYNC_USR_MASK));
 		info->custom_divisor = new_serial.custom_divisor;
 	} else {
@@ -1441,9 +1441,9 @@
 				if ((current_async->line >= info->line) &&
 				    (current_async->line < (info->line + 8))) {
 					if (current_async == info) {
-						if (current_async->count > 1)
+						if (current_async->port.count > 1)
 							return -EBUSY;
-					} else if (current_async->count)
+					} else if (current_async->port.count)
 						return -EBUSY;
 				}
 
@@ -1456,7 +1456,7 @@
 		 * At this point, we start making changes.....
 		 */
 
-		info->flags = ((info->flags & ~ASYNC_FLAGS) |
+		info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
 			       (new_serial.flags & ASYNC_FLAGS));
 		info->custom_divisor = new_serial.custom_divisor;
 		info->close_delay = new_serial.close_delay * HZ/100;
@@ -1487,18 +1487,18 @@
 		}
 	}
 
-	if (info->flags & ASYNC_INITIALIZED) {
-		if (((old_info.flags & ASYNC_SPD_MASK) !=
-		     (info->flags & ASYNC_SPD_MASK)) ||
+	if (info->port.flags & ASYNC_INITIALIZED) {
+		if (((old_info.port.flags & ASYNC_SPD_MASK) !=
+		     (info->port.flags & ASYNC_SPD_MASK)) ||
 		    (old_info.custom_divisor != info->custom_divisor)) {
-			if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-				info->tty->alt_speed = 57600;
-			if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-				info->tty->alt_speed = 115200;
-			if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-				info->tty->alt_speed = 230400;
-			if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-				info->tty->alt_speed = 460800;
+			if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->port.tty->alt_speed = 57600;
+			if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->port.tty->alt_speed = 115200;
+			if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->port.tty->alt_speed = 230400;
+			if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->port.tty->alt_speed = 460800;
 			change_speed(info);
 		}
 	} else
@@ -1554,9 +1554,9 @@
 
 			while (current_async) {
 				if (current_async == info) {
-					if (current_async->count > 1)
+					if (current_async->port.count > 1)
 						return -EBUSY;
-				} else if (current_async->count)
+				} else if (current_async->port.count)
 					return -EBUSY;
 
 				current_async = current_async->next_port;
@@ -1578,7 +1578,7 @@
 			spin_unlock_irqrestore(&info->lock, flags);
 		} else {
 			/* DMA mode to PIO mode only */
-			if (info->count > 1)
+			if (info->port.count > 1)
 				return -EBUSY;
 
 			shutdown(info);
@@ -1634,7 +1634,7 @@
 		spin_unlock_irqrestore(&info->lock, flags);
 	}
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		retval = startup(info);
 
 	return retval;
@@ -1917,9 +1917,9 @@
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk(KERN_DEBUG "rs_close ttys%d, count = %d\n",
-						info->line, info->count);
+						info->line, info->port.count);
 #endif
-	if (tty->count == 1 && info->count != 1) {
+	if (tty->count == 1 && info->port.count != 1) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -1927,19 +1927,19 @@
 		 * one, we've got real problems, since it means the
 		 * serial port won't be shutdown.
 		 */
-		printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
-		info->count = 1;
+		printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->port.count is %d\n", info->port.count);
+		info->port.count = 1;
 	}
-	if (--info->count < 0) {
+	if (--info->port.count < 0) {
 		printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
+		       info->line, info->port.count);
+		info->port.count = 0;
 	}
-	if (info->count) {
+	if (info->port.count) {
 		DBG_CNT("before DEC-2");
 		goto out;
 	}
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 
 	spin_unlock_irqrestore(&info->lock, flags);
 	/*
@@ -1958,7 +1958,7 @@
 	/* info->IER &= ~UART_IER_RLSI; */
 	info->IER &= ~UART_IER_RDI;
 	info->read_status_mask &= ~UART_LSR_DR;
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
 
 		spin_lock_irqsave(&info->lock, flags);
 		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
@@ -1981,15 +1981,15 @@
 	rs_flush_buffer(tty);
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
-	if (info->blocked_open) {
+	if (info->port.blocked_open) {
 		if (info->close_delay)
 			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&info->port.close_wait);
 	return;
 
 out:
@@ -2047,10 +2047,10 @@
 
 	rs_flush_buffer(tty);
 	shutdown(info);
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	info->port.count = 0;
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->port.tty = NULL;
+	wake_up_interruptible(&info->port.open_wait);
 }
 
 /*
@@ -2071,11 +2071,11 @@
 	 * until it's done, and then try again.
 	 */
 	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
+	    (info->port.flags & ASYNC_CLOSING)) {
+		if (info->port.flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->port.close_wait);
 #ifdef SERIAL_DO_RESTART
-		if (info->flags & ASYNC_HUP_NOTIFY)
+		if (info->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
 			return -ERESTARTSYS;
@@ -2090,7 +2090,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -2100,20 +2100,20 @@
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
+	 * this loop, info->port.count is dropped by one, so that
 	 * rs_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 #ifdef SERIAL_DEBUG_OPEN
 	printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
-	       info->line, info->count);
+	       info->line, info->port.count);
 #endif
 	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp))
-		info->count--;
-	info->blocked_open++;
+		info->port.count--;
+	info->port.blocked_open++;
 	while (1) {
 		if ((tty->termios->c_cflag & CBAUD)) {
 			unsigned int scratch;
@@ -2128,9 +2128,9 @@
 		}
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
+		    !(info->port.flags & ASYNC_INITIALIZED)) {
 #ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
+			if (info->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
@@ -2144,7 +2144,7 @@
 		if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
 			do_clocal = 1;
 
-		if (!(info->flags & ASYNC_CLOSING) &&
+		if (!(info->port.flags & ASYNC_CLOSING) &&
 		    (do_clocal))
 			break;
 		if (signal_pending(current)) {
@@ -2153,25 +2153,25 @@
 		}
 #ifdef SERIAL_DEBUG_OPEN
 		printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
-		       info->line, info->count);
+		       info->line, info->port.count);
 #endif
 		spin_unlock_irqrestore(&info->lock, flags);
 		schedule();
 		spin_lock_irqsave(&info->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
+		info->port.count++;
+	info->port.blocked_open--;
 	spin_unlock_irqrestore(&info->lock, flags);
 #ifdef SERIAL_DEBUG_OPEN
 	printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
-	       info->line, info->count);
+	       info->line, info->port.count);
 #endif
 	if (retval)
 		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
+	info->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -2204,12 +2204,12 @@
 	}
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count);
+	printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->port.count);
 #endif
 	spin_lock_irqsave(&info->lock, flags);
-	info->count++;
+	info->port.count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
 	spin_unlock_irqrestore(&info->lock, flags);
 
@@ -2263,7 +2263,7 @@
 	int port_detected = 0;
 	unsigned long flags;
 
-	if (!request_region(info->port, REGION_SIZE, "esp serial"))
+	if (!request_region(info->io_port, REGION_SIZE, "esp serial"))
 		return -EIO;
 
 	spin_lock_irqsave(&info->lock, flags);
@@ -2300,7 +2300,7 @@
 		}
 	}
 	if (!port_detected)
-		release_region(info->port, REGION_SIZE);
+		release_region(info->io_port, REGION_SIZE);
 
 	spin_unlock_irqrestore(&info->lock, flags);
 	return (port_detected);
@@ -2414,7 +2414,7 @@
 	offset = 0;
 
 	do {
-		info->port = esp[i] + offset;
+		info->io_port = esp[i] + offset;
 		info->irq = irq[i];
 		info->line = (i * 8) + (offset / 8);
 
@@ -2425,9 +2425,9 @@
 		}
 
 		info->custom_divisor = (divisor[i] >> (offset / 2)) & 0xf;
-		info->flags = STD_COM_FLAGS;
+		info->port.flags = STD_COM_FLAGS;
 		if (info->custom_divisor)
-			info->flags |= ASYNC_SPD_CUST;
+			info->port.flags |= ASYNC_SPD_CUST;
 		info->magic = ESP_MAGIC;
 		info->close_delay = 5*HZ/10;
 		info->closing_wait = 30*HZ;
@@ -2436,13 +2436,13 @@
 		info->config.flow_off = flow_off;
 		info->config.pio_threshold = pio_threshold;
 		info->next_port = ports;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
+		init_waitqueue_head(&info->port.open_wait);
+		init_waitqueue_head(&info->port.close_wait);
 		init_waitqueue_head(&info->delta_msr_wait);
 		init_waitqueue_head(&info->break_wait);
 		ports = info;
 		printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
-			info->line, info->port, info->irq);
+			info->line, info->io_port, info->irq);
 
 		if (info->line % 8) {
 			printk("secondary port\n");
@@ -2498,8 +2498,8 @@
 	put_tty_driver(esp_driver);
 
 	while (ports) {
-		if (ports->port)
-			release_region(ports->port, REGION_SIZE);
+		if (ports->io_port)
+			release_region(ports->io_port, REGION_SIZE);
 		temp_async = ports->next_port;
 		kfree(ports);
 		ports = temp_async;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 252f73e..19d3afb 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -60,7 +60,7 @@
 
 	if (!port) return 0;
 
-	if (! (port->flags & ASYNC_INITIALIZED)) return 0;
+	if (! (port->port.flags & ASYNC_INITIALIZED)) return 0;
 
 	/* Take a lock on the serial tranmit buffer! */
 	mutex_lock(& port->port_write_mutex);
@@ -103,7 +103,7 @@
 
 	if (!port) return 0;
 
-	if (! (port->flags & ASYNC_INITIALIZED))
+	if (! (port->port.flags & ASYNC_INITIALIZED))
 		return 0;
 
 	/* get exclusive "write" access to this port (problem 3) */
@@ -141,13 +141,13 @@
 	mutex_unlock(& port->port_write_mutex);
 
 	gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", 
-	            (port->flags & GS_TX_INTEN)?"enabled": "disabled"); 
+	            (port->port.flags & GS_TX_INTEN)?"enabled": "disabled");
 
 	if (port->xmit_cnt && 
 	    !tty->stopped && 
 	    !tty->hw_stopped &&
-	    !(port->flags & GS_TX_INTEN)) {
-		port->flags |= GS_TX_INTEN;
+	    !(port->port.flags & GS_TX_INTEN)) {
+		port->port.flags |= GS_TX_INTEN;
 		port->rd->enable_tx_interrupts (port);
 	}
 	func_exit ();
@@ -208,7 +208,7 @@
 	gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port);
 	if (port) {
 		gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", 
-		port->xmit_cnt, port->xmit_buf, port->tty);
+		port->xmit_cnt, port->xmit_buf, port->port.tty);
 	}
 
 	if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
@@ -217,7 +217,7 @@
 		return -EINVAL;  /* This is an error which we don't know how to handle. */
 	}
 
-	rcib = gs_real_chars_in_buffer(port->tty);
+	rcib = gs_real_chars_in_buffer(port->port.tty);
 
 	if(rcib <= 0) {
 		gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
@@ -236,7 +236,7 @@
 
 	/* the expression is actually jiffies < end_jiffies, but that won't
 	   work around the wraparound. Tricky eh? */
-	while ((charsleft = gs_real_chars_in_buffer (port->tty)) &&
+	while ((charsleft = gs_real_chars_in_buffer (port->port.tty)) &&
 	        time_after (end_jiffies, jiffies)) {
 		/* Units check: 
 		   chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
@@ -309,7 +309,7 @@
 	}
 
 	/* Beats me -- REW */
-	port->flags |= GS_TX_INTEN;
+	port->port.flags |= GS_TX_INTEN;
 	port->rd->enable_tx_interrupts (port);
 	func_exit ();
 }
@@ -329,8 +329,8 @@
 
 	if (port->xmit_cnt && 
 	    port->xmit_buf && 
-	    (port->flags & GS_TX_INTEN) ) {
-		port->flags &= ~GS_TX_INTEN;
+	    (port->port.flags & GS_TX_INTEN) ) {
+		port->port.flags &= ~GS_TX_INTEN;
 		port->rd->disable_tx_interrupts (port);
 	}
 	func_exit ();
@@ -349,8 +349,8 @@
 
 	if (port->xmit_cnt && 
 	    port->xmit_buf && 
-	    !(port->flags & GS_TX_INTEN) ) {
-		port->flags |= GS_TX_INTEN;
+	    !(port->port.flags & GS_TX_INTEN) ) {
+		port->port.flags |= GS_TX_INTEN;
 		port->rd->enable_tx_interrupts (port);
 	}
 	func_exit ();
@@ -365,7 +365,7 @@
 	
 	if (!port) return;
 	
-	if (!(port->flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	spin_lock_irqsave(&port->driver_lock, flags);
@@ -375,12 +375,12 @@
 		port->xmit_buf = NULL;
 	}
 
-	if (port->tty)
-		set_bit(TTY_IO_ERROR, &port->tty->flags);
+	if (port->port.tty)
+		set_bit(TTY_IO_ERROR, &port->port.tty->flags);
 
 	port->rd->shutdown_port (port);
 
-	port->flags &= ~ASYNC_INITIALIZED;
+	port->port.flags &= ~ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&port->driver_lock, flags);
 
 	func_exit();
@@ -396,16 +396,16 @@
 	if (!tty) return;
 
 	port = tty->driver_data;
-	tty = port->tty;
+	tty = port->port.tty;
 	if (!tty) 
 		return;
 
 	gs_shutdown_port (port);
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
-	port->tty = NULL;
-	port->count = 0;
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
+	port->port.tty = NULL;
+	port->port.count = 0;
 
-	wake_up_interruptible(&port->open_wait);
+	wake_up_interruptible(&port->port.open_wait);
 	func_exit ();
 }
 
@@ -424,7 +424,7 @@
 
 	if (!port) return 0;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	if (!tty) return 0;
 
@@ -433,9 +433,9 @@
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
 	 */
-	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&port->close_wait);
-		if (port->flags & ASYNC_HUP_NOTIFY)
+	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->port.close_wait);
+		if (port->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
 			return -ERESTARTSYS;
@@ -449,7 +449,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		port->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -461,34 +461,34 @@
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, port->count is dropped by one, so that
+	 * this loop, port->port.count is dropped by one, so that
 	 * rs_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
 
-	add_wait_queue(&port->open_wait, &wait);
+	add_wait_queue(&port->port.open_wait, &wait);
 
 	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
 	spin_lock_irqsave(&port->driver_lock, flags);
 	if (!tty_hung_up_p(filp)) {
-		port->count--;
+		port->port.count--;
 	}
 	spin_unlock_irqrestore(&port->driver_lock, flags);
-	port->blocked_open++;
+	port->port.blocked_open++;
 	while (1) {
 		CD = port->rd->get_CD (port);
 		gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
 		set_current_state (TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
-		    !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
+		    !(port->port.flags & ASYNC_INITIALIZED)) {
+			if (port->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CLOSING) &&
+		if (!(port->port.flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
@@ -500,17 +500,17 @@
 		schedule();
 	}
 	gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
-		    port->blocked_open);
+		    port->port.blocked_open);
 	set_current_state (TASK_RUNNING);
-	remove_wait_queue(&port->open_wait, &wait);
+	remove_wait_queue(&port->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp)) {
-		port->count++;
+		port->port.count++;
 	}
-	port->blocked_open--;
+	port->port.blocked_open--;
 	if (retval)
 		return retval;
 
-	port->flags |= ASYNC_NORMAL_ACTIVE;
+	port->port.flags |= ASYNC_NORMAL_ACTIVE;
 	func_exit ();
 	return 0;
 }			 
@@ -529,10 +529,10 @@
 
 	if (!port) return;
 
-	if (!port->tty) {
+	if (!port->port.tty) {
 		/* This seems to happen when this is called from vhangup. */
-		gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n");
-		port->tty = tty;
+		gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->port.tty is NULL\n");
+		port->port.tty = tty;
 	}
 
 	spin_lock_irqsave(&port->driver_lock, flags);
@@ -545,23 +545,23 @@
 		return;
 	}
 
-	if ((tty->count == 1) && (port->count != 1)) {
+	if ((tty->count == 1) && (port->port.count != 1)) {
 		printk(KERN_ERR "gs: gs_close port %p: bad port count;"
-		       " tty->count is 1, port count is %d\n", port, port->count);
-		port->count = 1;
+		       " tty->count is 1, port count is %d\n", port, port->port.count);
+		port->port.count = 1;
 	}
-	if (--port->count < 0) {
-		printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count);
-		port->count = 0;
+	if (--port->port.count < 0) {
+		printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->port.count);
+		port->port.count = 0;
 	}
 
-	if (port->count) {
-		gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count);
+	if (port->port.count) {
+		gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count);
 		spin_unlock_irqrestore(&port->driver_lock, flags);
 		func_exit ();
 		return;
 	}
-	port->flags |= ASYNC_CLOSING;
+	port->port.flags |= ASYNC_CLOSING;
 
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
@@ -585,7 +585,7 @@
 	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
 		gs_wait_tx_flushed (port, port->closing_wait);
 
-	port->flags &= ~GS_ACTIVE;
+	port->port.flags &= ~GS_ACTIVE;
 
 	gs_flush_buffer(tty);
 
@@ -595,18 +595,18 @@
 	port->event = 0;
 	port->rd->close (port);
 	port->rd->shutdown_port (port);
-	port->tty = NULL;
+	port->port.tty = NULL;
 
-	if (port->blocked_open) {
+	if (port->port.blocked_open) {
 		if (port->close_delay) {
 			spin_unlock_irqrestore(&port->driver_lock, flags);
 			msleep_interruptible(jiffies_to_msecs(port->close_delay));
 			spin_lock_irqsave(&port->driver_lock, flags);
 		}
-		wake_up_interruptible(&port->open_wait);
+		wake_up_interruptible(&port->port.open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
-	wake_up_interruptible(&port->close_wait);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
+	wake_up_interruptible(&port->port.close_wait);
 
 	func_exit ();
 }
@@ -626,10 +626,10 @@
 	port = tty->driver_data;
 
 	if (!port) return;
-	if (!port->tty) {
+	if (!port->port.tty) {
 		/* This seems to happen when this is called after gs_close. */
-		gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n");
-		port->tty = tty;
+		gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->port.tty is NULL\n");
+		port->port.tty = tty;
 	}
 
 
@@ -651,15 +651,15 @@
 	baudrate = tty_get_baud_rate(tty);
 
 	if ((tiosp->c_cflag & CBAUD) == B38400) {
-		if (     (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if (     (port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			baudrate = 57600;
-		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			baudrate = 115200;
-		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			baudrate = 230400;
-		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			baudrate = 460800;
-		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 			baudrate = (port->baud_base / port->custom_divisor);
 	}
 
@@ -715,7 +715,7 @@
 
 	func_enter ();
 
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (port->port.flags & ASYNC_INITIALIZED) {
 		func_exit ();
 		return 0;
 	}
@@ -737,15 +737,15 @@
 	}
 
 	spin_lock_irqsave (&port->driver_lock, flags);
-	if (port->tty) 
-		clear_bit(TTY_IO_ERROR, &port->tty->flags);
+	if (port->port.tty)
+		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
 	mutex_init(&port->port_write_mutex);
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	spin_unlock_irqrestore(&port->driver_lock, flags);
-	gs_set_termios(port->tty, NULL);
+	gs_set_termios(port->port.tty, NULL);
 	spin_lock_irqsave (&port->driver_lock, flags);
-	port->flags |= ASYNC_INITIALIZED;
-	port->flags &= ~GS_TX_INTEN;
+	port->port.flags |= ASYNC_INITIALIZED;
+	port->port.flags &= ~GS_TX_INTEN;
 
 	spin_unlock_irqrestore(&port->driver_lock, flags);
 	func_exit ();
@@ -764,11 +764,11 @@
 		if ((sio.baud_base != port->baud_base) ||
 		    (sio.close_delay != port->close_delay) ||
 		    ((sio.flags & ~ASYNC_USR_MASK) !=
-		     (port->flags & ~ASYNC_USR_MASK)))
+		     (port->port.flags & ~ASYNC_USR_MASK)))
 			return(-EPERM);
 	} 
 
-	port->flags = (port->flags & ~ASYNC_USR_MASK) |
+	port->port.flags = (port->port.flags & ~ASYNC_USR_MASK) |
 		(sio.flags & ASYNC_USR_MASK);
   
 	port->baud_base = sio.baud_base;
@@ -776,7 +776,7 @@
 	port->closing_wait = sio.closing_wait;
 	port->custom_divisor = sio.custom_divisor;
 
-	gs_set_termios (port->tty, NULL);
+	gs_set_termios (port->port.tty, NULL);
 
 	return 0;
 }
@@ -793,7 +793,7 @@
 	struct serial_struct    sio;
 
 	memset(&sio, 0, sizeof(struct serial_struct));
-	sio.flags = port->flags;
+	sio.flags = port->port.flags;
 	sio.baud_base = port->baud_base;
 	sio.close_delay = port->close_delay;
 	sio.closing_wait = port->closing_wait;
@@ -821,10 +821,10 @@
 {
 	func_enter ();
 
-	tty_insert_flip_char(port->tty, 0, TTY_BREAK);
-	tty_schedule_flip(port->tty);
-	if (port->flags & ASYNC_SAK) {
-		do_SAK (port->tty);
+	tty_insert_flip_char(port->port.tty, 0, TTY_BREAK);
+	tty_schedule_flip(port->port.tty);
+	if (port->port.flags & ASYNC_SAK) {
+		do_SAK (port->port.tty);
 	}
 
 	func_exit ();
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 938879c..0061e18 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -868,11 +868,11 @@
 		amountToMove = count;
 	}
 	// Move the first block
-	pCh->pTTY->ldisc.receive_buf( pCh->pTTY, 
+	pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
 		 &(pCh->Ibuf[stripIndex]), NULL, amountToMove );
 	// If we needed to wrap, do the second data move
 	if (count > amountToMove) {
-		pCh->pTTY->ldisc.receive_buf( pCh->pTTY, 
+		pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
 		 pCh->Ibuf, NULL, count - amountToMove );
 	}
 	// Bump and wrap the stripIndex all at once by the amount of data read. This
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 9a2394c..5dc7440 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -1289,11 +1289,12 @@
 // code duplicated from n_tty (ldisc)
 static inline void  isig(int sig, struct tty_struct *tty, int flush)
 {
+	/* FIXME: This is completely bogus */
 	if (tty->pgrp)
 		kill_pgrp(tty->pgrp, sig, 1);
 	if (flush || !L_NOFLSH(tty)) {
-		if ( tty->ldisc.flush_buffer )  
-			tty->ldisc.flush_buffer(tty);
+		if ( tty->ldisc.ops->flush_buffer )  
+			tty->ldisc.ops->flush_buffer(tty);
 		i2InputFlush( tty->driver_data );
 	}
 }
@@ -1342,7 +1343,7 @@
 		}
 		tmp = pCh->pTTY->real_raw;
 		pCh->pTTY->real_raw = 0;
-		pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
+		pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
 		pCh->pTTY->real_raw = tmp;
 	}
 #endif /* NEVER_HAPPENS_AS_SETUP_XXX */
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 4f3cefa..d4281df 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -198,17 +198,10 @@
 
 struct	isi_port {
 	unsigned short		magic;
-	unsigned int		flags;
-	int			count;
-	int			blocked_open;
-	int			close_delay;
+	struct tty_port		port;
 	u16			channel;
 	u16			status;
-	u16			closing_wait;
 	struct isi_board	*card;
-	struct tty_struct 	*tty;
-	wait_queue_head_t	close_wait;
-	wait_queue_head_t	open_wait;
 	unsigned char		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -430,11 +423,11 @@
 
 	for (; count > 0; count--, port++) {
 		/* port not active or tx disabled to force flow control */
-		if (!(port->flags & ASYNC_INITIALIZED) ||
+		if (!(port->port.flags & ASYNC_INITIALIZED) ||
 				!(port->status & ISI_TXOK))
 			continue;
 
-		tty = port->tty;
+		tty = port->port.tty;
 
 		if (tty == NULL)
 			continue;
@@ -458,7 +451,7 @@
 			if (residue == YES) {
 				residue = NO;
 				if (cnt > 0) {
-					wrd |= (port->xmit_buf[port->xmit_tail]
+					wrd |= (port->port.xmit_buf[port->xmit_tail]
 									<< 8);
 					port->xmit_tail = (port->xmit_tail + 1)
 						& (SERIAL_XMIT_SIZE - 1);
@@ -474,14 +467,14 @@
 			if (cnt <= 0)
 				break;
 			word_count = cnt >> 1;
-			outsw(base, port->xmit_buf+port->xmit_tail, word_count);
+			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
 			port->xmit_tail = (port->xmit_tail
 				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
 			txcount -= (word_count << 1);
 			port->xmit_cnt -= (word_count << 1);
 			if (cnt & 0x0001) {
 				residue = YES;
-				wrd = port->xmit_buf[port->xmit_tail];
+				wrd = port->port.xmit_buf[port->xmit_tail];
 				port->xmit_tail = (port->xmit_tail + 1)
 					& (SERIAL_XMIT_SIZE - 1);
 				port->xmit_cnt--;
@@ -548,13 +541,13 @@
 		return IRQ_HANDLED;
 	}
 	port = card->ports + channel;
-	if (!(port->flags & ASYNC_INITIALIZED)) {
+	if (!(port->port.flags & ASYNC_INITIALIZED)) {
 		outw(0x0000, base+0x04); /* enable interrupts */
 		spin_unlock(&card->card_lock);
 		return IRQ_HANDLED;
 	}
 
-	tty = port->tty;
+	tty = port->port.tty;
 	if (tty == NULL) {
 		word_count = byte_count >> 1;
 		while (byte_count > 1) {
@@ -572,7 +565,7 @@
 		header = inw(base);
 		switch (header & 0xff) {
 		case 0:	/* Change in EIA signals */
-			if (port->flags & ASYNC_CHECK_CD) {
+			if (port->port.flags & ASYNC_CHECK_CD) {
 				if (port->status & ISI_DCD) {
 					if (!(header & ISI_DCD)) {
 					/* Carrier has been lost  */
@@ -585,7 +578,7 @@
 				/* Carrier has been detected */
 					pr_dbg("interrupt: DCD->high.\n");
 					port->status |= ISI_DCD;
-					wake_up_interruptible(&port->open_wait);
+					wake_up_interruptible(&port->port.open_wait);
 				}
 			} else {
 				if (header & ISI_DCD)
@@ -594,17 +587,17 @@
 					port->status &= ~ISI_DCD;
 			}
 
-			if (port->flags & ASYNC_CTS_FLOW) {
-				if (port->tty->hw_stopped) {
+			if (port->port.flags & ASYNC_CTS_FLOW) {
+				if (port->port.tty->hw_stopped) {
 					if (header & ISI_CTS) {
-						port->tty->hw_stopped = 0;
+						port->port.tty->hw_stopped = 0;
 						/* start tx ing */
 						port->status |= (ISI_TXOK
 							| ISI_CTS);
 						tty_wakeup(tty);
 					}
 				} else if (!(header & ISI_CTS)) {
-					port->tty->hw_stopped = 1;
+					port->port.tty->hw_stopped = 1;
 					/* stop tx ing */
 					port->status &= ~(ISI_TXOK | ISI_CTS);
 				}
@@ -629,7 +622,7 @@
 
 		case 1:	/* Received Break !!! */
 			tty_insert_flip_char(tty, 0, TTY_BREAK);
-			if (port->flags & ASYNC_SAK)
+			if (port->port.flags & ASYNC_SAK)
 				do_SAK(tty);
 			tty_flip_buffer_push(tty);
 			break;
@@ -681,7 +674,7 @@
 		shift_count = card->shift_count;
 	unsigned char flow_ctrl;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	if (tty == NULL)
 		return;
@@ -697,7 +690,7 @@
 
 		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
 		if (baud < 1 || baud > 4)
-			port->tty->termios->c_cflag &= ~CBAUDEX;
+			port->port.tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			baud += 15;
 	}
@@ -708,13 +701,13 @@
 		 *  the 'setserial' utility.
 		 */
 
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			baud++; /*  57.6 Kbps */
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			baud += 2; /*  115  Kbps */
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			baud += 3; /* 230 kbps*/
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			baud += 4; /* 460 kbps*/
 	}
 	if (linuxb_to_isib[baud] == -1) {
@@ -754,15 +747,15 @@
 		InterruptTheCard(base);
 	}
 	if (C_CLOCAL(tty))
-		port->flags &= ~ASYNC_CHECK_CD;
+		port->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		port->flags |= ASYNC_CHECK_CD;
+		port->port.flags |= ASYNC_CHECK_CD;
 
 	/* flow control settings ...*/
 	flow_ctrl = 0;
-	port->flags &= ~ASYNC_CTS_FLOW;
+	port->port.flags &= ~ASYNC_CTS_FLOW;
 	if (C_CRTSCTS(tty)) {
-		port->flags |= ASYNC_CTS_FLOW;
+		port->port.flags |= ASYNC_CTS_FLOW;
 		flow_ctrl |= ISICOM_CTSRTS;
 	}
 	if (I_IXON(tty))
@@ -809,23 +802,15 @@
 	struct isi_board *card = port->card;
 	unsigned long flags;
 
-	if (port->flags & ASYNC_INITIALIZED)
+	if (port->port.flags & ASYNC_INITIALIZED)
 		return 0;
-	if (!port->xmit_buf) {
-		/* Relies on BKL */
-		unsigned long page  = get_zeroed_page(GFP_KERNEL);
-		if (page == 0)
-			return -ENOMEM;
-		if (port->xmit_buf)
-			free_page(page);
-		else
-			port->xmit_buf = (unsigned char *) page;
-	}
+	if (tty_port_alloc_xmit_buf(&port->port) < 0)
+		return -ENOMEM;
 
 	spin_lock_irqsave(&card->card_lock, flags);
-	if (port->tty)
-		clear_bit(TTY_IO_ERROR, &port->tty->flags);
-	if (port->count == 1)
+	if (port->port.tty)
+		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	if (port->port.count == 1)
 		card->count++;
 
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
@@ -839,7 +824,7 @@
 	}
 
 	isicom_config_port(port);
-	port->flags |= ASYNC_INITIALIZED;
+	port->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
 	return 0;
@@ -855,10 +840,10 @@
 
 	/* block if port is in the process of being closed */
 
-	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
 		pr_dbg("block_til_ready: close in progress.\n");
-		interruptible_sleep_on(&port->close_wait);
-		if (port->flags & ASYNC_HUP_NOTIFY)
+		interruptible_sleep_on(&port->port.close_wait);
+		if (port->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
 			return -ERESTARTSYS;
@@ -869,7 +854,7 @@
 	if ((filp->f_flags & O_NONBLOCK) ||
 			(tty->flags & (1 << TTY_IO_ERROR))) {
 		pr_dbg("block_til_ready: non-block mode.\n");
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		port->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -879,26 +864,26 @@
 	/* block waiting for DCD to be asserted, and while
 						callout dev is busy */
 	retval = 0;
-	add_wait_queue(&port->open_wait, &wait);
+	add_wait_queue(&port->port.open_wait, &wait);
 
 	spin_lock_irqsave(&card->card_lock, flags);
 	if (!tty_hung_up_p(filp))
-		port->count--;
-	port->blocked_open++;
+		port->port.count--;
+	port->port.blocked_open++;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
 	while (1) {
 		raise_dtr_rts(port);
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
+		if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
+			if (port->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CLOSING) &&
+		if (!(port->port.flags & ASYNC_CLOSING) &&
 				(do_clocal || (port->status & ISI_DCD))) {
 			break;
 		}
@@ -909,15 +894,15 @@
 		schedule();
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&port->open_wait, &wait);
+	remove_wait_queue(&port->port.open_wait, &wait);
 	spin_lock_irqsave(&card->card_lock, flags);
 	if (!tty_hung_up_p(filp))
-		port->count++;
-	port->blocked_open--;
+		port->port.count++;
+	port->port.blocked_open--;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 	if (retval)
 		return retval;
-	port->flags |= ASYNC_NORMAL_ACTIVE;
+	port->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -947,9 +932,9 @@
 
 	isicom_setup_board(card);
 
-	port->count++;
+	port->port.count++;
 	tty->driver_data = port;
-	port->tty = tty;
+	port->port.tty = tty;
 	error = isicom_setup_port(port);
 	if (error == 0)
 		error = block_til_ready(tty, filp, port);
@@ -970,18 +955,15 @@
 	struct isi_board *card = port->card;
 	struct tty_struct *tty;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
-	if (!(port->flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED))
 		return;
 
-	if (port->xmit_buf) {
-		free_page((unsigned long) port->xmit_buf);
-		port->xmit_buf = NULL;
-	}
-	port->flags &= ~ASYNC_INITIALIZED;
+	tty_port_free_xmit_buf(&port->port);
+	port->port.flags &= ~ASYNC_INITIALIZED;
 	/* 3rd October 2000 : Vinayak P Risbud */
-	port->tty = NULL;
+	port->port.tty = NULL;
 
 	/*Fix done by Anil .S on 30-04-2001
 	remote login through isi port has dtr toggle problem
@@ -1046,33 +1028,33 @@
 		return;
 	}
 
-	if (tty->count == 1 && port->count != 1) {
+	if (tty->count == 1 && port->port.count != 1) {
 		printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
 			"count tty->count = 1 port count = %d.\n",
-			card->base, port->count);
-		port->count = 1;
+			card->base, port->port.count);
+		port->port.count = 1;
 	}
-	if (--port->count < 0) {
+	if (--port->port.count < 0) {
 		printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
 			"count for channel%d = %d", card->base, port->channel,
-			port->count);
-		port->count = 0;
+			port->port.count);
+		port->port.count = 0;
 	}
 
-	if (port->count) {
+	if (port->port.count) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
 		return;
 	}
-	port->flags |= ASYNC_CLOSING;
+	port->port.flags |= ASYNC_CLOSING;
 	tty->closing = 1;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
-	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, port->closing_wait);
+	if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, port->port.closing_wait);
 	/* indicate to the card that no more data can be received
 	   on this port */
 	spin_lock_irqsave(&card->card_lock, flags);
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (port->port.flags & ASYNC_INITIALIZED) {
 		card->port_status &= ~(1 << port->channel);
 		outw(card->port_status, card->base + 0x02);
 	}
@@ -1085,18 +1067,18 @@
 	spin_lock_irqsave(&card->card_lock, flags);
 	tty->closing = 0;
 
-	if (port->blocked_open) {
+	if (port->port.blocked_open) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
-		if (port->close_delay) {
+		if (port->port.close_delay) {
 			pr_dbg("scheduling until time out.\n");
 			msleep_interruptible(
-				jiffies_to_msecs(port->close_delay));
+				jiffies_to_msecs(port->port.close_delay));
 		}
 		spin_lock_irqsave(&card->card_lock, flags);
-		wake_up_interruptible(&port->open_wait);
+		wake_up_interruptible(&port->port.open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-	wake_up_interruptible(&port->close_wait);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+	wake_up_interruptible(&port->port.close_wait);
 	spin_unlock_irqrestore(&card->card_lock, flags);
 }
 
@@ -1112,9 +1094,6 @@
 	if (isicom_paranoia_check(port, tty->name, "isicom_write"))
 		return 0;
 
-	if (!port->xmit_buf)
-		return 0;
-
 	spin_lock_irqsave(&card->card_lock, flags);
 
 	while (1) {
@@ -1123,7 +1102,7 @@
 		if (cnt <= 0)
 			break;
 
-		memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
+		memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
 		port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
 			- 1);
 		port->xmit_cnt += cnt;
@@ -1147,16 +1126,13 @@
 	if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
 		return 0;
 
-	if (!port->xmit_buf)
-		return 0;
-
 	spin_lock_irqsave(&card->card_lock, flags);
 	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
 		spin_unlock_irqrestore(&card->card_lock, flags);
 		return 0;
 	}
 
-	port->xmit_buf[port->xmit_head++] = ch;
+	port->port.xmit_buf[port->xmit_head++] = ch;
 	port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
 	port->xmit_cnt++;
 	spin_unlock_irqrestore(&card->card_lock, flags);
@@ -1172,7 +1148,7 @@
 		return;
 
 	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-			!port->xmit_buf)
+			!port->port.xmit_buf)
 		return;
 
 	/* this tells the transmitter to consider this port for
@@ -1274,23 +1250,23 @@
 
 	lock_kernel();
 
-	reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
+	reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
 		(newinfo.flags & ASYNC_SPD_MASK));
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if ((newinfo.close_delay != port->close_delay) ||
-				(newinfo.closing_wait != port->closing_wait) ||
+		if ((newinfo.close_delay != port->port.close_delay) ||
+				(newinfo.closing_wait != port->port.closing_wait) ||
 				((newinfo.flags & ~ASYNC_USR_MASK) !=
-				(port->flags & ~ASYNC_USR_MASK))) {
+				(port->port.flags & ~ASYNC_USR_MASK))) {
 			unlock_kernel();
 			return -EPERM;
 		}
-		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
 				(newinfo.flags & ASYNC_USR_MASK));
 	} else {
-		port->close_delay = newinfo.close_delay;
-		port->closing_wait = newinfo.closing_wait;
-		port->flags = ((port->flags & ~ASYNC_FLAGS) |
+		port->port.close_delay = newinfo.close_delay;
+		port->port.closing_wait = newinfo.closing_wait;
+		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
 				(newinfo.flags & ASYNC_FLAGS));
 	}
 	if (reconfig_port) {
@@ -1314,10 +1290,10 @@
 	out_info.line = port - isi_ports;
 	out_info.port = port->card->base;
 	out_info.irq = port->card->irq;
-	out_info.flags = port->flags;
+	out_info.flags = port->port.flags;
 /*	out_info.baud_base = ? */
-	out_info.close_delay = port->close_delay;
-	out_info.closing_wait = port->closing_wait;
+	out_info.close_delay = port->port.close_delay;
+	out_info.closing_wait = port->port.closing_wait;
 	unlock_kernel();
 	if (copy_to_user(info, &out_info, sizeof(out_info)))
 		return -EFAULT;
@@ -1454,10 +1430,10 @@
 	isicom_shutdown_port(port);
 	spin_unlock_irqrestore(&port->card->card_lock, flags);
 
-	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->tty = NULL;
-	wake_up_interruptible(&port->open_wait);
+	port->port.count = 0;
+	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	port->port.tty = NULL;
+	wake_up_interruptible(&port->port.open_wait);
 }
 
 
@@ -1736,6 +1712,12 @@
 	if (card_count >= BOARD_COUNT)
 		goto err;
 
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		dev_err(&pdev->dev, "failed to enable\n");
+		goto err;
+	}
+
 	dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
 
 	/* allot the first empty slot in the array */
@@ -1790,6 +1772,7 @@
 errdec:
 	board->base = 0;
 	card_count--;
+	pci_disable_device(pdev);
 err:
 	return retval;
 }
@@ -1806,6 +1789,7 @@
 	pci_release_region(pdev, 3);
 	board->base = 0;
 	card_count--;
+	pci_disable_device(pdev);
 }
 
 static int __init isicom_init(void)
@@ -1818,14 +1802,13 @@
 		isi_card[idx].ports = port;
 		spin_lock_init(&isi_card[idx].card_lock);
 		for (channel = 0; channel < 16; channel++, port++) {
+			tty_port_init(&port->port);
 			port->magic = ISICOM_MAGIC;
 			port->card = &isi_card[idx];
 			port->channel = channel;
-			port->close_delay = 50 * HZ/100;
-			port->closing_wait = 3000 * HZ/100;
+			port->port.close_delay = 50 * HZ/100;
+			port->port.closing_wait = 3000 * HZ/100;
 			port->status = 0;
-			init_waitqueue_head(&port->open_wait);
-			init_waitqueue_head(&port->close_wait);
 			/*  . . .  */
 		}
 		isi_card[idx].base = 0;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 7c8b62f..6ef1c56 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -735,8 +735,8 @@
 	for (j = 0; j < STL_MAXPORTS; j++) {
 		portp = brdp->ports[j];
 		if (portp != NULL) {
-			if (portp->tty != NULL)
-				tty_hangup(portp->tty);
+			if (portp->port.tty != NULL)
+				tty_hangup(portp->port.tty);
 			kfree(portp);
 		}
 	}
@@ -811,9 +811,9 @@
  *	The sleep here does not need interrupt protection since the wakeup
  *	for it is done with the same context.
  */
-	if (portp->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&portp->close_wait);
-		if (portp->flags & ASYNC_HUP_NOTIFY)
+	if (portp->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&portp->port.close_wait);
+		if (portp->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		return -ERESTARTSYS;
 	}
@@ -824,7 +824,7 @@
  *	requires several commands to the board we will need to wait for any
  *	other open that is already initializing the port.
  */
-	portp->tty = tty;
+	portp->port.tty = tty;
 	tty->driver_data = portp;
 	portp->refcount++;
 
@@ -833,10 +833,10 @@
 	if (signal_pending(current))
 		return -ERESTARTSYS;
 
-	if ((portp->flags & ASYNC_INITIALIZED) == 0) {
+	if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
 		set_bit(ST_INITIALIZING, &portp->state);
 		if ((rc = stli_initopen(brdp, portp)) >= 0) {
-			portp->flags |= ASYNC_INITIALIZED;
+			portp->port.flags |= ASYNC_INITIALIZED;
 			clear_bit(TTY_IO_ERROR, &tty->flags);
 		}
 		clear_bit(ST_INITIALIZING, &portp->state);
@@ -851,9 +851,9 @@
  *	The sleep here does not need interrupt protection since the wakeup
  *	for it is done with the same context.
  */
-	if (portp->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&portp->close_wait);
-		if (portp->flags & ASYNC_HUP_NOTIFY)
+	if (portp->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&portp->port.close_wait);
+		if (portp->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		return -ERESTARTSYS;
 	}
@@ -867,7 +867,7 @@
 		if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
 			return rc;
 	}
-	portp->flags |= ASYNC_NORMAL_ACTIVE;
+	portp->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -895,7 +895,7 @@
 		return;
 	}
 
-	portp->flags |= ASYNC_CLOSING;
+	portp->port.flags |= ASYNC_CLOSING;
 
 /*
  *	May want to wait for data to drain before closing. The BUSY flag
@@ -911,7 +911,7 @@
 	if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
 		tty_wait_until_sent(tty, portp->closing_wait);
 
-	portp->flags &= ~ASYNC_INITIALIZED;
+	portp->port.flags &= ~ASYNC_INITIALIZED;
 	brdp = stli_brds[portp->brdnr];
 	stli_rawclose(brdp, portp, 0, 0);
 	if (tty->termios->c_cflag & HUPCL) {
@@ -931,16 +931,16 @@
 	stli_flushbuffer(tty);
 
 	tty->closing = 0;
-	portp->tty = NULL;
+	portp->port.tty = NULL;
 
 	if (portp->openwaitcnt) {
 		if (portp->close_delay)
 			msleep_interruptible(jiffies_to_msecs(portp->close_delay));
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->port.open_wait);
 	}
 
-	portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&portp->close_wait);
+	portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&portp->port.close_wait);
 }
 
 /*****************************************************************************/
@@ -970,7 +970,7 @@
 	    sizeof(asynotify_t), 0)) < 0)
 		return rc;
 
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return -ENODEV;
 	stli_mkasyport(portp, &aport, tty->termios);
@@ -1169,7 +1169,7 @@
 
 	if (portp == NULL)
 		return -ENODEV;
-	if (portp->tty == NULL)
+	if (portp->port.tty == NULL)
 		return -ENODEV;
 	if (portp->brdnr >= stli_nrbrds)
 		return -ENODEV;
@@ -1177,7 +1177,7 @@
 	if (brdp == NULL)
 		return -ENODEV;
 
-	stli_mkasyport(portp, &aport, portp->tty->termios);
+	stli_mkasyport(portp, &aport, portp->port.tty->termios);
 	return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
 }
 
@@ -1196,7 +1196,7 @@
 	rc = 0;
 	doclocal = 0;
 
-	if (portp->tty->termios->c_cflag & CLOCAL)
+	if (portp->port.tty->termios->c_cflag & CLOCAL)
 		doclocal++;
 
 	spin_lock_irqsave(&stli_lock, flags);
@@ -1211,14 +1211,14 @@
 		    &portp->asig, sizeof(asysigs_t), 0)) < 0)
 			break;
 		if (tty_hung_up_p(filp) ||
-		    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
-			if (portp->flags & ASYNC_HUP_NOTIFY)
+		    ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
+			if (portp->port.flags & ASYNC_HUP_NOTIFY)
 				rc = -EBUSY;
 			else
 				rc = -ERESTARTSYS;
 			break;
 		}
-		if (((portp->flags & ASYNC_CLOSING) == 0) &&
+		if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
 		    (doclocal || (portp->sigs & TIOCM_CD))) {
 			break;
 		}
@@ -1226,7 +1226,7 @@
 			rc = -ERESTARTSYS;
 			break;
 		}
-		interruptible_sleep_on(&portp->open_wait);
+		interruptible_sleep_on(&portp->port.open_wait);
 	}
 
 	spin_lock_irqsave(&stli_lock, flags);
@@ -1548,7 +1548,7 @@
 	sio.type = PORT_UNKNOWN;
 	sio.line = portp->portnr;
 	sio.irq = 0;
-	sio.flags = portp->flags;
+	sio.flags = portp->port.flags;
 	sio.baud_base = portp->baud_base;
 	sio.close_delay = portp->close_delay;
 	sio.closing_wait = portp->closing_wait;
@@ -1583,11 +1583,11 @@
 		if ((sio.baud_base != portp->baud_base) ||
 		    (sio.close_delay != portp->close_delay) ||
 		    ((sio.flags & ~ASYNC_USR_MASK) !=
-		    (portp->flags & ~ASYNC_USR_MASK)))
+		    (portp->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
 	} 
 
-	portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+	portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
 		(sio.flags & ASYNC_USR_MASK);
 	portp->baud_base = sio.baud_base;
 	portp->close_delay = sio.close_delay;
@@ -1751,7 +1751,7 @@
 	if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0))
 		tty->hw_stopped = 0;
 	if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->port.open_wait);
 }
 
 /*****************************************************************************/
@@ -1834,7 +1834,7 @@
 	if (brdp == NULL)
 		return;
 
-	portp->flags &= ~ASYNC_INITIALIZED;
+	portp->port.flags &= ~ASYNC_INITIALIZED;
 
 	if (!test_bit(ST_CLOSING, &portp->state))
 		stli_rawclose(brdp, portp, 0, 0);
@@ -1855,12 +1855,12 @@
 	clear_bit(ST_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &portp->state);
 	set_bit(TTY_IO_ERROR, &tty->flags);
-	portp->tty = NULL;
-	portp->flags &= ~ASYNC_NORMAL_ACTIVE;
+	portp->port.tty = NULL;
+	portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	portp->refcount = 0;
 	spin_unlock_irqrestore(&stli_lock, flags);
 
-	wake_up_interruptible(&portp->open_wait);
+	wake_up_interruptible(&portp->port.open_wait);
 }
 
 /*****************************************************************************/
@@ -2188,7 +2188,7 @@
 
 	if (test_bit(ST_RXSTOP, &portp->state))
 		return;
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return;
 
@@ -2362,7 +2362,7 @@
 	if (ap->notify) {
 		nt = ap->changed;
 		ap->notify = 0;
-		tty = portp->tty;
+		tty = portp->port.tty;
 
 		if (nt.signal & SG_DCD) {
 			oldsigs = portp->sigs;
@@ -2370,10 +2370,10 @@
 			clear_bit(ST_GETSIGS, &portp->state);
 			if ((portp->sigs & TIOCM_CD) &&
 			    ((oldsigs & TIOCM_CD) == 0))
-				wake_up_interruptible(&portp->open_wait);
+				wake_up_interruptible(&portp->port.open_wait);
 			if ((oldsigs & TIOCM_CD) &&
 			    ((portp->sigs & TIOCM_CD) == 0)) {
-				if (portp->flags & ASYNC_CHECK_CD) {
+				if (portp->port.flags & ASYNC_CHECK_CD) {
 					if (tty)
 						tty_hangup(tty);
 				}
@@ -2392,7 +2392,7 @@
 		if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
 			if (tty != NULL) {
 				tty_insert_flip_char(tty, 0, TTY_BREAK);
-				if (portp->flags & ASYNC_SAK) {
+				if (portp->port.flags & ASYNC_SAK) {
 					do_SAK(tty);
 					EBRDENABLE(brdp);
 				}
@@ -2542,17 +2542,17 @@
 /*
  *	Start of by setting the baud, char size, parity and stop bit info.
  */
-	pp->baudout = tty_get_baud_rate(portp->tty);
+	pp->baudout = tty_get_baud_rate(portp->port.tty);
 	if ((tiosp->c_cflag & CBAUD) == B38400) {
-		if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			pp->baudout = 57600;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			pp->baudout = 115200;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			pp->baudout = 230400;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			pp->baudout = 460800;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 			pp->baudout = (portp->baud_base / portp->custom_divisor);
 	}
 	if (pp->baudout > STL_MAXBAUD)
@@ -2625,9 +2625,9 @@
  *	Set up clocal processing as required.
  */
 	if (tiosp->c_cflag & CLOCAL)
-		portp->flags &= ~ASYNC_CHECK_CD;
+		portp->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		portp->flags |= ASYNC_CHECK_CD;
+		portp->port.flags |= ASYNC_CHECK_CD;
 
 /*
  *	Transfer any persistent flags into the asyport structure.
@@ -2703,8 +2703,8 @@
 		portp->baud_base = STL_BAUDBASE;
 		portp->close_delay = STL_CLOSEDELAY;
 		portp->closing_wait = 30 * HZ;
-		init_waitqueue_head(&portp->open_wait);
-		init_waitqueue_head(&portp->close_wait);
+		init_waitqueue_head(&portp->port.open_wait);
+		init_waitqueue_head(&portp->port.close_wait);
 		init_waitqueue_head(&portp->raw_wait);
 		panelport++;
 		if (panelport >= brdp->panels[panelnr]) {
@@ -4246,18 +4246,18 @@
 	stli_comstats.panel = portp->panelnr;
 	stli_comstats.port = portp->portnr;
 	stli_comstats.state = portp->state;
-	stli_comstats.flags = portp->flags;
+	stli_comstats.flags = portp->port.flag;
 
 	spin_lock_irqsave(&brd_lock, flags);
-	if (portp->tty != NULL) {
-		if (portp->tty->driver_data == portp) {
-			stli_comstats.ttystate = portp->tty->flags;
+	if (portp->port.tty != NULL) {
+		if (portp->port.tty->driver_data == portp) {
+			stli_comstats.ttystate = portp->port.tty->flags;
 			stli_comstats.rxbuffered = -1;
-			if (portp->tty->termios != NULL) {
-				stli_comstats.cflags = portp->tty->termios->c_cflag;
-				stli_comstats.iflags = portp->tty->termios->c_iflag;
-				stli_comstats.oflags = portp->tty->termios->c_oflag;
-				stli_comstats.lflags = portp->tty->termios->c_lflag;
+			if (portp->port.tty->termios != NULL) {
+				stli_comstats.cflags = portp->port.tty->termios->c_cflag;
+				stli_comstats.iflags = portp->port.tty->termios->c_iflag;
+				stli_comstats.oflags = portp->port.tty->termios->c_oflag;
+				stli_comstats.lflags = portp->port.tty->termios->c_lflag;
 			}
 		}
 	}
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index e21346d..2bba250 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -130,17 +130,13 @@
 };
 
 struct moxa_port {
+	struct tty_port port;
 	struct moxa_board_conf *board;
-	struct tty_struct *tty;
 	void __iomem *tableAddr;
 
 	int type;
-	int close_delay;
-	unsigned int count;
-	int asyncflags;
 	int cflag;
 	unsigned long statusflags;
-	wait_queue_head_t open_wait;
 
 	u8 DCDState;
 	u8 lineCtrl;
@@ -348,10 +344,10 @@
 				if (status & 4)
 					tmp.dcd = 1;
 
-				if (!p->tty || !p->tty->termios)
+				if (!p->port.tty || !p->port.tty->termios)
 					tmp.cflag = p->cflag;
 				else
-					tmp.cflag = p->tty->termios->c_cflag;
+					tmp.cflag = p->port.tty->termios->c_cflag;
 copy:
 				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
 					mutex_unlock(&moxa_openlock);
@@ -825,10 +821,9 @@
 	}
 
 	for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+		tty_port_init(&p->port);
 		p->type = PORT_16550A;
-		p->close_delay = 5 * HZ / 10;
 		p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
-		init_waitqueue_head(&p->open_wait);
 	}
 
 	switch (brd->boardType) {
@@ -884,12 +879,12 @@
 
 	/* pci hot-un-plug support */
 	for (a = 0; a < brd->numPorts; a++)
-		if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
-			tty_hangup(brd->ports[a].tty);
+		if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+			tty_hangup(brd->ports[a].port.tty);
 	while (1) {
 		opened = 0;
 		for (a = 0; a < brd->numPorts; a++)
-			if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
 				opened++;
 		mutex_unlock(&moxa_openlock);
 		if (!opened)
@@ -1104,9 +1099,9 @@
 {
 	moxa_shut_down(ch);
 	MoxaPortFlushData(ch, 2);
-	ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
-	ch->tty->driver_data = NULL;
-	ch->tty = NULL;
+	ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	ch->port.tty->driver_data = NULL;
+	ch->port.tty = NULL;
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1117,7 +1112,7 @@
 	u8 dcd;
 
 	while (1) {
-		prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+		prepare_to_wait(&ch->port.open_wait, &wait, TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp)) {
 #ifdef SERIAL_DO_RESTART
 			retval = -ERESTARTSYS;
@@ -1138,7 +1133,7 @@
 		}
 		schedule();
 	}
-	finish_wait(&ch->open_wait, &wait);
+	finish_wait(&ch->port.open_wait, &wait);
 
 	return retval;
 }
@@ -1163,16 +1158,16 @@
 	}
 
 	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
-	ch->count++;
+	ch->port.count++;
 	tty->driver_data = ch;
-	ch->tty = tty;
-	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
+	ch->port.tty = tty;
+	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
 		ch->statusflags = 0;
 		moxa_set_tty_param(tty, tty->termios);
 		MoxaPortLineCtrl(ch, 1, 1);
 		MoxaPortEnable(ch);
 		MoxaSetFifo(ch, ch->type == PORT_16550A);
-		ch->asyncflags |= ASYNC_INITIALIZED;
+		ch->port.flags |= ASYNC_INITIALIZED;
 	}
 	mutex_unlock(&moxa_openlock);
 
@@ -1181,11 +1176,11 @@
 		retval = moxa_block_till_ready(tty, filp, ch);
 	mutex_lock(&moxa_openlock);
 	if (retval) {
-		if (ch->count) /* 0 means already hung up... */
-			if (--ch->count == 0)
+		if (ch->port.count) /* 0 means already hung up... */
+			if (--ch->port.count == 0)
 				moxa_close_port(ch);
 	} else
-		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+		ch->port.flags |= ASYNC_NORMAL_ACTIVE;
 	mutex_unlock(&moxa_openlock);
 
 	return retval;
@@ -1204,21 +1199,21 @@
 	ch = tty->driver_data;
 	if (ch == NULL)
 		goto unlock;
-	if (tty->count == 1 && ch->count != 1) {
+	if (tty->count == 1 && ch->port.count != 1) {
 		printk(KERN_WARNING "moxa_close: bad serial port count; "
-			"tty->count is 1, ch->count is %d\n", ch->count);
-		ch->count = 1;
+			"tty->count is 1, ch->port.count is %d\n", ch->port.count);
+		ch->port.count = 1;
 	}
-	if (--ch->count < 0) {
+	if (--ch->port.count < 0) {
 		printk(KERN_WARNING "moxa_close: bad serial port count, "
 			"device=%s\n", tty->name);
-		ch->count = 0;
+		ch->port.count = 0;
 	}
-	if (ch->count)
+	if (ch->port.count)
 		goto unlock;
 
 	ch->cflag = tty->termios->c_cflag;
-	if (ch->asyncflags & ASYNC_INITIALIZED) {
+	if (ch->port.flags & ASYNC_INITIALIZED) {
 		moxa_setup_empty_event(tty);
 		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
 	}
@@ -1374,7 +1369,7 @@
 		return;
 	moxa_set_tty_param(tty, old_termios);
 	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
-		wake_up_interruptible(&ch->open_wait);
+		wake_up_interruptible(&ch->port.open_wait);
 }
 
 static void moxa_stop(struct tty_struct *tty)
@@ -1412,20 +1407,20 @@
 		mutex_unlock(&moxa_openlock);
 		return;
 	}
-	ch->count = 0;
+	ch->port.count = 0;
 	moxa_close_port(ch);
 	mutex_unlock(&moxa_openlock);
 
-	wake_up_interruptible(&ch->open_wait);
+	wake_up_interruptible(&ch->port.open_wait);
 }
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
 	dcd = !!dcd;
 
-	if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) {
+	if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
 		if (!dcd)
-			tty_hangup(p->tty);
+			tty_hangup(p->port.tty);
 	}
 	p->DCDState = dcd;
 }
@@ -1433,9 +1428,9 @@
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 		u16 __iomem *ip)
 {
-	struct tty_struct *tty = p->tty;
+	struct tty_struct *tty = p->port.tty;
 	void __iomem *ofsAddr;
-	unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
 	u16 intr;
 
 	if (tty) {
@@ -1566,9 +1561,9 @@
 
 static void moxa_shut_down(struct moxa_port *ch)
 {
-	struct tty_struct *tp = ch->tty;
+	struct tty_struct *tp = ch->port.tty;
 
-	if (!(ch->asyncflags & ASYNC_INITIALIZED))
+	if (!(ch->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	MoxaPortDisable(ch);
@@ -1580,7 +1575,7 @@
 		MoxaPortLineCtrl(ch, 0, 0);
 
 	spin_lock_bh(&moxa_lock);
-	ch->asyncflags &= ~ASYNC_INITIALIZED;
+	ch->port.flags &= ~ASYNC_INITIALIZED;
 	spin_unlock_bh(&moxa_lock);
 }
 
@@ -1975,7 +1970,7 @@
 	c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
 	if (c > len)
 		c = len;
-	moxaLog.txcnt[port->tty->index] += c;
+	moxaLog.txcnt[port->port.tty->index] += c;
 	total = c;
 	if (spage == epage) {
 		bufhead = readw(ofsAddr + Ofs_txb);
@@ -2017,7 +2012,7 @@
 
 static int MoxaPortReadData(struct moxa_port *port)
 {
-	struct tty_struct *tty = port->tty;
+	struct tty_struct *tty = port->port.tty;
 	unsigned char *dst;
 	void __iomem *baseAddr, *ofsAddr, *ofs;
 	unsigned int count, len, total;
@@ -2124,10 +2119,10 @@
 {
 	struct serial_struct tmp = {
 		.type = info->type,
-		.line = info->tty->index,
-		.flags = info->asyncflags,
+		.line = info->port.tty->index,
+		.flags = info->port.flags,
 		.baud_base = 921600,
-		.close_delay = info->close_delay
+		.close_delay = info->port.close_delay
 	};
 	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
 }
@@ -2148,13 +2143,13 @@
 
 	if (!capable(CAP_SYS_ADMIN)) {
 		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (info->asyncflags & ~ASYNC_USR_MASK)))
+		     (info->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
 	} else
-		info->close_delay = new_serial.close_delay * HZ / 100;
+		info->port.close_delay = new_serial.close_delay * HZ / 100;
 
 	new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
-	new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
+	new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
 
 	MoxaSetFifo(info, new_serial.type == PORT_16550A);
 
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 4b81a85..6307e30 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -222,8 +222,8 @@
 struct mxser_board;
 
 struct mxser_port {
+	struct tty_port port;
 	struct mxser_board *board;
-	struct tty_struct *tty;
 
 	unsigned long ioaddr;
 	unsigned long opmode_ioaddr;
@@ -234,7 +234,6 @@
 	int rx_low_water;
 	int baud_base;		/* max. speed */
 	int type;		/* UART type */
-	int flags;		/* defined in tty.h */
 
 	int x_char;		/* xon/xoff character */
 	int IER;		/* Interrupt Enable Register */
@@ -244,20 +243,14 @@
 	unsigned char ldisc_stop_rx;
 
 	int custom_divisor;
-	int close_delay;
-	unsigned short closing_wait;
 	unsigned char err_shadow;
-	unsigned long event;
 
-	int count;		/* # of fd on device */
-	int blocked_open;	/* # of blocked opens */
 	struct async_icount icount; /* kernel counters for 4 input interrupts */
 	int timeout;
 
 	int read_status_mask;
 	int ignore_status_mask;
 	int xmit_fifo_size;
-	unsigned char *xmit_buf;
 	int xmit_head;
 	int xmit_tail;
 	int xmit_cnt;
@@ -267,7 +260,6 @@
 	struct mxser_mon mon_data;
 
 	spinlock_t slock;
-	wait_queue_head_t open_wait;
 	wait_queue_head_t delta_msr_wait;
 };
 
@@ -575,7 +567,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 			test_bit(TTY_IO_ERROR, &tty->flags)) {
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		port->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -585,32 +577,32 @@
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, port->count is dropped by one, so that
+	 * this loop, port->port.count is dropped by one, so that
 	 * mxser_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&port->open_wait, &wait);
+	add_wait_queue(&port->port.open_wait, &wait);
 
 	spin_lock_irqsave(&port->slock, flags);
 	if (!tty_hung_up_p(filp))
-		port->count--;
+		port->port.count--;
 	spin_unlock_irqrestore(&port->slock, flags);
-	port->blocked_open++;
+	port->port.blocked_open++;
 	while (1) {
 		spin_lock_irqsave(&port->slock, flags);
 		outb(inb(port->ioaddr + UART_MCR) |
 			UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
 		spin_unlock_irqrestore(&port->slock, flags);
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
+		if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
+			if (port->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CLOSING) &&
+		if (!(port->port.flags & ASYNC_CLOSING) &&
 				(do_clocal ||
 				(inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
 			break;
@@ -621,13 +613,13 @@
 		schedule();
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&port->open_wait, &wait);
+	remove_wait_queue(&port->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp))
-		port->count++;
-	port->blocked_open--;
+		port->port.count++;
+	port->port.blocked_open--;
 	if (retval)
 		return retval;
-	port->flags |= ASYNC_NORMAL_ACTIVE;
+	port->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -636,7 +628,7 @@
 	int quot = 0, baud;
 	unsigned char cval;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return -1;
 
 	if (!(info->ioaddr))
@@ -647,13 +639,13 @@
 
 	if (newspd == 134) {
 		quot = 2 * info->baud_base / 269;
-		tty_encode_baud_rate(info->tty, 134, 134);
+		tty_encode_baud_rate(info->port.tty, 134, 134);
 	} else if (newspd) {
 		quot = info->baud_base / newspd;
 		if (quot == 0)
 			quot = 1;
 		baud = info->baud_base/quot;
-		tty_encode_baud_rate(info->tty, baud, baud);
+		tty_encode_baud_rate(info->port.tty, baud, baud);
 	} else {
 		quot = 0;
 	}
@@ -679,7 +671,7 @@
 	outb(cval, info->ioaddr + UART_LCR);	/* reset DLAB */
 
 #ifdef BOTHER
-	if (C_BAUD(info->tty) == BOTHER) {
+	if (C_BAUD(info->port.tty) == BOTHER) {
 		quot = info->baud_base % newspd;
 		quot *= 8;
 		if (quot % newspd > newspd / 2) {
@@ -707,14 +699,14 @@
 	int ret = 0;
 	unsigned char status;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return ret;
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 	if (!(info->ioaddr))
 		return ret;
 
-	if (mxser_set_baud_method[info->tty->index] == 0)
-		mxser_set_baud(info, tty_get_baud_rate(info->tty));
+	if (mxser_set_baud_method[info->port.tty->index] == 0)
+		mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
 
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
@@ -777,15 +769,15 @@
 	info->IER &= ~UART_IER_MSI;
 	info->MCR &= ~UART_MCR_AFE;
 	if (cflag & CRTSCTS) {
-		info->flags |= ASYNC_CTS_FLOW;
+		info->port.flags |= ASYNC_CTS_FLOW;
 		info->IER |= UART_IER_MSI;
 		if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
 			info->MCR |= UART_MCR_AFE;
 		} else {
 			status = inb(info->ioaddr + UART_MSR);
-			if (info->tty->hw_stopped) {
+			if (info->port.tty->hw_stopped) {
 				if (status & UART_MSR_CTS) {
-					info->tty->hw_stopped = 0;
+					info->port.tty->hw_stopped = 0;
 					if (info->type != PORT_16550A &&
 							!info->board->chip_flag) {
 						outb(info->IER & ~UART_IER_THRI,
@@ -795,11 +787,11 @@
 						outb(info->IER, info->ioaddr +
 								UART_IER);
 					}
-					tty_wakeup(info->tty);
+					tty_wakeup(info->port.tty);
 				}
 			} else {
 				if (!(status & UART_MSR_CTS)) {
-					info->tty->hw_stopped = 1;
+					info->port.tty->hw_stopped = 1;
 					if ((info->type != PORT_16550A) &&
 							(!info->board->chip_flag)) {
 						info->IER &= ~UART_IER_THRI;
@@ -810,13 +802,13 @@
 			}
 		}
 	} else {
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 	}
 	outb(info->MCR, info->ioaddr + UART_MCR);
 	if (cflag & CLOCAL) {
-		info->flags &= ~ASYNC_CHECK_CD;
+		info->port.flags &= ~ASYNC_CHECK_CD;
 	} else {
-		info->flags |= ASYNC_CHECK_CD;
+		info->port.flags |= ASYNC_CHECK_CD;
 		info->IER |= UART_IER_MSI;
 	}
 	outb(info->IER, info->ioaddr + UART_IER);
@@ -825,21 +817,21 @@
 	 * Set up parity check flag
 	 */
 	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
 		info->read_status_mask |= UART_LSR_BI;
 
 	info->ignore_status_mask = 0;
 
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		info->read_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty)) {
+		if (I_IGNPAR(info->port.tty)) {
 			info->ignore_status_mask |=
 						UART_LSR_OE |
 						UART_LSR_PE |
@@ -851,16 +843,16 @@
 		}
 	}
 	if (info->board->chip_flag) {
-		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty));
-		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty));
-		if (I_IXON(info->tty)) {
+		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
+		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
+		if (I_IXON(info->port.tty)) {
 			mxser_enable_must_rx_software_flow_control(
 					info->ioaddr);
 		} else {
 			mxser_disable_must_rx_software_flow_control(
 					info->ioaddr);
 		}
-		if (I_IXOFF(info->tty)) {
+		if (I_IXOFF(info->port.tty)) {
 			mxser_enable_must_tx_software_flow_control(
 					info->ioaddr);
 		} else {
@@ -890,15 +882,15 @@
 	port->mon_data.modem_status = status;
 	wake_up_interruptible(&port->delta_msr_wait);
 
-	if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+	if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
 		if (status & UART_MSR_DCD)
-			wake_up_interruptible(&port->open_wait);
+			wake_up_interruptible(&port->port.open_wait);
 	}
 
-	if (port->flags & ASYNC_CTS_FLOW) {
-		if (port->tty->hw_stopped) {
+	if (port->port.flags & ASYNC_CTS_FLOW) {
+		if (port->port.tty->hw_stopped) {
 			if (status & UART_MSR_CTS) {
-				port->tty->hw_stopped = 0;
+				port->port.tty->hw_stopped = 0;
 
 				if ((port->type != PORT_16550A) &&
 						(!port->board->chip_flag)) {
@@ -908,11 +900,11 @@
 					outb(port->IER, port->ioaddr +
 							UART_IER);
 				}
-				tty_wakeup(port->tty);
+				tty_wakeup(port->port.tty);
 			}
 		} else {
 			if (!(status & UART_MSR_CTS)) {
-				port->tty->hw_stopped = 1;
+				port->port.tty->hw_stopped = 1;
 				if (port->type != PORT_16550A &&
 						!port->board->chip_flag) {
 					port->IER &= ~UART_IER_THRI;
@@ -935,23 +927,23 @@
 
 	spin_lock_irqsave(&info->slock, flags);
 
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
 		return 0;
 	}
 
 	if (!info->ioaddr || !info->type) {
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
 		return 0;
 	}
-	if (info->xmit_buf)
+	if (info->port.xmit_buf)
 		free_page(page);
 	else
-		info->xmit_buf = (unsigned char *) page;
+		info->port.xmit_buf = (unsigned char *) page;
 
 	/*
 	 * Clear the FIFO buffers and disable them
@@ -973,8 +965,8 @@
 	if (inb(info->ioaddr + UART_LSR) == 0xff) {
 		spin_unlock_irqrestore(&info->slock, flags);
 		if (capable(CAP_SYS_ADMIN)) {
-			if (info->tty)
-				set_bit(TTY_IO_ERROR, &info->tty->flags);
+			if (info->port.tty)
+				set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 			return 0;
 		} else
 			return -ENODEV;
@@ -1012,15 +1004,15 @@
 	(void) inb(info->ioaddr + UART_IIR);
 	(void) inb(info->ioaddr + UART_MSR);
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
 	 * and set the speed of the serial port
 	 */
 	mxser_change_speed(info, NULL);
-	info->flags |= ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&info->slock, flags);
 
 	return 0;
@@ -1034,7 +1026,7 @@
 {
 	unsigned long flags;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	spin_lock_irqsave(&info->slock, flags);
@@ -1048,15 +1040,15 @@
 	/*
 	 * Free the IRQ, if necessary
 	 */
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = NULL;
+	if (info->port.xmit_buf) {
+		free_page((unsigned long) info->port.xmit_buf);
+		info->port.xmit_buf = NULL;
 	}
 
 	info->IER = 0;
 	outb(0x00, info->ioaddr + UART_IER);
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
 		info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
 	outb(info->MCR, info->ioaddr + UART_MCR);
 
@@ -1072,10 +1064,10 @@
 	/* read data port to reset things */
 	(void) inb(info->ioaddr + UART_RX);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 
 	if (info->board->chip_flag)
 		SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
@@ -1105,12 +1097,12 @@
 		return -ENODEV;
 
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 	/*
 	 * Start up serial port
 	 */
 	spin_lock_irqsave(&info->slock, flags);
-	info->count++;
+	info->port.count++;
 	spin_unlock_irqrestore(&info->slock, flags);
 	retval = mxser_startup(info);
 	if (retval)
@@ -1170,42 +1162,42 @@
 		spin_unlock_irqrestore(&info->slock, flags);
 		return;
 	}
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Info->count should always
+		 * structure will be freed.  Info->port.count should always
 		 * be one in these conditions.  If it's greater than
 		 * one, we've got real problems, since it means the
 		 * serial port won't be shutdown.
 		 */
 		printk(KERN_ERR "mxser_close: bad serial port count; "
-			"tty->count is 1, info->count is %d\n", info->count);
-		info->count = 1;
+			"tty->count is 1, info->port.count is %d\n", info->port.count);
+		info->port.count = 1;
 	}
-	if (--info->count < 0) {
+	if (--info->port.count < 0) {
 		printk(KERN_ERR "mxser_close: bad serial port count for "
-			"ttys%d: %d\n", tty->index, info->count);
-		info->count = 0;
+			"ttys%d: %d\n", tty->index, info->port.count);
+		info->port.count = 0;
 	}
-	if (info->count) {
+	if (info->port.count) {
 		spin_unlock_irqrestore(&info->slock, flags);
 		return;
 	}
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 	spin_unlock_irqrestore(&info->slock, flags);
 	/*
 	 * Save the termios structure, since this port may have
 	 * separate termios for callout and dialin.
 	 */
-	if (info->flags & ASYNC_NORMAL_ACTIVE)
+	if (info->port.flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->port.closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1216,7 +1208,7 @@
 	if (info->board->chip_flag)
 		info->IER &= ~MOXA_MUST_RECV_ISR;
 
-	if (info->flags & ASYNC_INITIALIZED) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
 		outb(info->IER, info->ioaddr + UART_IER);
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
@@ -1236,15 +1228,14 @@
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	info->event = 0;
-	info->tty = NULL;
-	if (info->blocked_open) {
-		if (info->close_delay)
-			schedule_timeout_interruptible(info->close_delay);
-		wake_up_interruptible(&info->open_wait);
+	info->port.tty = NULL;
+	if (info->port.blocked_open) {
+		if (info->port.close_delay)
+			schedule_timeout_interruptible(info->port.close_delay);
+		wake_up_interruptible(&info->port.open_wait);
 	}
 
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 }
 
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1253,7 +1244,7 @@
 	struct mxser_port *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!info->xmit_buf)
+	if (!info->port.xmit_buf)
 		return 0;
 
 	while (1) {
@@ -1262,7 +1253,7 @@
 		if (c <= 0)
 			break;
 
-		memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
 		spin_lock_irqsave(&info->slock, flags);
 		info->xmit_head = (info->xmit_head + c) &
 				  (SERIAL_XMIT_SIZE - 1);
@@ -1294,14 +1285,14 @@
 	struct mxser_port *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!info->xmit_buf)
+	if (!info->port.xmit_buf)
 		return 0;
 
 	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
 		return 0;
 
 	spin_lock_irqsave(&info->slock, flags);
-	info->xmit_buf[info->xmit_head++] = ch;
+	info->port.xmit_buf[info->xmit_head++] = ch;
 	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
 	info->xmit_cnt++;
 	spin_unlock_irqrestore(&info->slock, flags);
@@ -1327,7 +1318,7 @@
 
 	if (info->xmit_cnt <= 0 ||
 			tty->stopped ||
-			!info->xmit_buf ||
+			!info->port.xmit_buf ||
 			(tty->hw_stopped &&
 			 (info->type != PORT_16550A) &&
 			 (!info->board->chip_flag)
@@ -1370,13 +1361,13 @@
 {
 	struct serial_struct tmp = {
 		.type = info->type,
-		.line = info->tty->index,
+		.line = info->port.tty->index,
 		.port = info->ioaddr,
 		.irq = info->board->irq,
-		.flags = info->flags,
+		.flags = info->port.flags,
 		.baud_base = info->baud_base,
-		.close_delay = info->close_delay,
-		.closing_wait = info->closing_wait,
+		.close_delay = info->port.close_delay,
+		.closing_wait = info->port.closing_wait,
 		.custom_divisor = info->custom_divisor,
 		.hub6 = 0
 	};
@@ -1403,33 +1394,33 @@
 			new_serial.port != info->ioaddr)
 		return -EINVAL;
 
-	flags = info->flags & ASYNC_SPD_MASK;
+	flags = info->port.flags & ASYNC_SPD_MASK;
 
 	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
-				(new_serial.close_delay != info->close_delay) ||
-				((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+				(new_serial.close_delay != info->port.close_delay) ||
+				((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+		info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
 				(new_serial.flags & ASYNC_USR_MASK));
 	} else {
 		/*
 		 * OK, past this point, all the error checking has been done.
 		 * At this point, we start making changes.....
 		 */
-		info->flags = ((info->flags & ~ASYNC_FLAGS) |
+		info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
 				(new_serial.flags & ASYNC_FLAGS));
-		info->close_delay = new_serial.close_delay * HZ / 100;
-		info->closing_wait = new_serial.closing_wait * HZ / 100;
-		info->tty->low_latency =
-				(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-		info->tty->low_latency = 0;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
+		info->port.close_delay = new_serial.close_delay * HZ / 100;
+		info->port.closing_wait = new_serial.closing_wait * HZ / 100;
+		info->port.tty->low_latency =
+				(info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+		info->port.tty->low_latency = 0;
+		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
 				(new_serial.baud_base != info->baud_base ||
 				new_serial.custom_divisor !=
 				info->custom_divisor)) {
 			baud = new_serial.baud_base / new_serial.custom_divisor;
-			tty_encode_baud_rate(info->tty, baud, baud);
+			tty_encode_baud_rate(info->port.tty, baud, baud);
 		}
 	}
 
@@ -1437,8 +1428,8 @@
 
 	process_txrx_fifo(info);
 
-	if (info->flags & ASYNC_INITIALIZED) {
-		if (flags != (info->flags & ASYNC_SPD_MASK)) {
+	if (info->port.flags & ASYNC_INITIALIZED) {
+		if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
 			spin_lock_irqsave(&info->slock, sl_flags);
 			mxser_change_speed(info, NULL);
 			spin_unlock_irqrestore(&info->slock, sl_flags);
@@ -1693,12 +1684,12 @@
 					continue;
 				}
 
-				if (!port->tty || !port->tty->termios)
+				if (!port->port.tty || !port->port.tty->termios)
 					GMStatus[i].cflag =
 						port->normal_termios.c_cflag;
 				else
 					GMStatus[i].cflag =
-						port->tty->termios->c_cflag;
+						port->port.tty->termios->c_cflag;
 
 				status = inb(port->ioaddr + UART_MSR);
 				if (status & 0x80 /*UART_MSR_DCD */ )
@@ -1755,14 +1746,14 @@
 				mon_data_ext.modem_status[i] =
 					port->mon_data.modem_status;
 				mon_data_ext.baudrate[i] =
-					tty_get_baud_rate(port->tty);
+					tty_get_baud_rate(port->port.tty);
 
-				if (!port->tty || !port->tty->termios) {
+				if (!port->port.tty || !port->port.tty->termios) {
 					cflag = port->normal_termios.c_cflag;
 					iflag = port->normal_termios.c_iflag;
 				} else {
-					cflag = port->tty->termios->c_cflag;
-					iflag = port->tty->termios->c_iflag;
+					cflag = port->port.tty->termios->c_cflag;
+					iflag = port->port.tty->termios->c_iflag;
 				}
 
 				mon_data_ext.databits[i] = cflag & CSIZE;
@@ -1989,7 +1980,7 @@
 		else
 			info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-		if (info->tty->hw_stopped)
+		if (info->port.tty->hw_stopped)
 			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
 		else
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -2038,7 +2029,7 @@
 		}
 	}
 
-	if (info->tty->termios->c_cflag & CRTSCTS) {
+	if (info->port.tty->termios->c_cflag & CRTSCTS) {
 		info->MCR &= ~UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -2075,7 +2066,7 @@
 		}
 	}
 
-	if (info->tty->termios->c_cflag & CRTSCTS) {
+	if (info->port.tty->termios->c_cflag & CRTSCTS) {
 		info->MCR |= UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -2106,7 +2097,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
-	if (info->xmit_cnt && info->xmit_buf) {
+	if (info->xmit_cnt && info->port.xmit_buf) {
 		outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
 		info->IER |= UART_IER_THRI;
 		outb(info->IER, info->ioaddr + UART_IER);
@@ -2219,11 +2210,10 @@
 
 	mxser_flush_buffer(tty);
 	mxser_shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	info->port.count = 0;
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->port.tty = NULL;
+	wake_up_interruptible(&info->port.open_wait);
 }
 
 /*
@@ -2246,7 +2236,7 @@
 
 static void mxser_receive_chars(struct mxser_port *port, int *status)
 {
-	struct tty_struct *tty = port->tty;
+	struct tty_struct *tty = port->port.tty;
 	unsigned char ch, gdl;
 	int ignored = 0;
 	int cnt = 0;
@@ -2302,7 +2292,7 @@
 					flag = TTY_BREAK;
 					port->icount.brk++;
 
-					if (port->flags & ASYNC_SAK)
+					if (port->port.flags & ASYNC_SAK)
 						do_SAK(tty);
 				} else if (*status & UART_LSR_PE) {
 					flag = TTY_PARITY;
@@ -2333,7 +2323,7 @@
 	} while (*status & UART_LSR_DR);
 
 end_intr:
-	mxvar_log.rxcnt[port->tty->index] += cnt;
+	mxvar_log.rxcnt[port->port.tty->index] += cnt;
 	port->mon_data.rxcnt += cnt;
 	port->mon_data.up_rxcnt += cnt;
 
@@ -2354,18 +2344,18 @@
 	if (port->x_char) {
 		outb(port->x_char, port->ioaddr + UART_TX);
 		port->x_char = 0;
-		mxvar_log.txcnt[port->tty->index]++;
+		mxvar_log.txcnt[port->port.tty->index]++;
 		port->mon_data.txcnt++;
 		port->mon_data.up_txcnt++;
 		port->icount.tx++;
 		return;
 	}
 
-	if (port->xmit_buf == NULL)
+	if (port->port.xmit_buf == NULL)
 		return;
 
-	if ((port->xmit_cnt <= 0) || port->tty->stopped ||
-			(port->tty->hw_stopped &&
+	if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
+			(port->port.tty->hw_stopped &&
 			(port->type != PORT_16550A) &&
 			(!port->board->chip_flag))) {
 		port->IER &= ~UART_IER_THRI;
@@ -2376,20 +2366,20 @@
 	cnt = port->xmit_cnt;
 	count = port->xmit_fifo_size;
 	do {
-		outb(port->xmit_buf[port->xmit_tail++],
+		outb(port->port.xmit_buf[port->xmit_tail++],
 			port->ioaddr + UART_TX);
 		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
 		if (--port->xmit_cnt <= 0)
 			break;
 	} while (--count > 0);
-	mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
+	mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
 
 	port->mon_data.txcnt += (cnt - port->xmit_cnt);
 	port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
 	port->icount.tx += (cnt - port->xmit_cnt);
 
 	if (port->xmit_cnt < WAKEUP_CHARS)
-		tty_wakeup(port->tty);
+		tty_wakeup(port->port.tty);
 
 	if (port->xmit_cnt <= 0) {
 		port->IER &= ~UART_IER_THRI;
@@ -2440,9 +2430,9 @@
 				if (iir & UART_IIR_NO_INT)
 					break;
 				iir &= MOXA_MUST_IIR_MASK;
-				if (!port->tty ||
-						(port->flags & ASYNC_CLOSING) ||
-						!(port->flags &
+				if (!port->port.tty ||
+						(port->port.flags & ASYNC_CLOSING) ||
+						!(port->port.flags &
 							ASYNC_INITIALIZED)) {
 					status = inb(port->ioaddr + UART_LSR);
 					outb(0x27, port->ioaddr + UART_FCR);
@@ -2550,6 +2540,7 @@
 
 	for (i = 0; i < brd->info->nports; i++) {
 		info = &brd->ports[i];
+		tty_port_init(&info->port);
 		info->board = brd;
 		info->stop_rx = 0;
 		info->ldisc_stop_rx = 0;
@@ -2558,16 +2549,15 @@
 		if (brd->chip_flag != MOXA_OTHER_UART)
 			mxser_enable_must_enchance_mode(info->ioaddr);
 
-		info->flags = ASYNC_SHARE_IRQ;
+		info->port.flags = ASYNC_SHARE_IRQ;
 		info->type = brd->uart_type;
 
 		process_txrx_fifo(info);
 
 		info->custom_divisor = info->baud_base * 16;
-		info->close_delay = 5 * HZ / 10;
-		info->closing_wait = 30 * HZ;
+		info->port.close_delay = 5 * HZ / 10;
+		info->port.closing_wait = 30 * HZ;
 		info->normal_termios = mxvar_sdriver->init_termios;
-		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->delta_msr_wait);
 		memset(&info->mon_data, 0, sizeof(struct mxser_mon));
 		info->err_shadow = 0;
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index a35bfd7..ed4e033 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -199,7 +199,7 @@
 #define tty2n_hdlc(tty)	((struct n_hdlc *) ((tty)->disc_data))
 #define n_hdlc2tty(n_hdlc)	((n_hdlc)->tty)
 
-static struct tty_ldisc n_hdlc_ldisc = {
+static struct tty_ldisc_ops n_hdlc_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
 	.name		= "hdlc",
@@ -342,8 +342,8 @@
 #endif
 	
 	/* Flush any pending characters in the driver and discipline. */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
+	if (tty->ldisc.ops->flush_buffer)
+		tty->ldisc.ops->flush_buffer(tty);
 
 	tty_driver_flush_buffer(tty);
 		
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 9021690..ae377aa 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -143,7 +143,7 @@
 static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 		char *fp, int count);
 
-static struct tty_ldisc tty_ldisc_N_R3964 = {
+static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
 	.owner = THIS_MODULE,
 	.magic = TTY_LDISC_MAGIC,
 	.name = "R3964",
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 8096389..708c2b1 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1573,7 +1573,7 @@
 	return mask;
 }
 
-struct tty_ldisc tty_ldisc_N_TTY = {
+struct tty_ldisc_ops tty_ldisc_N_TTY = {
 	.magic           = TTY_LDISC_MAGIC,
 	.name            = "n_tty",
 	.open            = n_tty_open,
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 197cd7a..a22662b 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -444,7 +444,7 @@
 
 	/* First test whether the driver should init at all */
 	if (!CHECK_DRIVER_INIT())
-		return -ENXIO;
+		return -ENODEV;
 
 	ret = misc_register(&nvram_dev);
 	if (ret) {
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index fb2fb15..b694d43 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -514,8 +514,8 @@
 		return;
 	ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if (ld->receive_buf)
-			ld->receive_buf(tty, data, flags, count);
+		if (ld->ops->receive_buf)
+			ld->ops->receive_buf(tty, data, flags, count);
 		tty_ldisc_deref(ld);
 	}
 }
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 0a05c03..76b2793 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -111,7 +111,7 @@
 	c = to->receive_room;
 	if (c > count)
 		c = count;
-	to->ldisc.receive_buf(to, buf, NULL, c);
+	to->ldisc.ops->receive_buf(to, buf, NULL, c);
 	
 	return c;
 }
@@ -149,11 +149,11 @@
 	int count;
 
 	/* We should get the line discipline lock for "tty->link" */
-	if (!to || !to->ldisc.chars_in_buffer)
+	if (!to || !to->ldisc.ops->chars_in_buffer)
 		return 0;
 
 	/* The ldisc must report 0 if no characters available to be read */
-	count = to->ldisc.chars_in_buffer(to);
+	count = to->ldisc.ops->chars_in_buffer(to);
 
 	if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
 
@@ -186,8 +186,8 @@
 	if (!to)
 		return;
 	
-	if (to->ldisc.flush_buffer)
-		to->ldisc.flush_buffer(to);
+	if (to->ldisc.ops->flush_buffer)
+		to->ldisc.ops->flush_buffer(to);
 	
 	if (to->packet) {
 		spin_lock_irqsave(&tty->ctrl_lock, flags);
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index a03a538..5ab5167 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -35,9 +35,6 @@
  ***************************************************************************/
 
 #ifndef _cirrus_h
-#ifndef lint
-/* static char* _cirrus_h_sccs = "@(#)cirrus.h	1.16"; */
-#endif
 #define _cirrus_h 1
 
 /* Bit fields for particular registers shared with driver */
diff --git a/drivers/char/rio/cmdblk.h b/drivers/char/rio/cmdblk.h
index c46b2fd..9ed4f86 100644
--- a/drivers/char/rio/cmdblk.h
+++ b/drivers/char/rio/cmdblk.h
@@ -33,12 +33,6 @@
 #ifndef __rio_cmdblk_h__
 #define __rio_cmdblk_h__
 
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_cmdblk_h_sccs_ = "@(#)cmdblk.h	1.2";
-#endif
-#endif
-
 /*
 ** the structure of a command block, used to queue commands destined for
 ** a rup.
diff --git a/drivers/char/rio/cmdpkt.h b/drivers/char/rio/cmdpkt.h
index 357ae57..c1e7a27 100644
--- a/drivers/char/rio/cmdpkt.h
+++ b/drivers/char/rio/cmdpkt.h
@@ -32,12 +32,6 @@
 #ifndef __rio_cmdpkt_h__
 #define __rio_cmdpkt_h__
 
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_cmdpkt_h_sccs_ = "@(#)cmdpkt.h	1.2";
-#endif
-#endif
-
 /*
 ** overlays for the data area of a packet. Used in both directions
 ** (to build a packet to send, and to interpret a packet that arrives)
diff --git a/drivers/char/rio/daemon.h b/drivers/char/rio/daemon.h
index 6e63f8b..4af9032 100644
--- a/drivers/char/rio/daemon.h
+++ b/drivers/char/rio/daemon.h
@@ -33,12 +33,6 @@
 #ifndef	__rio_daemon_h__
 #define	__rio_daemon_h__
 
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_daemon_h_sccs_ = "@(#)daemon.h	1.3";
-#endif
-#endif
-
 
 /*
 ** structures used on /dev/rio
diff --git a/drivers/char/rio/errors.h b/drivers/char/rio/errors.h
index 1d0d891..bdb0523 100644
--- a/drivers/char/rio/errors.h
+++ b/drivers/char/rio/errors.h
@@ -33,12 +33,6 @@
 #ifndef	__rio_errors_h__
 #define	__rio_errors_h__
 
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_errors_h_sccs_ = "@(#)errors.h	1.2";
-#endif
-#endif
-
 /*
 ** error codes
 */
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
index 9e7283b..078d44f 100644
--- a/drivers/char/rio/func.h
+++ b/drivers/char/rio/func.h
@@ -35,12 +35,6 @@
 
 #include <linux/kdev_t.h>
 
-#ifdef SCCS_LABELS
-#ifndef lint
-static char *_func_h_sccs_ = "@(#)func.h	1.3";
-#endif
-#endif
-
 /* rioboot.c */
 int RIOBootCodeRTA(struct rio_info *, struct DownLoad *);
 int RIOBootCodeHOST(struct rio_info *, struct DownLoad *);
diff --git a/drivers/char/rio/map.h b/drivers/char/rio/map.h
index bdbcd09..8366978 100644
--- a/drivers/char/rio/map.h
+++ b/drivers/char/rio/map.h
@@ -33,10 +33,6 @@
 #ifndef __rio_map_h__
 #define __rio_map_h__
 
-#ifdef SCCS_LABELS
-static char *_map_h_sccs_ = "@(#)map.h	1.2";
-#endif
-
 /*
 ** mapping structure passed to and from the config.rio program to
 ** determine the current topology of the world
diff --git a/drivers/char/rio/param.h b/drivers/char/rio/param.h
index 675c200..7e9b628 100644
--- a/drivers/char/rio/param.h
+++ b/drivers/char/rio/param.h
@@ -33,11 +33,6 @@
 #ifndef __rio_param_h__
 #define __rio_param_h__
 
-#ifdef SCCS_LABELS
-static char *_param_h_sccs_ = "@(#)param.h	1.2";
-#endif
-
-
 /*
 ** the param command block, as used in OPEN and PARAM calls.
 */
diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h
index 9764ef8..acc8fa4 100644
--- a/drivers/char/rio/parmmap.h
+++ b/drivers/char/rio/parmmap.h
@@ -37,13 +37,6 @@
 #ifndef _parmap_h
 #define _parmap_h
 
-
-#ifdef SCCS_LABELS
-#ifndef lint
-/* static char *_rio_parmmap_h_sccs = "@(#)parmmap.h	1.4"; */
-#endif
-#endif
-
 typedef struct PARM_MAP PARM_MAP;
 
 struct PARM_MAP {
diff --git a/drivers/char/rio/pci.h b/drivers/char/rio/pci.h
index 1eba911..6032f91 100644
--- a/drivers/char/rio/pci.h
+++ b/drivers/char/rio/pci.h
@@ -33,10 +33,6 @@
 #ifndef __rio_pci_h__
 #define	__rio_pci_h__
 
-#ifdef SCCS_LABELS
-static char *_pci_h_sccs_ = "@(#)pci.h	1.2";
-#endif
-
 /*
 ** PCI stuff
 */
diff --git a/drivers/char/rio/protsts.h b/drivers/char/rio/protsts.h
index 69fc4bc..8ab7940 100644
--- a/drivers/char/rio/protsts.h
+++ b/drivers/char/rio/protsts.h
@@ -37,13 +37,6 @@
 #ifndef _protsts_h
 #define _protsts_h 1
 
-
-#ifdef SCCS_LABELS
-#ifndef lint
-/* static char *_rio_protsts_h_sccs = "@(#)protsts.h	1.4"; */
-#endif
-#endif
-
 /*************************************************
  * ACK bit. Last Packet received OK. Set by
  * rxpkt to indicate that the Packet has been
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 412777c..0cdfee1 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -25,11 +25,6 @@
  *      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  *      USA.
  *
- * Revision history:
- * $Log: rio.c,v $
- * Revision 1.1  1999/07/11 10:13:54  wolff
- * Initial revision
- *
  * */
 
 #include <linux/module.h>
@@ -436,7 +431,7 @@
 {
 	func_enter();
 
-	/*  port->gs.flags &= ~GS_TX_INTEN; */
+	/*  port->gs.port.flags &= ~GS_TX_INTEN; */
 
 	func_exit();
 }
@@ -460,7 +455,7 @@
 	 * In general we cannot count on "tx empty" interrupts, although
 	 * the interrupt routine seems to be able to tell the difference.
 	 */
-	PortP->gs.flags &= ~GS_TX_INTEN;
+	PortP->gs.port.flags &= ~GS_TX_INTEN;
 
 	func_exit();
 }
@@ -515,7 +510,7 @@
 	func_enter();
 
 	PortP = (struct Port *) ptr;
-	PortP->gs.tty = NULL;
+	PortP->gs.port.tty = NULL;
 	func_exit();
 }
 
@@ -534,7 +529,7 @@
 	func_enter();
 
 	PortP = (struct Port *) ptr;
-	PortP->gs.tty = NULL;
+	PortP->gs.port.tty = NULL;
 
 	func_exit();
 }
@@ -554,12 +549,12 @@
 
 	riotclose(ptr);
 
-	if (PortP->gs.count) {
-		printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.count);
-		PortP->gs.count = 0;
+	if (PortP->gs.port.count) {
+		printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.port.count);
+		PortP->gs.port.count = 0;
 	}
 
-	PortP->gs.tty = NULL;
+	PortP->gs.port.tty = NULL;
 	func_exit();
 }
 
@@ -854,8 +849,8 @@
 		/*
 		 * Initializing wait queue
 		 */
-		init_waitqueue_head(&port->gs.open_wait);
-		init_waitqueue_head(&port->gs.close_wait);
+		init_waitqueue_head(&port->gs.port.open_wait);
+		init_waitqueue_head(&port->gs.port.close_wait);
 	}
 #else
 	/* We could postpone initializing them to when they are configured. */
diff --git a/drivers/char/rio/rioboard.h b/drivers/char/rio/rioboard.h
index 822c071..2522300 100644
--- a/drivers/char/rio/rioboard.h
+++ b/drivers/char/rio/rioboard.h
@@ -29,12 +29,6 @@
 /*									*/
 /************************************************************************/
 
-/* History...
-
-1.0.0	26/04/99 NPV	Creation.
-
-*/
-
 #ifndef	_rioboard_h		/* If RIOBOARD.H not already defined */
 #define	_rioboard_h    1
 
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 7b96e08..01f2654 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -30,9 +30,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_riocmd_c_sccs_ = "@(#)riocmd.c	1.2";
-#endif
 
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -487,12 +484,12 @@
 				 ** If the device is a modem, then check the modem
 				 ** carrier.
 				 */
-				if (PortP->gs.tty == NULL)
+				if (PortP->gs.port.tty == NULL)
 					break;
-				if (PortP->gs.tty->termios == NULL)
+				if (PortP->gs.port.tty->termios == NULL)
 					break;
 
-				if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) {
+				if (!(PortP->gs.port.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) {
 
 					rio_dprintk(RIO_DEBUG_CMD, "Is there a Carrier?\n");
 					/*
@@ -509,7 +506,7 @@
 							 ** wakeup anyone in WOPEN
 							 */
 							if (PortP->State & (PORT_ISOPEN | RIO_WOPEN))
-								wake_up_interruptible(&PortP->gs.open_wait);
+								wake_up_interruptible(&PortP->gs.port.open_wait);
 						}
 					} else {
 						/*
@@ -517,7 +514,7 @@
 						 */
 						if (PortP->State & RIO_CARR_ON) {
 							if (PortP->State & (PORT_ISOPEN | RIO_WOPEN | RIO_MOPEN))
-								tty_hangup(PortP->gs.tty);
+								tty_hangup(PortP->gs.port.tty);
 							PortP->State &= ~RIO_CARR_ON;
 							rio_dprintk(RIO_DEBUG_CMD, "Carrirer just went down\n");
 						}
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index d65ceb9..eecee0f 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -29,10 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_rioctrl_c_sccs_ = "@(#)rioctrl.c	1.3";
-#endif
-
 
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/char/rio/riodrvr.h b/drivers/char/rio/riodrvr.h
index 3cffe27..0907e71 100644
--- a/drivers/char/rio/riodrvr.h
+++ b/drivers/char/rio/riodrvr.h
@@ -35,10 +35,6 @@
 
 #include <asm/param.h>		/* for HZ */
 
-#ifdef SCCS_LABELS
-static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h	1.3";
-#endif
-
 #define MEMDUMP_SIZE	32
 #define	MOD_DISABLE	(RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
 
diff --git a/drivers/char/rio/rioinfo.h b/drivers/char/rio/rioinfo.h
index 8de7966..42ff1e7 100644
--- a/drivers/char/rio/rioinfo.h
+++ b/drivers/char/rio/rioinfo.h
@@ -33,10 +33,6 @@
 #ifndef __rioinfo_h
 #define __rioinfo_h
 
-#ifdef SCCS_LABELS
-static char *_rioinfo_h_sccs_ = "@(#)rioinfo.h	1.2";
-#endif
-
 /*
 ** Host card data structure
 */
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
index add1718..be0ba40 100644
--- a/drivers/char/rio/rioinit.c
+++ b/drivers/char/rio/rioinit.c
@@ -29,9 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_rioinit_c_sccs_ = "@(#)rioinit.c	1.3";
-#endif
 
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index ea21686..71f8760 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -29,10 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_riointr_c_sccs_ = "@(#)riointr.c	1.2";
-#endif
-
 
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -106,7 +102,7 @@
 
 	PortP = (struct Port *) en;
 	p = (struct rio_info *) PortP->p;
-	tty = PortP->gs.tty;
+	tty = PortP->gs.port.tty;
 
 
 	rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt);
@@ -162,7 +158,7 @@
 	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 
 	if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN))
-		tty_wakeup(PortP->gs.tty);
+		tty_wakeup(PortP->gs.port.tty);
 
 }
 
@@ -245,7 +241,7 @@
 			 ** find corresponding tty structure. The process of mapping
 			 ** the ports puts these here.
 			 */
-			ttyP = PortP->gs.tty;
+			ttyP = PortP->gs.port.tty;
 
 			/*
 			 ** Lock the port before we begin working on it.
@@ -339,7 +335,7 @@
 			 ** find corresponding tty structure. The process of mapping
 			 ** the ports puts these here.
 			 */
-			ttyP = PortP->gs.tty;
+			ttyP = PortP->gs.port.tty;
 			/* If ttyP is NULL, the port is getting closed. Forget about it. */
 			if (!ttyP) {
 				rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n");
@@ -546,7 +542,7 @@
 
 	intCount++;
 
-	TtyP = PortP->gs.tty;
+	TtyP = PortP->gs.port.tty;
 	if (!TtyP) {
 		rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n");
 		return;
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
index 4810b84..d687c17 100644
--- a/drivers/char/rio/rioparam.c
+++ b/drivers/char/rio/rioparam.c
@@ -30,10 +30,6 @@
 ** -----------------------------------------------------------------------------
 */
 
-#ifdef SCCS_LABELS
-static char *_rioparam_c_sccs_ = "@(#)rioparam.c	1.3";
-#endif
-
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
@@ -164,7 +160,7 @@
 
 	func_enter();
 
-	TtyP = PortP->gs.tty;
+	TtyP = PortP->gs.port.tty;
 
 	rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP);
 
diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c
index 7a9df7d..706c2a2 100644
--- a/drivers/char/rio/rioroute.c
+++ b/drivers/char/rio/rioroute.c
@@ -29,9 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_rioroute_c_sccs_ = "@(#)rioroute.c	1.3";
-#endif
 
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/char/rio/riospace.h b/drivers/char/rio/riospace.h
index 534f1f5..ffb31d4 100644
--- a/drivers/char/rio/riospace.h
+++ b/drivers/char/rio/riospace.h
@@ -33,10 +33,6 @@
 #ifndef __rio_riospace_h__
 #define __rio_riospace_h__
 
-#ifdef SCCS_LABELS
-static char *_riospace_h_sccs_ = "@(#)riospace.h	1.2";
-#endif
-
 #define	RIO_LOCATOR_LEN	16
 #define	MAX_RIO_BOARDS	4
 
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c
index 2b24488..3d15802 100644
--- a/drivers/char/rio/riotable.c
+++ b/drivers/char/rio/riotable.c
@@ -29,9 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_riotable_c_sccs_ = "@(#)riotable.c	1.2";
-#endif
 
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index c993548..2fb49e8 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -29,10 +29,6 @@
 **
 ** -----------------------------------------------------------------------------
 */
-#ifdef SCCS_LABELS
-static char *_riotty_c_sccs_ = "@(#)riotty.c	1.3";
-#endif
-
 
 #define __EXPLICIT_DEF_H__
 
@@ -144,14 +140,14 @@
 
 	tty->driver_data = PortP;
 
-	PortP->gs.tty = tty;
-	PortP->gs.count++;
+	PortP->gs.port.tty = tty;
+	PortP->gs.port.count++;
 
 	rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt);
 
 	retval = gs_init_port(&PortP->gs);
 	if (retval) {
-		PortP->gs.count--;
+		PortP->gs.port.count--;
 		return -ENXIO;
 	}
 	/*
@@ -297,7 +293,7 @@
 	 ** insert test for carrier here. -- ???
 	 ** I already see that test here. What's the deal? -- REW
 	 */
-	if ((PortP->gs.tty->termios->c_cflag & CLOCAL) ||
+	if ((PortP->gs.port.tty->termios->c_cflag & CLOCAL) ||
 			(PortP->ModemState & RIOC_MSVR1_CD)) {
 		rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
 		/*
@@ -305,16 +301,16 @@
 		   wakeup((caddr_t) &tp->tm.c_canq);
 		 */
 		PortP->State |= RIO_CARR_ON;
-		wake_up_interruptible(&PortP->gs.open_wait);
+		wake_up_interruptible(&PortP->gs.port.open_wait);
 	} else {	/* no carrier - wait for DCD */
 			/*
-		   while (!(PortP->gs.tty->termios->c_state & CARR_ON) &&
+		   while (!(PortP->gs.port.tty->termios->c_state & CARR_ON) &&
 		   !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted )
 		 */
 		while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) {
 				rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort);
 			/*
-			   PortP->gs.tty->termios->c_state |= WOPEN;
+			   PortP->gs.port.tty->termios->c_state |= WOPEN;
 			 */
 			PortP->State |= RIO_WOPEN;
 			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
@@ -384,7 +380,7 @@
 	/* PortP = p->RIOPortp[SysPort]; */
 	rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP);
 	/* tp = PortP->TtyP; *//* Get tty */
-	tty = PortP->gs.tty;
+	tty = PortP->gs.port.tty;
 	rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty);
 
 	if (PortP->gs.closing_wait)
diff --git a/drivers/char/rio/route.h b/drivers/char/rio/route.h
index 769744e..20ed73f 100644
--- a/drivers/char/rio/route.h
+++ b/drivers/char/rio/route.h
@@ -37,12 +37,6 @@
 #ifndef _route_h
 #define _route_h
 
-#ifdef SCCS_LABELS
-#ifndef lint
-/* static char *_rio_route_h_sccs = "@(#)route.h	1.3"; */
-#endif
-#endif
-
 #define MAX_LINKS 4
 #define MAX_NODES 17		/* Maximum nodes in a subnet */
 #define NODE_BYTES ((MAX_NODES / 8) + 1)	/* Number of bytes needed for
diff --git a/drivers/char/rio/unixrup.h b/drivers/char/rio/unixrup.h
index 46bd532..7abf0cb 100644
--- a/drivers/char/rio/unixrup.h
+++ b/drivers/char/rio/unixrup.h
@@ -33,10 +33,6 @@
 #ifndef __rio_unixrup_h__
 #define __rio_unixrup_h__
 
-#ifdef SCCS_LABELS
-static char *_unixrup_h_sccs_ = "@(#)unixrup.h	1.2";
-#endif
-
 /*
 **    UnixRup data structure. This contains pointers to actual RUPs on the
 **    host card, and all the command/boot control stuff.
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index f073c71..724b2b2 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -322,7 +322,7 @@
 	channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
 	if (channel < CD180_NCH)  {
 		port = &rc_port[board_No(bp) * RC_NPORT + channel];
-		if (port->flags & ASYNC_INITIALIZED)
+		if (port->port.flags & ASYNC_INITIALIZED)
 			return port;
 	}
 	printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
@@ -341,7 +341,7 @@
 	if (port == NULL)
 		return;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 #ifdef RC_REPORT_OVERRUN
 	status = rc_in(bp, CD180_RCSR);
@@ -364,7 +364,7 @@
 		printk(KERN_INFO "rc%d: port %d: Handling break...\n",
 		       board_No(bp), port_No(port));
 		flag = TTY_BREAK;
-		if (port->flags & ASYNC_SAK)
+		if (port->port.flags & ASYNC_SAK)
 			do_SAK(tty);
 
 	} else if (status & RCSR_PE)
@@ -392,7 +392,7 @@
 	if (port == NULL)
 		return;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	count = rc_in(bp, CD180_RDCR);
 
@@ -422,7 +422,7 @@
 	if (port == NULL)
 		return;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	if (port->IER & IER_TXEMPTY) {
 		/* FIFO drained */
@@ -467,7 +467,7 @@
 
 	count = CD180_NFIFO;
 	do {
-		rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
+		rc_out(bp, CD180_TDR, port->port.xmit_buf[port->xmit_tail++]);
 		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
 		if (--port->xmit_cnt <= 0)
 			break;
@@ -492,12 +492,12 @@
 	if (port == NULL)
 		return;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	mcr = rc_in(bp, CD180_MCR);
 	if (mcr & MCR_CDCHG) {
 		if (rc_in(bp, CD180_MSVR) & MSVR_CD)
-			wake_up_interruptible(&port->open_wait);
+			wake_up_interruptible(&port->port.open_wait);
 		else
 			tty_hangup(tty);
 	}
@@ -632,15 +632,12 @@
  */
 static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
 {
-	struct tty_struct *tty = port->tty;
+	struct tty_struct *tty = port->port.tty;
 	unsigned long baud;
 	long tmp;
 	unsigned char cor1 = 0, cor3 = 0;
 	unsigned char mcor1 = 0, mcor2 = 0;
 
-	if (tty == NULL || tty->termios == NULL)
-		return;
-
 	port->IER  = 0;
 	port->COR2 = 0;
 	port->MSVR = MSVR_RTS;
@@ -786,39 +783,30 @@
 {
 	unsigned long flags;
 
-	if (port->flags & ASYNC_INITIALIZED)
+	if (port->port.flags & ASYNC_INITIALIZED)
 		return 0;
 
-	if (!port->xmit_buf) {
-		/* We may sleep in get_zeroed_page() */
-		unsigned long tmp = get_zeroed_page(GFP_KERNEL);
-		if (tmp == 0)
-			return -ENOMEM;
-		if (port->xmit_buf)
-			free_page(tmp);
-		else
-			port->xmit_buf = (unsigned char *) tmp;
-	}
+	if (tty_port_alloc_xmit_buf(&port->port) < 0)
+		return -ENOMEM;
+
 	spin_lock_irqsave(&riscom_lock, flags);
 
-	if (port->tty)
-		clear_bit(TTY_IO_ERROR, &port->tty->flags);
-	if (port->count == 1)
+	clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	if (port->port.count == 1)
 		bp->count++;
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	rc_change_speed(bp, port);
-	port->flags |= ASYNC_INITIALIZED;
+	port->port.flags |= ASYNC_INITIALIZED;
 
 	spin_unlock_irqrestore(&riscom_lock, flags);
 	return 0;
 }
 
 /* Must be called with interrupts disabled */
-static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
+static void rc_shutdown_port(struct tty_struct *tty,
+			struct riscom_board *bp, struct riscom_port *port)
 {
-	struct tty_struct *tty;
-
-	if (!(port->flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED))
 		return;
 
 #ifdef RC_REPORT_OVERRUN
@@ -836,14 +824,8 @@
 		printk("].\n");
 	}
 #endif
-	if (port->xmit_buf)  {
-		free_page((unsigned long) port->xmit_buf);
-		port->xmit_buf = NULL;
-	}
-
-	tty = port->tty;
-
-	if (tty == NULL || C_HUPCL(tty)) {
+	tty_port_free_xmit_buf(&port->port);
+	if (C_HUPCL(tty)) {
 		/* Drop DTR */
 		bp->DTR |= (1u << port_No(port));
 		rc_out(bp, RC_DTR, bp->DTR);
@@ -858,9 +840,8 @@
 	port->IER = 0;
 	rc_out(bp, CD180_IER, port->IER);
 
-	if (tty)
-		set_bit(TTY_IO_ERROR, &tty->flags);
-	port->flags &= ~ASYNC_INITIALIZED;
+	set_bit(TTY_IO_ERROR, &tty->flags);
+	port->port.flags &= ~ASYNC_INITIALIZED;
 
 	if (--bp->count < 0)  {
 		printk(KERN_INFO "rc%d: rc_shutdown_port: "
@@ -890,9 +871,9 @@
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
 	 */
-	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&port->close_wait);
-		if (port->flags & ASYNC_HUP_NOTIFY)
+	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->port.close_wait);
+		if (port->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		else
 			return -ERESTARTSYS;
@@ -904,7 +885,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		port->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -919,16 +900,16 @@
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&port->open_wait, &wait);
+	add_wait_queue(&port->port.open_wait, &wait);
 
 	spin_lock_irqsave(&riscom_lock, flags);
 
 	if (!tty_hung_up_p(filp))
-		port->count--;
+		port->port.count--;
 
 	spin_unlock_irqrestore(&riscom_lock, flags);
 
-	port->blocked_open++;
+	port->port.blocked_open++;
 	while (1) {
 		spin_lock_irqsave(&riscom_lock, flags);
 
@@ -942,14 +923,14 @@
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
-		    !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
+		    !(port->port.flags & ASYNC_INITIALIZED)) {
+			if (port->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CLOSING) &&
+		if (!(port->port.flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		if (signal_pending(current)) {
@@ -959,14 +940,14 @@
 		schedule();
 	}
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&port->open_wait, &wait);
+	remove_wait_queue(&port->port.open_wait, &wait);
 	if (!tty_hung_up_p(filp))
-		port->count++;
-	port->blocked_open--;
+		port->port.count++;
+	port->port.blocked_open--;
 	if (retval)
 		return retval;
 
-	port->flags |= ASYNC_NORMAL_ACTIVE;
+	port->port.flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
 }
 
@@ -990,9 +971,9 @@
 	if (error)
 		return error;
 
-	port->count++;
+	port->port.count++;
 	tty->driver_data = port;
-	port->tty = tty;
+	port->port.tty = tty;
 
 	error = rc_setup_port(bp, port);
 	if (error == 0)
@@ -1031,28 +1012,28 @@
 		goto out;
 
 	bp = port_Board(port);
-	if ((tty->count == 1) && (port->count != 1))  {
+	if ((tty->count == 1) && (port->port.count != 1))  {
 		printk(KERN_INFO "rc%d: rc_close: bad port count;"
 		       " tty->count is 1, port count is %d\n",
-		       board_No(bp), port->count);
-		port->count = 1;
+		       board_No(bp), port->port.count);
+		port->port.count = 1;
 	}
-	if (--port->count < 0)  {
+	if (--port->port.count < 0)  {
 		printk(KERN_INFO "rc%d: rc_close: bad port count "
 				 "for tty%d: %d\n",
-		       board_No(bp), port_No(port), port->count);
-		port->count = 0;
+		       board_No(bp), port_No(port), port->port.count);
+		port->port.count = 0;
 	}
-	if (port->count)
+	if (port->port.count)
 		goto out;
-	port->flags |= ASYNC_CLOSING;
+	port->port.flags |= ASYNC_CLOSING;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, port->closing_wait);
+	if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, port->port.closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1060,7 +1041,7 @@
 	 * line status register.
 	 */
 	port->IER &= ~IER_RXD;
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (port->port.flags & ASYNC_INITIALIZED) {
 		port->IER &= ~IER_TXRDY;
 		port->IER |= IER_TXEMPTY;
 		rc_out(bp, CD180_CAR, port_No(port));
@@ -1077,19 +1058,19 @@
 				break;
 		}
 	}
-	rc_shutdown_port(bp, port);
+	rc_shutdown_port(tty, bp, port);
 	rc_flush_buffer(tty);
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	port->tty = NULL;
-	if (port->blocked_open) {
-		if (port->close_delay)
-			msleep_interruptible(jiffies_to_msecs(port->close_delay));
-		wake_up_interruptible(&port->open_wait);
+	port->port.tty = NULL;
+	if (port->port.blocked_open) {
+		if (port->port.close_delay)
+			msleep_interruptible(jiffies_to_msecs(port->port.close_delay));
+		wake_up_interruptible(&port->port.open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&port->close_wait);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&port->port.close_wait);
 
 out:
 	spin_unlock_irqrestore(&riscom_lock, flags);
@@ -1108,9 +1089,6 @@
 
 	bp = port_Board(port);
 
-	if (!tty || !port->xmit_buf)
-		return 0;
-
 	while (1) {
 		spin_lock_irqsave(&riscom_lock, flags);
 
@@ -1119,7 +1097,7 @@
 		if (c <= 0)
 			break;	/* lock continues to be held */
 
-		memcpy(port->xmit_buf + port->xmit_head, buf, c);
+		memcpy(port->port.xmit_buf + port->xmit_head, buf, c);
 		port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
 		port->xmit_cnt += c;
 
@@ -1151,15 +1129,12 @@
 	if (rc_paranoia_check(port, tty->name, "rc_put_char"))
 		return 0;
 
-	if (!tty || !port->xmit_buf)
-		return 0;
-
 	spin_lock_irqsave(&riscom_lock, flags);
 
 	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
 		goto out;
 
-	port->xmit_buf[port->xmit_head++] = ch;
+	port->port.xmit_buf[port->xmit_head++] = ch;
 	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
 	port->xmit_cnt++;
 	ret = 1;
@@ -1177,8 +1152,7 @@
 	if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
 		return;
 
-	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !port->xmit_buf)
+	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped)
 		return;
 
 	spin_lock_irqsave(&riscom_lock, flags);
@@ -1317,22 +1291,22 @@
 		return -EINVAL;
 #endif
 
-	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
+	change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
 			(tmp.flags & ASYNC_SPD_MASK));
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if ((tmp.close_delay != port->close_delay) ||
-		    (tmp.closing_wait != port->closing_wait) ||
+		if ((tmp.close_delay != port->port.close_delay) ||
+		    (tmp.closing_wait != port->port.closing_wait) ||
 		    ((tmp.flags & ~ASYNC_USR_MASK) !=
-		     (port->flags & ~ASYNC_USR_MASK)))
+		     (port->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
-		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
 			       (tmp.flags & ASYNC_USR_MASK));
 	} else  {
-		port->flags = ((port->flags & ~ASYNC_FLAGS) |
+		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
 			       (tmp.flags & ASYNC_FLAGS));
-		port->close_delay = tmp.close_delay;
-		port->closing_wait = tmp.closing_wait;
+		port->port.close_delay = tmp.close_delay;
+		port->port.closing_wait = tmp.closing_wait;
 	}
 	if (change_speed)  {
 		unsigned long flags;
@@ -1355,10 +1329,10 @@
 	tmp.line = port - rc_port;
 	tmp.port = bp->base;
 	tmp.irq  = bp->irq;
-	tmp.flags = port->flags;
+	tmp.flags = port->port.flags;
 	tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
-	tmp.close_delay = port->close_delay * HZ/100;
-	tmp.closing_wait = port->closing_wait * HZ/100;
+	tmp.close_delay = port->port.close_delay * HZ/100;
+	tmp.closing_wait = port->port.closing_wait * HZ/100;
 	tmp.xmit_fifo_size = CD180_NFIFO;
 	return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
@@ -1480,7 +1454,7 @@
 
 	spin_lock_irqsave(&riscom_lock, flags);
 
-	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
+	if (port->xmit_cnt && port->port.xmit_buf && !(port->IER & IER_TXRDY)) {
 		port->IER |= IER_TXRDY;
 		rc_out(bp, CD180_CAR, port_No(port));
 		rc_out(bp, CD180_IER, port->IER);
@@ -1498,11 +1472,11 @@
 
 	bp = port_Board(port);
 
-	rc_shutdown_port(bp, port);
-	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->tty = NULL;
-	wake_up_interruptible(&port->open_wait);
+	rc_shutdown_port(tty, bp, port);
+	port->port.count = 0;
+	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	port->port.tty = NULL;
+	wake_up_interruptible(&port->port.open_wait);
 }
 
 static void rc_set_termios(struct tty_struct *tty,
@@ -1575,11 +1549,8 @@
 	}
 	memset(rc_port, 0, sizeof(rc_port));
 	for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {
+		tty_port_init(&rc_port[i].port);
 		rc_port[i].magic = RISCOM8_MAGIC;
-		rc_port[i].close_delay = 50 * HZ / 100;
-		rc_port[i].closing_wait = 3000 * HZ / 100;
-		init_waitqueue_head(&rc_port[i].open_wait);
-		init_waitqueue_head(&rc_port[i].close_wait);
 	}
 	return 0;
 }
diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h
index cdfdf43..c9876b3 100644
--- a/drivers/char/riscom8.h
+++ b/drivers/char/riscom8.h
@@ -66,23 +66,15 @@
 	
 struct riscom_port {
 	int			magic;
+	struct			tty_port port;
 	int			baud_base;
-	int			flags;
-	struct tty_struct 	* tty;
-	int			count;
-	int			blocked_open;
 	int			timeout;
-	int			close_delay;
-	unsigned char 		* xmit_buf;
 	int			custom_divisor;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
 	short			wakeup_chars;
 	short			break_length;
-	unsigned short		closing_wait;
 	unsigned char		mark_mask;
 	unsigned char		IER;
 	unsigned char		MSVR;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 743dc80..e670eae 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -72,6 +72,7 @@
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
+#include <linux/serial.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
@@ -81,7 +82,7 @@
 #include <linux/completion.h>
 #include <linux/wait.h>
 #include <linux/pci.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/atomic.h>
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
@@ -434,15 +435,15 @@
 #endif
 	if (!info)
 		return;
-	if (!info->tty) {
+	if (!info->port.tty) {
 		printk(KERN_WARNING "rp: WARNING %s called with "
-				"info->tty==NULL\n", __func__);
+				"info->port.tty==NULL\n", __func__);
 		clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
 		return;
 	}
 
 	spin_lock_irqsave(&info->slock, flags);
-	tty = info->tty;
+	tty = info->port.tty;
 	info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
 
 	/*  Loop sending data to FIFO until done or FIFO full */
@@ -502,13 +503,13 @@
 				"info->flags & NOT_INIT\n");
 		return;
 	}
-	if (!info->tty) {
+	if (!info->port.tty) {
 		printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
-				"info->tty==NULL\n");
+				"info->port.tty==NULL\n");
 		return;
 	}
 	cp = &info->channel;
-	tty = info->tty;
+	tty = info->port.tty;
 
 	IntMask = sGetChanIntID(cp) & info->intmask;
 #ifdef ROCKET_DEBUG_INTR
@@ -530,7 +531,7 @@
 			tty_hangup(tty);
 		}
 		info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
 #ifdef ROCKET_DEBUG_INTR
 	if (IntMask & DELTA_CTS) {	/* CTS change */
@@ -648,9 +649,9 @@
 	info->board = board;
 	info->aiop = aiop;
 	info->chan = chan;
-	info->closing_wait = 3000;
-	info->close_delay = 50;
-	init_waitqueue_head(&info->open_wait);
+	info->port.closing_wait = 3000;
+	info->port.close_delay = 50;
+	init_waitqueue_head(&info->port.open_wait);
 	init_completion(&info->close_wait);
 	info->flags &= ~ROCKET_MODE_MASK;
 	switch (pc104[board][line]) {
@@ -717,7 +718,7 @@
 	unsigned rocketMode;
 	int bits, baud, divisor;
 	CHANNEL_t *cp;
-	struct ktermios *t = info->tty->termios;
+	struct ktermios *t = info->port.tty->termios;
 
 	cp = &info->channel;
 	cflag = t->c_cflag;
@@ -750,7 +751,7 @@
 	}
 
 	/* baud rate */
-	baud = tty_get_baud_rate(info->tty);
+	baud = tty_get_baud_rate(info->port.tty);
 	if (!baud)
 		baud = 9600;
 	divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
@@ -768,7 +769,7 @@
 	sSetBaud(cp, divisor);
 
 	/* FIXME: Should really back compute a baud rate from the divisor */
-	tty_encode_baud_rate(info->tty, baud, baud);
+	tty_encode_baud_rate(info->port.tty, baud, baud);
 
 	if (cflag & CRTSCTS) {
 		info->intmask |= DELTA_CTS;
@@ -793,15 +794,15 @@
 	 * Handle software flow control in the board
 	 */
 #ifdef ROCKET_SOFT_FLOW
-	if (I_IXON(info->tty)) {
+	if (I_IXON(info->port.tty)) {
 		sEnTxSoftFlowCtl(cp);
-		if (I_IXANY(info->tty)) {
+		if (I_IXANY(info->port.tty)) {
 			sEnIXANY(cp);
 		} else {
 			sDisIXANY(cp);
 		}
-		sSetTxXONChar(cp, START_CHAR(info->tty));
-		sSetTxXOFFChar(cp, STOP_CHAR(info->tty));
+		sSetTxXONChar(cp, START_CHAR(info->port.tty));
+		sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty));
 	} else {
 		sDisTxSoftFlowCtl(cp);
 		sDisIXANY(cp);
@@ -813,24 +814,24 @@
 	 * Set up ignore/read mask words
 	 */
 	info->read_status_mask = STMRCVROVRH | 0xFF;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= STMFRAMEH | STMPARITYH;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
 		info->read_status_mask |= STMBREAKH;
 
 	/*
 	 * Characters to ignore
 	 */
 	info->ignore_status_mask = 0;
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= STMBREAKH;
 		/*
 		 * If we're ignoring parity and break indicators,
 		 * ignore overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			info->ignore_status_mask |= STMRCVROVRH;
 	}
 
@@ -863,7 +864,7 @@
 	}
 }
 
-/*  info->count is considered critical, protected by spinlocks.  */
+/*  info->port.count is considered critical, protected by spinlocks.  */
 static int block_til_ready(struct tty_struct *tty, struct file *filp,
 			   struct r_port *info)
 {
@@ -897,13 +898,13 @@
 
 	/*
 	 * Block waiting for the carrier detect and the line to become free.  While we are in
-	 * this loop, info->count is dropped by one, so that rp_close() knows when to free things.  
+	 * this loop, info->port.count is dropped by one, so that rp_close() knows when to free things.
          * We restore it upon exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 #ifdef ROCKET_DEBUG_OPEN
-	printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count);
+	printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->port.count);
 #endif
 	spin_lock_irqsave(&info->slock, flags);
 
@@ -912,10 +913,10 @@
 #else
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
-		info->count--;
+		info->port.count--;
 	}
 #endif
-	info->blocked_open++;
+	info->port.blocked_open++;
 
 	spin_unlock_irqrestore(&info->slock, flags);
 
@@ -940,24 +941,24 @@
 		}
 #ifdef ROCKET_DEBUG_OPEN
 		printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
-		     info->line, info->count, info->flags);
+		     info->line, info->port.count, info->flags);
 #endif
 		schedule();	/*  Don't hold spinlock here, will hang PC */
 	}
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 
 	spin_lock_irqsave(&info->slock, flags);
 
 	if (extra_count)
-		info->count++;
-	info->blocked_open--;
+		info->port.count++;
+	info->port.blocked_open--;
 
 	spin_unlock_irqrestore(&info->slock, flags);
 
 #ifdef ROCKET_DEBUG_OPEN
 	printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
-	       info->line, info->count);
+	       info->line, info->port.count);
 #endif
 	if (retval)
 		return retval;
@@ -1001,9 +1002,9 @@
 		info->xmit_buf = (unsigned char *) page;
 
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
-	if (info->count++ == 0) {
+	if (info->port.count++ == 0) {
 		atomic_inc(&rp_num_ports_open);
 
 #ifdef ROCKET_DEBUG_OPEN
@@ -1012,7 +1013,7 @@
 #endif
 	}
 #ifdef ROCKET_DEBUG_OPEN
-	printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count);
+	printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
 #endif
 
 	/*
@@ -1048,13 +1049,13 @@
 		 * Set up the tty->alt_speed kludge
 		 */
 		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
-			info->tty->alt_speed = 57600;
+			info->port.tty->alt_speed = 57600;
 		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
-			info->tty->alt_speed = 115200;
+			info->port.tty->alt_speed = 115200;
 		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
-			info->tty->alt_speed = 230400;
+			info->port.tty->alt_speed = 230400;
 		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
-			info->tty->alt_speed = 460800;
+			info->port.tty->alt_speed = 460800;
 
 		configure_r_port(info, NULL);
 		if (tty->termios->c_cflag & CBAUD) {
@@ -1076,7 +1077,7 @@
 }
 
 /*
- *  Exception handler that closes a serial port. info->count is considered critical. 
+ *  Exception handler that closes a serial port. info->port.count is considered critical.
  */
 static void rp_close(struct tty_struct *tty, struct file *filp)
 {
@@ -1089,14 +1090,14 @@
 		return;
 
 #ifdef ROCKET_DEBUG_OPEN
-	printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count);
+	printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
 #endif
 
 	if (tty_hung_up_p(filp))
 		return;
 	spin_lock_irqsave(&info->slock, flags);
 
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -1105,15 +1106,15 @@
 		 * serial port won't be shutdown.
 		 */
 		printk(KERN_WARNING "rp_close: bad serial port count; "
-			"tty->count is 1, info->count is %d\n", info->count);
-		info->count = 1;
+			"tty->count is 1, info->port.count is %d\n", info->port.count);
+		info->port.count = 1;
 	}
-	if (--info->count < 0) {
+	if (--info->port.count < 0) {
 		printk(KERN_WARNING "rp_close: bad serial port count for "
-				"ttyR%d: %d\n", info->line, info->count);
-		info->count = 0;
+				"ttyR%d: %d\n", info->line, info->port.count);
+		info->port.count = 0;
 	}
-	if (info->count) {
+	if (info->port.count) {
 		spin_unlock_irqrestore(&info->slock, flags);
 		return;
 	}
@@ -1137,8 +1138,8 @@
 	/*
 	 * Wait for the transmit buffer to clear
 	 */
-	if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->port.closing_wait);
 	/*
 	 * Before we drop DTR, make sure the UART transmitter
 	 * has completely drained; this is especially
@@ -1167,11 +1168,11 @@
 
 	clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
 
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
+	if (info->port.blocked_open) {
+		if (info->port.close_delay) {
+			msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	} else {
 		if (info->xmit_buf) {
 			free_page((unsigned long) info->xmit_buf);
@@ -1327,8 +1328,8 @@
 	memset(&tmp, 0, sizeof (tmp));
 	tmp.line = info->line;
 	tmp.flags = info->flags;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
+	tmp.close_delay = info->port.close_delay;
+	tmp.closing_wait = info->port.closing_wait;
 	tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
 
 	if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
@@ -1353,17 +1354,17 @@
 	}
 
 	info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
+	info->port.close_delay = new_serial.close_delay;
+	info->port.closing_wait = new_serial.closing_wait;
 
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
-		info->tty->alt_speed = 57600;
+		info->port.tty->alt_speed = 57600;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
-		info->tty->alt_speed = 115200;
+		info->port.tty->alt_speed = 115200;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
-		info->tty->alt_speed = 230400;
+		info->port.tty->alt_speed = 230400;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
-		info->tty->alt_speed = 460800;
+		info->port.tty->alt_speed = 460800;
 
 	configure_r_port(info, NULL);
 	return 0;
@@ -1636,13 +1637,13 @@
 	rp_flush_buffer(tty);
 	if (info->flags & ROCKET_CLOSING)
 		return;
-	if (info->count) 
+	if (info->port.count)
 		atomic_dec(&rp_num_ports_open);
 	clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
 
-	info->count = 0;
+	info->port.count = 0;
 	info->flags &= ~ROCKET_NORMAL_ACTIVE;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
 	cp = &info->channel;
 	sDisRxFIFO(cp);
@@ -1653,7 +1654,7 @@
 	sClrTxXOFF(cp);
 	info->flags &= ~ROCKET_INITIALIZED;
 
-	wake_up_interruptible(&info->open_wait);
+	wake_up_interruptible(&info->port.open_wait);
 }
 
 /*
@@ -1762,7 +1763,7 @@
 
 	/*  Write remaining data into the port's xmit_buf */
 	while (1) {
-		if (!info->tty)		/* Seemingly obligatory check... */
+		if (!info->port.tty)		/* Seemingly obligatory check... */
 			goto end;
 		c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
 		c = min(c, XMIT_BUF_SIZE - info->xmit_head);
diff --git a/drivers/char/rocket.h b/drivers/char/rocket.h
index ae6b04f..a8b0919 100644
--- a/drivers/char/rocket.h
+++ b/drivers/char/rocket.h
@@ -64,8 +64,8 @@
 /*
  * For closing_wait and closing_wait2
  */
-#define ROCKET_CLOSING_WAIT_NONE	65535
-#define ROCKET_CLOSING_WAIT_INF		0
+#define ROCKET_CLOSING_WAIT_NONE	ASYNC_CLOSING_WAIT_NONE
+#define ROCKET_CLOSING_WAIT_INF		ASYNC_CLOSING_WAIT_INF
 
 /*
  * Rocketport ioctls -- "RP"
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 143cc43..21f3ff5 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1125,18 +1125,14 @@
 
 struct r_port {
 	int magic;
+	struct tty_port port;
 	int line;
-	int flags;
-	int count;
-	int blocked_open;
-	struct tty_struct *tty;
+	int flags;		/* Don't yet match the ASY_ flags!! */
 	unsigned int board:3;
 	unsigned int aiop:2;
 	unsigned int chan:3;
 	CONTROLLER_t *ctlp;
 	CHANNEL_t channel;
-	int closing_wait;
-	int close_delay;
 	int intmask;
 	int xmit_fifo_room;	/* room in xmit fifo */
 	unsigned char *xmit_buf;
@@ -1148,8 +1144,7 @@
 	int read_status_mask;
 	int cps;
 
-	wait_queue_head_t open_wait;
-	struct completion close_wait;
+	struct completion close_wait;	/* Not yet matching the core */
 	spinlock_t slock;
 	struct mutex write_mtx;
 };
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index d63f5cc..2978a49 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -327,7 +327,8 @@
 		}
 		count = sel_buffer_lth - pasted;
 		count = min(count, tty->receive_room);
-		tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count);
+		tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted,
+								NULL, count);
 		pasted += count;
 	}
 	remove_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 2ee4d98..037dc47 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -608,9 +608,9 @@
 	dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
 	if (channel < CD186x_NCH) {
 		port = &sx_port[board_No(bp) * SX_NPORT + channel];
-		dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel,  port, port->flags & ASYNC_INITIALIZED);
+		dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%lx\n",board_No(bp) * SX_NPORT + channel,  port, port->port.flags & ASYNC_INITIALIZED);
 
-		if (port->flags & ASYNC_INITIALIZED) {
+		if (port->port.flags & ASYNC_INITIALIZED) {
 			dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
 			func_exit();
 			return port;
@@ -637,7 +637,7 @@
 		func_exit();
 		return;
 	}
-	tty = port->tty;
+	tty = port->port.tty;
 
 	status = sx_in(bp, CD186x_RCSR);
 
@@ -673,7 +673,7 @@
 		dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
 		       board_No(bp), port_No(port));
 		flag = TTY_BREAK;
-		if (port->flags & ASYNC_SAK)
+		if (port->port.flags & ASYNC_SAK)
 			do_SAK(tty);
 
 	} else if (status & RCSR_PE)
@@ -707,7 +707,7 @@
 		func_exit();
 		return;
 	}
-	tty = port->tty;
+	tty = port->port.tty;
 
 	count = sx_in(bp, CD186x_RDCR);
 	dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
@@ -734,7 +734,7 @@
 		return;
 	}
 	dprintk (SX_DEBUG_TX, "port: %p\n", port);
-	tty = port->tty;
+	tty = port->port.tty;
 
 	if (port->IER & IER_TXEMPTY) {
 		/* FIFO drained */
@@ -811,7 +811,7 @@
 	if (!(port = sx_get_port(bp, "Modem")))
 		return;
 
-	tty = port->tty;
+	tty = port->port.tty;
 
 	mcr = sx_in(bp, CD186x_MCR);
 	printk ("mcr = %02x.\n", mcr);
@@ -821,7 +821,7 @@
 		msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
 		if (msvr_cd) {
 			dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
-			wake_up_interruptible(&port->open_wait);
+			wake_up_interruptible(&port->port.open_wait);
 		} else {
 			dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
 			tty_hangup(tty);
@@ -1030,7 +1030,7 @@
 
 	func_enter();
 
-	if (!(tty = port->tty) || !tty->termios) {
+	if (!(tty = port->port.tty) || !tty->termios) {
 		func_exit();
 		return;
 	}
@@ -1052,9 +1052,9 @@
 	baud = tty_get_baud_rate(tty);
 
 	if (baud == 38400) {
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			baud = 57600;
-		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			baud = 115200;
 	}
 
@@ -1244,7 +1244,7 @@
 
 	func_enter();
 
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (port->port.flags & ASYNC_INITIALIZED) {
 		func_exit();
 		return 0;
 	}
@@ -1268,12 +1268,12 @@
 
 	spin_lock_irqsave(&port->lock, flags);
 
-	if (port->tty)
-		clear_bit(TTY_IO_ERROR, &port->tty->flags);
+	if (port->port.tty)
+		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
 
 	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 	sx_change_speed(bp, port);
-	port->flags |= ASYNC_INITIALIZED;
+	port->port.flags |= ASYNC_INITIALIZED;
 
 	spin_unlock_irqrestore(&port->lock, flags);
 
@@ -1292,7 +1292,7 @@
 
 	func_enter();
 
-	if (!(port->flags & ASYNC_INITIALIZED)) {
+	if (!(port->port.flags & ASYNC_INITIALIZED)) {
 		func_exit();
 		return;
 	}
@@ -1315,7 +1315,7 @@
 	spin_lock_irqsave(&bp->lock, flags);
 	sx_out(bp, CD186x_CAR, port_No(port));
 
-	if (!(tty = port->tty) || C_HUPCL(tty)) {
+	if (!(tty = port->port.tty) || C_HUPCL(tty)) {
 		/* Drop DTR */
 		sx_out(bp, CD186x_MSVDTR, 0);
 	}
@@ -1330,7 +1330,7 @@
 	spin_unlock_irqrestore(&bp->lock, flags);
 	if (tty)
 		set_bit(TTY_IO_ERROR, &tty->flags);
-	port->flags &= ~ASYNC_INITIALIZED;
+	port->port.flags &= ~ASYNC_INITIALIZED;
 
 	if (!bp->count)
 		sx_shutdown_board(bp);
@@ -1354,9 +1354,9 @@
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
 	 */
-	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&port->close_wait);
-		if (port->flags & ASYNC_HUP_NOTIFY) {
+	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->port.close_wait);
+		if (port->port.flags & ASYNC_HUP_NOTIFY) {
 			func_exit();
 			return -EAGAIN;
 		} else {
@@ -1371,7 +1371,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		port->port.flags |= ASYNC_NORMAL_ACTIVE;
 		func_exit();
 		return 0;
 	}
@@ -1387,13 +1387,13 @@
 	 * exit, either normal or abnormal.
 	 */
 	retval = 0;
-	add_wait_queue(&port->open_wait, &wait);
+	add_wait_queue(&port->port.open_wait, &wait);
 	spin_lock_irqsave(&port->lock, flags);
 	if (!tty_hung_up_p(filp)) {
-		port->count--;
+		port->port.count--;
 	}
 	spin_unlock_irqrestore(&port->lock, flags);
-	port->blocked_open++;
+	port->port.blocked_open++;
 	while (1) {
 		spin_lock_irqsave(&bp->lock, flags);
 		sx_out(bp, CD186x_CAR, port_No(port));
@@ -1410,14 +1410,14 @@
 		spin_unlock_irqrestore(&bp->lock, flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
-		    !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
+		    !(port->port.flags & ASYNC_INITIALIZED)) {
+			if (port->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CLOSING) &&
+		if (!(port->port.flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		if (signal_pending(current)) {
@@ -1428,19 +1428,19 @@
 	}
 
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&port->open_wait, &wait);
+	remove_wait_queue(&port->port.open_wait, &wait);
 	spin_lock_irqsave(&port->lock, flags);
 	if (!tty_hung_up_p(filp)) {
-		port->count++;
+		port->port.count++;
 	}
-	port->blocked_open--;
+	port->port.blocked_open--;
 	spin_unlock_irqrestore(&port->lock, flags);
 	if (retval) {
 		func_exit();
 		return retval;
 	}
 
-	port->flags |= ASYNC_NORMAL_ACTIVE;
+	port->port.flags |= ASYNC_NORMAL_ACTIVE;
 	func_exit();
 	return 0;
 }
@@ -1484,10 +1484,10 @@
 	}
 
 	spin_lock_irqsave(&bp->lock, flags);
-	port->count++;
+	port->port.count++;
 	bp->count++;
 	tty->driver_data = port;
-	port->tty = tty;
+	port->port.tty = tty;
 	spin_unlock_irqrestore(&bp->lock, flags);
 
 	if ((error = sx_setup_port(bp, port))) {
@@ -1547,15 +1547,15 @@
 	}
 
 	bp = port_Board(port);
-	if ((tty->count == 1) && (port->count != 1)) {
+	if ((tty->count == 1) && (port->port.count != 1)) {
 		printk(KERN_ERR "sx%d: sx_close: bad port count;"
 		       " tty->count is 1, port count is %d\n",
-		       board_No(bp), port->count);
-		port->count = 1;
+		       board_No(bp), port->port.count);
+		port->port.count = 1;
 	}
 
-	if (port->count > 1) {
-		port->count--;
+	if (port->port.count > 1) {
+		port->port.count--;
 		bp->count--;
 
 		spin_unlock_irqrestore(&port->lock, flags);
@@ -1563,7 +1563,7 @@
 		func_exit();
 		return;
 	}
-	port->flags |= ASYNC_CLOSING;
+	port->port.flags |= ASYNC_CLOSING;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
@@ -1571,8 +1571,8 @@
 	tty->closing = 1;
 	spin_unlock_irqrestore(&port->lock, flags);
 	dprintk (SX_DEBUG_OPEN, "Closing\n");
-	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-		tty_wait_until_sent(tty, port->closing_wait);
+	if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+		tty_wait_until_sent(tty, port->port.closing_wait);
 	}
 	/*
 	 * At this point we stop accepting input.  To do this, we
@@ -1582,7 +1582,7 @@
 	 */
 	dprintk (SX_DEBUG_OPEN, "Closed\n");
 	port->IER &= ~IER_RXD;
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (port->port.flags & ASYNC_INITIALIZED) {
 		port->IER &= ~IER_TXRDY;
 		port->IER |= IER_TXEMPTY;
 		spin_lock_irqsave(&bp->lock, flags);
@@ -1611,10 +1611,10 @@
 		       board_No(bp), bp->count, tty->index);
 		bp->count = 0;
 	}
-	if (--port->count < 0) {
+	if (--port->port.count < 0) {
 		printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
-		       board_No(bp), port_No(port), port->count);
-		port->count = 0;
+		       board_No(bp), port_No(port), port->port.count);
+		port->port.count = 0;
 	}
 
 	sx_shutdown_port(bp, port);
@@ -1622,16 +1622,16 @@
 	tty_ldisc_flush(tty);
 	spin_lock_irqsave(&port->lock, flags);
 	tty->closing = 0;
-	port->tty = NULL;
+	port->port.tty = NULL;
 	spin_unlock_irqrestore(&port->lock, flags);
-	if (port->blocked_open) {
-		if (port->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(port->close_delay));
+	if (port->port.blocked_open) {
+		if (port->port.close_delay) {
+			msleep_interruptible(jiffies_to_msecs(port->port.close_delay));
 		}
-		wake_up_interruptible(&port->open_wait);
+		wake_up_interruptible(&port->port.open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&port->close_wait);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&port->port.close_wait);
 
 	func_exit();
 }
@@ -1815,7 +1815,7 @@
 	dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
 		port_No(port), status, sx_in (bp, CD186x_CAR));
 	dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
-	if (SX_CRTSCTS(port->tty)) {
+	if (SX_CRTSCTS(port->port.tty)) {
 		result  = /*   (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */
 		          |   ((status & MSVR_DTR) ? TIOCM_RTS : 0)
 		          |   ((status & MSVR_CD)  ? TIOCM_CAR : 0)
@@ -1857,7 +1857,7 @@
    /*   if (set & TIOCM_DTR)
 		port->MSVR |= MSVR_DTR; */
 
-	if (SX_CRTSCTS(port->tty)) {
+	if (SX_CRTSCTS(port->port.tty)) {
 		if (set & TIOCM_RTS)
 			port->MSVR |= MSVR_DTR;
 	} else {
@@ -1869,7 +1869,7 @@
 		port->MSVR &= ~MSVR_RTS; */
   /*    if (clear & TIOCM_DTR)
 		port->MSVR &= ~MSVR_DTR; */
-	if (SX_CRTSCTS(port->tty)) {
+	if (SX_CRTSCTS(port->port.tty)) {
 		if (clear & TIOCM_RTS)
 			port->MSVR &= ~MSVR_DTR;
 	} else {
@@ -1929,27 +1929,27 @@
 
 	lock_kernel();
 
-	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
+	change_speed = ((port->port.flags & ASYNC_SPD_MASK) !=
 			(tmp.flags & ASYNC_SPD_MASK));
 	change_speed |= (tmp.custom_divisor != port->custom_divisor);
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if ((tmp.close_delay != port->close_delay) ||
-		    (tmp.closing_wait != port->closing_wait) ||
+		if ((tmp.close_delay != port->port.close_delay) ||
+		    (tmp.closing_wait != port->port.closing_wait) ||
 		    ((tmp.flags & ~ASYNC_USR_MASK) !=
-		     (port->flags & ~ASYNC_USR_MASK))) {
+		     (port->port.flags & ~ASYNC_USR_MASK))) {
 			func_exit();
 			unlock_kernel();
 			return -EPERM;
 		}
-		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+		port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
 		                  (tmp.flags & ASYNC_USR_MASK));
 		port->custom_divisor = tmp.custom_divisor;
 	} else {
-		port->flags = ((port->flags & ~ASYNC_FLAGS) |
+		port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
 		                  (tmp.flags & ASYNC_FLAGS));
-		port->close_delay = tmp.close_delay;
-		port->closing_wait = tmp.closing_wait;
+		port->port.close_delay = tmp.close_delay;
+		port->port.closing_wait = tmp.closing_wait;
 		port->custom_divisor = tmp.custom_divisor;
 	}
 	if (change_speed) {
@@ -1975,10 +1975,10 @@
 	tmp.line = port - sx_port;
 	tmp.port = bp->base;
 	tmp.irq  = bp->irq;
-	tmp.flags = port->flags;
+	tmp.flags = port->port.flags;
 	tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC;
-	tmp.close_delay = port->close_delay * HZ/100;
-	tmp.closing_wait = port->closing_wait * HZ/100;
+	tmp.close_delay = port->port.close_delay * HZ/100;
+	tmp.closing_wait = port->port.closing_wait * HZ/100;
 	tmp.custom_divisor =  port->custom_divisor;
 	tmp.xmit_fifo_size = CD186x_NFIFO;
 	unlock_kernel();
@@ -2199,17 +2199,17 @@
 
 	sx_shutdown_port(bp, port);
 	spin_lock_irqsave(&port->lock, flags);
-	bp->count -= port->count;
+	bp->count -= port->port.count;
 	if (bp->count < 0) {
 		printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
 			board_No(bp), bp->count, tty->index);
 		bp->count = 0;
 	}
-	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->tty = NULL;
+	port->port.count = 0;
+	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	port->port.tty = NULL;
 	spin_unlock_irqrestore(&port->lock, flags);
-	wake_up_interruptible(&port->open_wait);
+	wake_up_interruptible(&port->port.open_wait);
 
 	func_exit();
 }
@@ -2224,10 +2224,6 @@
 	if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
 		return;
 
-	if (tty->termios->c_cflag == old_termios->c_cflag &&
-	    tty->termios->c_iflag == old_termios->c_iflag)
-		return;
-
 	bp = port_Board(port);
 	spin_lock_irqsave(&port->lock, flags);
 	sx_change_speed(port_Board(port), port);
@@ -2297,10 +2293,7 @@
 	memset(sx_port, 0, sizeof(sx_port));
 	for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
 		sx_port[i].magic = SPECIALIX_MAGIC;
-		sx_port[i].close_delay = 50 * HZ/100;
-		sx_port[i].closing_wait = 3000 * HZ/100;
-		init_waitqueue_head(&sx_port[i].open_wait);
-		init_waitqueue_head(&sx_port[i].close_wait);
+		tty_port_init(&sx_port[i].port);
 		spin_lock_init(&sx_port[i].lock);
 	}
 
diff --git a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h
index 3f2f85b..c630052 100644
--- a/drivers/char/specialix_io8.h
+++ b/drivers/char/specialix_io8.h
@@ -107,23 +107,17 @@
 
 struct specialix_port {
 	int			magic;
+	struct tty_port		port;
 	int			baud_base;
 	int			flags;
-	struct tty_struct 	* tty;
-	int			count;
-	int			blocked_open;
 	int			timeout;
-	int			close_delay;
 	unsigned char 		* xmit_buf;
 	int			custom_divisor;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
 	short			wakeup_chars;
 	short			break_length;
-	unsigned short		closing_wait;
 	unsigned char		mark_mask;
 	unsigned char		IER;
 	unsigned char		MSVR;
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index d17be10..0243efb 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -613,17 +613,17 @@
 {
 	unsigned int oldsigs = portp->sigs;
 
-	if (!portp->tty)
+	if (!portp->port.tty)
 		return;
 
 	portp->sigs = stl_getsignals(portp);
 
 	if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->port.open_wait);
 
 	if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
-		if (portp->flags & ASYNC_CHECK_CD)
-			tty_hangup(portp->tty);
+		if (portp->port.flags & ASYNC_CHECK_CD)
+			tty_hangup(portp->port.tty);
 }
 
 /*
@@ -734,11 +734,11 @@
  *	On the first open of the device setup the port hardware, and
  *	initialize the per port data structure.
  */
-	portp->tty = tty;
+	portp->port.tty = tty;
 	tty->driver_data = portp;
-	portp->refcount++;
+	portp->port.count++;
 
-	if ((portp->flags & ASYNC_INITIALIZED) == 0) {
+	if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
 		if (!portp->tx.buf) {
 			portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
 			if (!portp->tx.buf)
@@ -752,7 +752,7 @@
 		stl_enablerxtx(portp, 1, 1);
 		stl_startrxtx(portp, 1, 0);
 		clear_bit(TTY_IO_ERROR, &tty->flags);
-		portp->flags |= ASYNC_INITIALIZED;
+		portp->port.flags |= ASYNC_INITIALIZED;
 	}
 
 /*
@@ -761,9 +761,9 @@
  *	The sleep here does not need interrupt protection since the wakeup
  *	for it is done with the same context.
  */
-	if (portp->flags & ASYNC_CLOSING) {
-		interruptible_sleep_on(&portp->close_wait);
-		if (portp->flags & ASYNC_HUP_NOTIFY)
+	if (portp->port.flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&portp->port.close_wait);
+		if (portp->port.flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 		return -ERESTARTSYS;
 	}
@@ -777,7 +777,7 @@
 		if ((rc = stl_waitcarrier(portp, filp)) != 0)
 			return rc;
 
-	portp->flags |= ASYNC_NORMAL_ACTIVE;
+	portp->port.flags |= ASYNC_NORMAL_ACTIVE;
 
 	return 0;
 }
@@ -801,25 +801,25 @@
 
 	spin_lock_irqsave(&stallion_lock, flags);
 
-	if (portp->tty->termios->c_cflag & CLOCAL)
+	if (portp->port.tty->termios->c_cflag & CLOCAL)
 		doclocal++;
 
 	portp->openwaitcnt++;
 	if (! tty_hung_up_p(filp))
-		portp->refcount--;
+		portp->port.count--;
 
 	for (;;) {
 		/* Takes brd_lock internally */
 		stl_setsignals(portp, 1, 1);
 		if (tty_hung_up_p(filp) ||
-		    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
-			if (portp->flags & ASYNC_HUP_NOTIFY)
+		    ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
+			if (portp->port.flags & ASYNC_HUP_NOTIFY)
 				rc = -EBUSY;
 			else
 				rc = -ERESTARTSYS;
 			break;
 		}
-		if (((portp->flags & ASYNC_CLOSING) == 0) &&
+		if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
 		    (doclocal || (portp->sigs & TIOCM_CD)))
 			break;
 		if (signal_pending(current)) {
@@ -827,11 +827,11 @@
 			break;
 		}
 		/* FIXME */
-		interruptible_sleep_on(&portp->open_wait);
+		interruptible_sleep_on(&portp->port.open_wait);
 	}
 
 	if (! tty_hung_up_p(filp))
-		portp->refcount++;
+		portp->port.count++;
 	portp->openwaitcnt--;
 	spin_unlock_irqrestore(&stallion_lock, flags);
 
@@ -904,15 +904,15 @@
 		spin_unlock_irqrestore(&stallion_lock, flags);
 		return;
 	}
-	if ((tty->count == 1) && (portp->refcount != 1))
-		portp->refcount = 1;
-	if (portp->refcount-- > 1) {
+	if ((tty->count == 1) && (portp->port.count != 1))
+		portp->port.count = 1;
+	if (portp->port.count-- > 1) {
 		spin_unlock_irqrestore(&stallion_lock, flags);
 		return;
 	}
 
-	portp->refcount = 0;
-	portp->flags |= ASYNC_CLOSING;
+	portp->port.count = 0;
+	portp->port.flags |= ASYNC_CLOSING;
 
 /*
  *	May want to wait for any data to drain before closing. The BUSY
@@ -930,7 +930,7 @@
 
 
 	spin_lock_irqsave(&stallion_lock, flags);
-	portp->flags &= ~ASYNC_INITIALIZED;
+	portp->port.flags &= ~ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&stallion_lock, flags);
 
 	stl_disableintrs(portp);
@@ -949,16 +949,16 @@
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	portp->tty = NULL;
+	portp->port.tty = NULL;
 
 	if (portp->openwaitcnt) {
 		if (portp->close_delay)
 			msleep_interruptible(jiffies_to_msecs(portp->close_delay));
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->port.open_wait);
 	}
 
-	portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&portp->close_wait);
+	portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&portp->port.close_wait);
 }
 
 /*****************************************************************************/
@@ -1153,7 +1153,7 @@
 	memset(&sio, 0, sizeof(struct serial_struct));
 	sio.line = portp->portnr;
 	sio.port = portp->ioaddr;
-	sio.flags = portp->flags;
+	sio.flags = portp->port.flags;
 	sio.baud_base = portp->baud_base;
 	sio.close_delay = portp->close_delay;
 	sio.closing_wait = portp->closing_wait;
@@ -1194,17 +1194,17 @@
 		if ((sio.baud_base != portp->baud_base) ||
 		    (sio.close_delay != portp->close_delay) ||
 		    ((sio.flags & ~ASYNC_USR_MASK) !=
-		    (portp->flags & ~ASYNC_USR_MASK)))
+		    (portp->port.flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
 	} 
 
-	portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+	portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
 		(sio.flags & ASYNC_USR_MASK);
 	portp->baud_base = sio.baud_base;
 	portp->close_delay = sio.close_delay;
 	portp->closing_wait = sio.closing_wait;
 	portp->custom_divisor = sio.custom_divisor;
-	stl_setport(portp, portp->tty->termios);
+	stl_setport(portp, portp->port.tty->termios);
 	return 0;
 }
 
@@ -1353,7 +1353,7 @@
 		stl_start(tty);
 	}
 	if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->port.open_wait);
 }
 
 /*****************************************************************************/
@@ -1438,7 +1438,7 @@
 	if (portp == NULL)
 		return;
 
-	portp->flags &= ~ASYNC_INITIALIZED;
+	portp->port.flags &= ~ASYNC_INITIALIZED;
 	stl_disableintrs(portp);
 	if (tty->termios->c_cflag & HUPCL)
 		stl_setsignals(portp, 0, 0);
@@ -1452,10 +1452,10 @@
 		portp->tx.head = NULL;
 		portp->tx.tail = NULL;
 	}
-	portp->tty = NULL;
-	portp->flags &= ~ASYNC_NORMAL_ACTIVE;
-	portp->refcount = 0;
-	wake_up_interruptible(&portp->open_wait);
+	portp->port.tty = NULL;
+	portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	portp->port.count = 0;
+	wake_up_interruptible(&portp->port.open_wait);
 }
 
 /*****************************************************************************/
@@ -1814,8 +1814,8 @@
 		portp->baud_base = STL_BAUDBASE;
 		portp->close_delay = STL_CLOSEDELAY;
 		portp->closing_wait = 30 * HZ;
-		init_waitqueue_head(&portp->open_wait);
-		init_waitqueue_head(&portp->close_wait);
+		init_waitqueue_head(&portp->port.open_wait);
+		init_waitqueue_head(&portp->port.close_wait);
 		portp->stats.brd = portp->brdnr;
 		portp->stats.panel = portp->panelnr;
 		portp->stats.port = portp->portnr;
@@ -1840,8 +1840,8 @@
 			portp = panelp->ports[k];
 			if (portp == NULL)
 				continue;
-			if (portp->tty != NULL)
-				stl_hangup(portp->tty);
+			if (portp->port.tty != NULL)
+				stl_hangup(portp->port.tty);
 			kfree(portp->tx.buf);
 			kfree(portp);
 		}
@@ -2513,7 +2513,7 @@
 	}
 
 	portp->stats.state = portp->istate;
-	portp->stats.flags = portp->flags;
+	portp->stats.flags = portp->port.flags;
 	portp->stats.hwid = portp->hwid;
 
 	portp->stats.ttystate = 0;
@@ -2524,16 +2524,16 @@
 	portp->stats.rxbuffered = 0;
 
 	spin_lock_irqsave(&stallion_lock, flags);
-	if (portp->tty != NULL)
-		if (portp->tty->driver_data == portp) {
-			portp->stats.ttystate = portp->tty->flags;
+	if (portp->port.tty != NULL)
+		if (portp->port.tty->driver_data == portp) {
+			portp->stats.ttystate = portp->port.tty->flags;
 			/* No longer available as a statistic */
-			portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */
-			if (portp->tty->termios != NULL) {
-				portp->stats.cflags = portp->tty->termios->c_cflag;
-				portp->stats.iflags = portp->tty->termios->c_iflag;
-				portp->stats.oflags = portp->tty->termios->c_oflag;
-				portp->stats.lflags = portp->tty->termios->c_lflag;
+			portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
+			if (portp->port.tty->termios != NULL) {
+				portp->stats.cflags = portp->port.tty->termios->c_cflag;
+				portp->stats.iflags = portp->port.tty->termios->c_iflag;
+				portp->stats.oflags = portp->port.tty->termios->c_oflag;
+				portp->stats.lflags = portp->port.tty->termios->c_lflag;
 			}
 		}
 	spin_unlock_irqrestore(&stallion_lock, flags);
@@ -2939,15 +2939,15 @@
 	}
 	baudrate = stl_baudrates[baudrate];
 	if ((tiosp->c_cflag & CBAUD) == B38400) {
-		if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			baudrate = 57600;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			baudrate = 115200;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			baudrate = 230400;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			baudrate = 460800;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 			baudrate = (portp->baud_base / portp->custom_divisor);
 	}
 	if (baudrate > STL_CD1400MAXBAUD)
@@ -2969,9 +2969,9 @@
 		mcor1 |= MCOR1_DCD;
 		mcor2 |= MCOR2_DCD;
 		sreron |= SRER_MODEM;
-		portp->flags |= ASYNC_CHECK_CD;
+		portp->port.flags |= ASYNC_CHECK_CD;
 	} else
-		portp->flags &= ~ASYNC_CHECK_CD;
+		portp->port.flags &= ~ASYNC_CHECK_CD;
 
 /*
  *	Setup cd1400 enhanced modes if we can. In particular we want to
@@ -3242,7 +3242,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return;
 
@@ -3304,7 +3304,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return;
 
@@ -3503,8 +3503,8 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		if (portp->tty)
-			tty_wakeup(portp->tty);
+		if (portp->port.tty)
+			tty_wakeup(portp->port.tty);
 	}
 
 	if (len == 0) {
@@ -3568,7 +3568,7 @@
 		return;
 	}
 	portp = panelp->ports[(ioack >> 3)];
-	tty = portp->tty;
+	tty = portp->port.tty;
 
 	if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
 		outb((RDCR + portp->uartaddr), ioaddr);
@@ -3613,7 +3613,7 @@
 			if (portp->rxmarkmsk & status) {
 				if (status & ST_BREAK) {
 					status = TTY_BREAK;
-					if (portp->flags & ASYNC_SAK) {
+					if (portp->port.flags & ASYNC_SAK) {
 						do_SAK(tty);
 						BRDENABLE(portp->brdnr, portp->pagenr);
 					}
@@ -3899,15 +3899,15 @@
 	}
 	baudrate = stl_baudrates[baudrate];
 	if ((tiosp->c_cflag & CBAUD) == B38400) {
-		if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			baudrate = 57600;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			baudrate = 115200;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			baudrate = 230400;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			baudrate = 460800;
-		else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+		else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 			baudrate = (portp->baud_base / portp->custom_divisor);
 	}
 	if (baudrate > STL_SC26198MAXBAUD)
@@ -3922,11 +3922,11 @@
  *	Check what form of modem signaling is required and set it up.
  */
 	if (tiosp->c_cflag & CLOCAL) {
-		portp->flags &= ~ASYNC_CHECK_CD;
+		portp->port.flags &= ~ASYNC_CHECK_CD;
 	} else {
 		iopr |= IOPR_DCDCOS;
 		imron |= IR_IOPORT;
-		portp->flags |= ASYNC_CHECK_CD;
+		portp->port.flags |= ASYNC_CHECK_CD;
 	}
 
 /*
@@ -4174,7 +4174,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return;
 
@@ -4243,7 +4243,7 @@
 
 	if (portp == NULL)
 		return;
-	tty = portp->tty;
+	tty = portp->port.tty;
 	if (tty == NULL)
 		return;
 
@@ -4421,8 +4421,8 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		if (portp->tty)
-			tty_wakeup(portp->tty);
+		if (portp->port.tty)
+			tty_wakeup(portp->port.tty);
 	}
 
 	if (len == 0) {
@@ -4475,7 +4475,7 @@
 
 	pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
 
-	tty = portp->tty;
+	tty = portp->port.tty;
 	ioaddr = portp->ioaddr;
 	outb(GIBCR, (ioaddr + XP_ADDR));
 	len = inb(ioaddr + XP_DATA) + 1;
@@ -4527,7 +4527,7 @@
 	struct tty_struct	*tty;
 	unsigned int		ioaddr;
 
-	tty = portp->tty;
+	tty = portp->port.tty;
 	ioaddr = portp->ioaddr;
 
 	if (status & SR_RXPARITY)
@@ -4544,7 +4544,7 @@
 		if (portp->rxmarkmsk & status) {
 			if (status & SR_RXBREAK) {
 				status = TTY_BREAK;
-				if (portp->flags & ASYNC_SAK) {
+				if (portp->port.flags & ASYNC_SAK) {
 					do_SAK(tty);
 					BRDENABLE(portp->brdnr, portp->pagenr);
 				}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index b1a7a8c..d5cffcd 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -1,4 +1,3 @@
-
 /* sx.c -- driver for the Specialix SX series cards. 
  *
  *  This driver will also support the older SI, and XIO cards.
@@ -930,7 +929,7 @@
 
 	func_enter2();
 
-	if (!port->gs.tty)
+	if (!port->gs.port.tty)
 		return 0;
 
 	/* What is this doing here? -- REW
@@ -941,19 +940,19 @@
 
 	sx_set_baud(port);
 
-#define CFLAG port->gs.tty->termios->c_cflag
+#define CFLAG port->gs.port.tty->termios->c_cflag
 	sx_write_channel_byte(port, hi_mr1,
-			(C_PARENB(port->gs.tty) ? MR1_WITH : MR1_NONE) |
-			(C_PARODD(port->gs.tty) ? MR1_ODD : MR1_EVEN) |
-			(C_CRTSCTS(port->gs.tty) ? MR1_RTS_RXFLOW : 0) |
+			(C_PARENB(port->gs.port.tty) ? MR1_WITH : MR1_NONE) |
+			(C_PARODD(port->gs.port.tty) ? MR1_ODD : MR1_EVEN) |
+			(C_CRTSCTS(port->gs.port.tty) ? MR1_RTS_RXFLOW : 0) |
 			(((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) |
 			(((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) |
 			(((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) |
 			(((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0));
 
 	sx_write_channel_byte(port, hi_mr2,
-			(C_CRTSCTS(port->gs.tty) ? MR2_CTS_TXFLOW : 0) |
-			(C_CSTOPB(port->gs.tty) ? MR2_2_STOP :
+			(C_CRTSCTS(port->gs.port.tty) ? MR2_CTS_TXFLOW : 0) |
+			(C_CSTOPB(port->gs.port.tty) ? MR2_2_STOP :
 			MR2_1_STOP));
 
 	switch (CFLAG & CSIZE) {
@@ -976,44 +975,44 @@
 	}
 
 	sx_write_channel_byte(port, hi_prtcl,
-			(I_IXON(port->gs.tty) ? SP_TXEN : 0) |
-			(I_IXOFF(port->gs.tty) ? SP_RXEN : 0) |
-			(I_IXANY(port->gs.tty) ? SP_TANY : 0) | SP_DCEN);
+			(I_IXON(port->gs.port.tty) ? SP_TXEN : 0) |
+			(I_IXOFF(port->gs.port.tty) ? SP_RXEN : 0) |
+			(I_IXANY(port->gs.port.tty) ? SP_TANY : 0) | SP_DCEN);
 
 	sx_write_channel_byte(port, hi_break,
-			(I_IGNBRK(port->gs.tty) ? BR_IGN : 0 |
-			I_BRKINT(port->gs.tty) ? BR_INT : 0));
+			(I_IGNBRK(port->gs.port.tty) ? BR_IGN : 0 |
+			I_BRKINT(port->gs.port.tty) ? BR_INT : 0));
 
-	sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.tty));
-	sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.tty));
-	sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.tty));
-	sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.tty));
+	sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.port.tty));
 
 	sx_reconfigure_port(port);
 
 	/* Tell line discipline whether we will do input cooking */
-	if (I_OTHER(port->gs.tty)) {
-		clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+	if (I_OTHER(port->gs.port.tty)) {
+		clear_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
 	} else {
-		set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+		set_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
 	}
 	sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
-			(unsigned int)port->gs.tty->termios->c_iflag,
-			I_OTHER(port->gs.tty));
+			(unsigned int)port->gs.port.tty->termios->c_iflag,
+			I_OTHER(port->gs.port.tty));
 
 /* Tell line discipline whether we will do output cooking.
  * If OPOST is set and no other output flags are set then we can do output
  * processing.  Even if only *one* other flag in the O_OTHER group is set
  * we do cooking in software.
  */
-	if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
-		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+	if (O_OPOST(port->gs.port.tty) && !O_OTHER(port->gs.port.tty)) {
+		set_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
 	} else {
-		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+		clear_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
 	}
 	sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
-			(unsigned int)port->gs.tty->termios->c_oflag,
-			O_OTHER(port->gs.tty));
+			(unsigned int)port->gs.port.tty->termios->c_oflag,
+			O_OTHER(port->gs.port.tty));
 	/* port->c_dcd = sx_get_CD (port); */
 	func_exit();
 	return 0;
@@ -1102,8 +1101,8 @@
 		sx_disable_tx_interrupts(port);
 	}
 
-	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
-		tty_wakeup(port->gs.tty);
+	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) {
+		tty_wakeup(port->gs.port.tty);
 		sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
 				port->gs.wakeup_chars);
 	}
@@ -1126,7 +1125,7 @@
 	unsigned char *rp;
 
 	func_enter2();
-	tty = port->gs.tty;
+	tty = port->gs.port.tty;
 	while (1) {
 		rx_op = sx_read_channel_byte(port, hi_rxopos);
 		c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff;
@@ -1211,12 +1210,12 @@
 				/* DCD went UP */
 				if ((sx_read_channel_byte(port, hi_hstat) !=
 						HS_IDLE_CLOSED) &&
-						!(port->gs.tty->termios->
+						!(port->gs.port.tty->termios->
 							c_cflag & CLOCAL)) {
 					/* Are we blocking in open? */
 					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
 						"active, unblocking open\n");
-					wake_up_interruptible(&port->gs.
+					wake_up_interruptible(&port->gs.port.
 							open_wait);
 				} else {
 					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
@@ -1224,10 +1223,10 @@
 				}
 			} else {
 				/* DCD went down! */
-				if (!(port->gs.tty->termios->c_cflag & CLOCAL)){
+				if (!(port->gs.port.tty->termios->c_cflag & CLOCAL)){
 					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
 						"dropped. hanging up....\n");
-					tty_hangup(port->gs.tty);
+					tty_hangup(port->gs.port.tty);
 				} else {
 					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
 						"dropped. ignoring.\n");
@@ -1325,7 +1324,7 @@
 
 	for (i = 0; i < board->nports; i++) {
 		port = &board->ports[i];
-		if (port->gs.flags & GS_ACTIVE) {
+		if (port->gs.port.flags & GS_ACTIVE) {
 			if (sx_read_channel_byte(port, hi_state)) {
 				sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: "
 						"modem signal change?... \n",i);
@@ -1334,7 +1333,7 @@
 			if (port->gs.xmit_cnt) {
 				sx_transmit_chars(port);
 			}
-			if (!(port->gs.flags & SX_RX_THROTTLE)) {
+			if (!(port->gs.port.flags & SX_RX_THROTTLE)) {
 				sx_receive_chars(port);
 			}
 		}
@@ -1373,7 +1372,7 @@
 	struct sx_port *port = ptr;
 	func_enter2();
 
-	port->gs.flags &= ~GS_TX_INTEN;
+	port->gs.port.flags &= ~GS_TX_INTEN;
 
 	func_exit();
 }
@@ -1394,7 +1393,7 @@
 
 	/* XXX Must be "HIGH_WATER" for SI card according to doc. */
 	if (data_in_buffer < LOW_WATER)
-		port->gs.flags &= ~GS_TX_INTEN;
+		port->gs.port.flags &= ~GS_TX_INTEN;
 
 	func_exit();
 }
@@ -1442,8 +1441,8 @@
 
 	func_enter();
 
-	port->gs.flags &= ~GS_ACTIVE;
-	if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) {
+	port->gs.port.flags &= ~GS_ACTIVE;
+	if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
 		sx_setsignals(port, 0, 0);
 		sx_reconfigure_port(port);
 	}
@@ -1485,8 +1484,8 @@
 	spin_lock_irqsave(&port->gs.driver_lock, flags);
 
 	tty->driver_data = port;
-	port->gs.tty = tty;
-	port->gs.count++;
+	port->gs.port.tty = tty;
+	port->gs.port.count++;
 	spin_unlock_irqrestore(&port->gs.driver_lock, flags);
 
 	sx_dprintk(SX_DEBUG_OPEN, "starting port\n");
@@ -1497,12 +1496,12 @@
 	retval = gs_init_port(&port->gs);
 	sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");
 	if (retval) {
-		port->gs.count--;
+		port->gs.port.count--;
 		return retval;
 	}
 
-	port->gs.flags |= GS_ACTIVE;
-	if (port->gs.count <= 1)
+	port->gs.port.flags |= GS_ACTIVE;
+	if (port->gs.port.count <= 1)
 		sx_setsignals(port, 1, 1);
 
 #if 0
@@ -1513,12 +1512,12 @@
 		my_hd_io(port->board->base + port->ch_base, sizeof(*port));
 #endif
 
-	if (port->gs.count <= 1) {
+	if (port->gs.port.count <= 1) {
 		if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
 			printk(KERN_ERR "sx: Card didn't respond to LOPEN "
 					"command.\n");
 			spin_lock_irqsave(&port->gs.driver_lock, flags);
-			port->gs.count--;
+			port->gs.port.count--;
 			spin_unlock_irqrestore(&port->gs.driver_lock, flags);
 			return -EIO;
 		}
@@ -1526,11 +1525,11 @@
 
 	retval = gs_block_til_ready(port, filp);
 	sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
-			retval, port->gs.count);
+			retval, port->gs.port.count);
 
 	if (retval) {
 /*
- * Don't lower gs.count here because sx_close() will be called later
+ * Don't lower gs.port.count here because sx_close() will be called later
  */
 
 		return retval;
@@ -1571,14 +1570,14 @@
 	}
 
 	sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
-			5 * HZ - to - 1, port->gs.count);
+			5 * HZ - to - 1, port->gs.port.count);
 
-	if (port->gs.count) {
+	if (port->gs.port.count) {
 		sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
-				port->gs.count);
+				port->gs.port.count);
 		/*printk("%s SETTING port count to zero: %p count: %d\n",
-				__func__, port, port->gs.count);
-		port->gs.count = 0;*/
+				__func__, port, port->gs.port.count);
+		port->gs.port.count = 0;*/
 	}
 
 	func_exit();
@@ -1939,7 +1938,7 @@
 	 * control then throttle the port.
 	 */
 	if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
-		port->gs.flags |= SX_RX_THROTTLE;
+		port->gs.port.flags |= SX_RX_THROTTLE;
 	}
 	func_exit();
 }
@@ -1953,7 +1952,7 @@
 	 * this port in case we disabled flow control while the port
 	 * was throttled
 	 */
-	port->gs.flags &= ~SX_RX_THROTTLE;
+	port->gs.port.flags &= ~SX_RX_THROTTLE;
 	func_exit();
 	return;
 }
@@ -2396,6 +2395,7 @@
 		board->ports = port;
 		for (j = 0; j < boards[i].nports; j++) {
 			sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
+			tty_port_init(&port->gs.port);
 			port->gs.magic = SX_MAGIC;
 			port->gs.close_delay = HZ / 2;
 			port->gs.closing_wait = 30 * HZ;
@@ -2408,9 +2408,6 @@
 			/*
 			 * Initializing wait queue
 			 */
-			init_waitqueue_head(&port->gs.open_wait);
-			init_waitqueue_head(&port->gs.close_wait);
-
 			port++;
 		}
 	}
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 9d247d8..527d220 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -180,19 +180,14 @@
  
 struct mgsl_struct {
 	int			magic;
-	int			flags;
-	int			count;		/* count of opens */
+	struct tty_port		port;
 	int			line;
 	int                     hw_version;
-	unsigned short		close_delay;
-	unsigned short		closing_wait;	/* time to wait before closing */
 	
 	struct mgsl_icount	icount;
 	
-	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
-	int			blocked_open;	/* # of blocked opens */
 	u16			read_status_mask;
 	u16			ignore_status_mask;	
 	unsigned char 		*xmit_buf;
@@ -200,9 +195,6 @@
 	int			xmit_tail;
 	int			xmit_cnt;
 	
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-	
 	wait_queue_head_t	status_event_wait_q;
 	wait_queue_head_t	event_wait_q;
 	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
@@ -975,8 +967,8 @@
 		return;
 	ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if (ld->receive_buf)
-			ld->receive_buf(tty, data, flags, count);
+		if (ld->ops->receive_buf)
+			ld->ops->receive_buf(tty, data, flags, count);
 		tty_ldisc_deref(ld);
 	}
 }
@@ -1134,7 +1126,7 @@
 
 static void mgsl_bh_transmit(struct mgsl_struct *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	unsigned long flags;
 	
 	if ( debug_level >= DEBUG_LEVEL_BH )
@@ -1276,7 +1268,7 @@
 	else 
 #endif
 	{
-		if (info->tty->stopped || info->tty->hw_stopped) {
+		if (info->port.tty->stopped || info->port.tty->hw_stopped) {
 			usc_stop_transmitter(info);
 			return;
 		}
@@ -1357,29 +1349,29 @@
 		wake_up_interruptible(&info->status_event_wait_q);
 		wake_up_interruptible(&info->event_wait_q);
 
-		if ( (info->flags & ASYNC_CHECK_CD) && 
+		if ( (info->port.flags & ASYNC_CHECK_CD) && 
 		     (status & MISCSTATUS_DCD_LATCHED) ) {
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 				printk("%s CD now %s...", info->device_name,
 				       (status & MISCSTATUS_DCD) ? "on" : "off");
 			if (status & MISCSTATUS_DCD)
-				wake_up_interruptible(&info->open_wait);
+				wake_up_interruptible(&info->port.open_wait);
 			else {
 				if ( debug_level >= DEBUG_LEVEL_ISR )
 					printk("doing serial hangup...");
-				if (info->tty)
-					tty_hangup(info->tty);
+				if (info->port.tty)
+					tty_hangup(info->port.tty);
 			}
 		}
 	
-		if ( (info->flags & ASYNC_CTS_FLOW) && 
+		if ( (info->port.flags & ASYNC_CTS_FLOW) && 
 		     (status & MISCSTATUS_CTS_LATCHED) ) {
-			if (info->tty->hw_stopped) {
+			if (info->port.tty->hw_stopped) {
 				if (status & MISCSTATUS_CTS) {
 					if ( debug_level >= DEBUG_LEVEL_ISR )
 						printk("CTS tx start...");
-					if (info->tty)
-						info->tty->hw_stopped = 0;
+					if (info->port.tty)
+						info->port.tty->hw_stopped = 0;
 					usc_start_transmitter(info);
 					info->pending_bh |= BH_TRANSMIT;
 					return;
@@ -1388,8 +1380,8 @@
 				if (!(status & MISCSTATUS_CTS)) {
 					if ( debug_level >= DEBUG_LEVEL_ISR )
 						printk("CTS tx stop...");
-					if (info->tty)
-						info->tty->hw_stopped = 1;
+					if (info->port.tty)
+						info->port.tty->hw_stopped = 1;
 					usc_stop_transmitter(info);
 				}
 			}
@@ -1423,7 +1415,7 @@
 			
 	usc_ClearIrqPendingBits( info, TRANSMIT_DATA );
 	
-	if (info->tty->stopped || info->tty->hw_stopped) {
+	if (info->port.tty->stopped || info->port.tty->hw_stopped) {
 		usc_stop_transmitter(info);
 		return;
 	}
@@ -1453,7 +1445,7 @@
 	u16 status;
 	int work = 0;
 	unsigned char DataByte;
- 	struct tty_struct *tty = info->tty;
+ 	struct tty_struct *tty = info->port.tty;
  	struct	mgsl_icount *icount = &info->icount;
 	
 	if ( debug_level >= DEBUG_LEVEL_ISR )	
@@ -1514,7 +1506,7 @@
 		
 			if (status & RXSTATUS_BREAK_RECEIVED) {
 				flag = TTY_BREAK;
-				if (info->flags & ASYNC_SAK)
+				if (info->port.flags & ASYNC_SAK)
 					do_SAK(tty);
 			} else if (status & RXSTATUS_PARITY_ERROR)
 				flag = TTY_PARITY;
@@ -1771,7 +1763,7 @@
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 		printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name);
 		
-	if (info->flags & ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		return 0;
 	
 	if (!info->xmit_buf) {
@@ -1798,8 +1790,8 @@
 		retval = mgsl_adapter_test(info);
 		
 	if ( retval ) {
-  		if (capable(CAP_SYS_ADMIN) && info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
+  		if (capable(CAP_SYS_ADMIN) && info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		mgsl_release_resources(info);
   		return retval;
   	}
@@ -1807,10 +1799,10 @@
 	/* program hardware for current parameters */
 	mgsl_change_params(info);
 	
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags |= ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 	
 	return 0;
 	
@@ -1827,7 +1819,7 @@
 {
 	unsigned long flags;
 	
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1864,7 +1856,7 @@
 	/* on the ISA adapter. This has no effect for the PCI adapter */
 	usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12));
 	
- 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 	if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
  		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
 		usc_set_serial_signals(info);
 	}
@@ -1873,10 +1865,10 @@
 
 	mgsl_release_resources(info);	
 	
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 	
 }	/* end of shutdown() */
 
@@ -1908,7 +1900,7 @@
 	usc_EnableInterrupts(info, IO_PIN);
 	usc_get_serial_signals(info);
 		
-	if (info->netcount || info->tty->termios->c_cflag & CREAD)
+	if (info->netcount || info->port.tty->termios->c_cflag & CREAD)
 		usc_start_receiver(info);
 		
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -1921,14 +1913,14 @@
 	unsigned cflag;
 	int bits_per_char;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
 		
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_change_params(%s)\n",
 			 __FILE__,__LINE__, info->device_name );
 			 
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 
 	/* if B0 rate (hangup) specified then negate DTR and RTS */
 	/* otherwise assert DTR and RTS */
@@ -1976,7 +1968,7 @@
 	 * current data rate.
 	 */
 	if (info->params.data_rate <= 460800)
-		info->params.data_rate = tty_get_baud_rate(info->tty);
+		info->params.data_rate = tty_get_baud_rate(info->port.tty);
 	
 	if ( info->params.data_rate ) {
 		info->timeout = (32*HZ*bits_per_char) / 
@@ -1985,31 +1977,31 @@
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
 
 	if (cflag & CRTSCTS)
-		info->flags |= ASYNC_CTS_FLOW;
+		info->port.flags |= ASYNC_CTS_FLOW;
 	else
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 		
 	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
+		info->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		info->flags |= ASYNC_CHECK_CD;
+		info->port.flags |= ASYNC_CHECK_CD;
 
 	/* process tty input control flags */
 	
 	info->read_status_mask = RXSTATUS_OVERRUN;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR;
- 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ 	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
  		info->read_status_mask |= RXSTATUS_BREAK_RECEIVED;
 	
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED;
 		/* If ignoring parity and break indicators, ignore 
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			info->ignore_status_mask |= RXSTATUS_OVERRUN;
 	}
 
@@ -3113,32 +3105,32 @@
 	
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
-			 __FILE__,__LINE__, info->device_name, info->count);
+			 __FILE__,__LINE__, info->device_name, info->port.count);
 			 
-	if (!info->count)
+	if (!info->port.count)
 		return;
 
 	if (tty_hung_up_p(filp))
 		goto cleanup;
 			
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * tty->count is 1 and the tty structure will be freed.
-		 * info->count should be one in this case.
+		 * info->port.count should be one in this case.
 		 * if it's not, correct it so that the port is shutdown.
 		 */
 		printk("mgsl_close: bad refcount; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
+		       "info->port.count is %d\n", info->port.count);
+		info->port.count = 1;
 	}
 	
-	info->count--;
+	info->port.count--;
 	
 	/* if at least one open remaining, leave hardware active */
-	if (info->count)
+	if (info->port.count)
 		goto cleanup;
 	
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 	
 	/* set tty->closing to notify line discipline to 
 	 * only process XON/XOFF characters. Only the N_TTY
@@ -3148,14 +3140,14 @@
 	
 	/* wait for transmit data to clear all layers */
 	
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+	if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
 		if (debug_level >= DEBUG_LEVEL_INFO)
 			printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n",
 				 __FILE__,__LINE__, info->device_name );
-		tty_wait_until_sent(tty, info->closing_wait);
+		tty_wait_until_sent(tty, info->port.closing_wait);
 	}
 		
- 	if (info->flags & ASYNC_INITIALIZED)
+ 	if (info->port.flags & ASYNC_INITIALIZED)
  		mgsl_wait_until_sent(tty, info->timeout);
 
 	mgsl_flush_buffer(tty);
@@ -3165,23 +3157,23 @@
 	shutdown(info);
 	
 	tty->closing = 0;
-	info->tty = NULL;
+	info->port.tty = NULL;
 	
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
+	if (info->port.blocked_open) {
+		if (info->port.close_delay) {
+			msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
 	
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 			 
-	wake_up_interruptible(&info->close_wait);
+	wake_up_interruptible(&info->port.close_wait);
 	
 cleanup:			
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__,
-			tty->driver->name, info->count);
+			tty->driver->name, info->port.count);
 			
 }	/* end of mgsl_close() */
 
@@ -3211,7 +3203,7 @@
 	if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent"))
 		return;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		goto exit;
 	 
 	orig_jiffies = jiffies;
@@ -3283,11 +3275,11 @@
 	mgsl_flush_buffer(tty);
 	shutdown(info);
 	
-	info->count = 0;	
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
+	info->port.count = 0;	
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->port.tty = NULL;
 
-	wake_up_interruptible(&info->open_wait);
+	wake_up_interruptible(&info->port.open_wait);
 	
 }	/* end of mgsl_hangup() */
 
@@ -3319,7 +3311,7 @@
 
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -3328,25 +3320,25 @@
 
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
+	 * this loop, info->port.count is dropped by one, so that
 	 * mgsl_close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 	 
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 	
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):block_til_ready before block on %s count=%d\n",
-			 __FILE__,__LINE__, tty->driver->name, info->count );
+			 __FILE__,__LINE__, tty->driver->name, info->port.count );
 
 	spin_lock_irqsave(&info->irq_spinlock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = true;
-		info->count--;
+		info->port.count--;
 	}
 	spin_unlock_irqrestore(&info->irq_spinlock, flags);
-	info->blocked_open++;
+	info->port.blocked_open++;
 	
 	while (1) {
 		if (tty->termios->c_cflag & CBAUD) {
@@ -3358,8 +3350,8 @@
 		
 		set_current_state(TASK_INTERRUPTIBLE);
 		
-		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
-			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+		if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
+			retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 			break;
 		}
@@ -3368,7 +3360,7 @@
 	 	usc_get_serial_signals(info);
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 		
- 		if (!(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->port.flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -3380,24 +3372,24 @@
 		
 		if (debug_level >= DEBUG_LEVEL_INFO)
 			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
-				 __FILE__,__LINE__, tty->driver->name, info->count );
+				 __FILE__,__LINE__, tty->driver->name, info->port.count );
 				 
 		schedule();
 	}
 	
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 	
 	if (extra_count)
-		info->count++;
-	info->blocked_open--;
+		info->port.count++;
+	info->port.blocked_open--;
 	
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
-			 __FILE__,__LINE__, tty->driver->name, info->count );
+			 __FILE__,__LINE__, tty->driver->name, info->port.count );
 			 
 	if (!retval)
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		
 	return retval;
 	
@@ -3435,22 +3427,22 @@
 		return -ENODEV;
 	
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 		
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_open(%s), old ref count = %d\n",
-			 __FILE__,__LINE__,tty->driver->name, info->count);
+			 __FILE__,__LINE__,tty->driver->name, info->port.count);
 
 	/* If port is closing, signal caller to try again */
-	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+		if (info->port.flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->port.close_wait);
+		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
 		goto cleanup;
 	}
 	
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	spin_lock_irqsave(&info->netlock, flags);
 	if (info->netcount) {
@@ -3458,10 +3450,10 @@
 		spin_unlock_irqrestore(&info->netlock, flags);
 		goto cleanup;
 	}
-	info->count++;
+	info->port.count++;
 	spin_unlock_irqrestore(&info->netlock, flags);
 
-	if (info->count == 1) {
+	if (info->port.count == 1) {
 		/* 1st open on this device, init hardware */
 		retval = startup(info);
 		if (retval < 0)
@@ -3484,9 +3476,9 @@
 cleanup:			
 	if (retval) {
 		if (tty->count == 1)
-			info->tty = NULL; /* tty layer will release tty struct */
-		if(info->count)
-			info->count--;
+			info->port.tty = NULL; /* tty layer will release tty struct */
+		if(info->port.count)
+			info->port.count--;
 	}
 	
 	return retval;
@@ -4332,13 +4324,12 @@
 	if (!info) {
 		printk("Error can't allocate device instance data\n");
 	} else {
+		tty_port_init(&info->port);
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, mgsl_bh_handler);
 		info->max_frame_size = 4096;
-		info->close_delay = 5*HZ/10;
-		info->closing_wait = 30*HZ;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
+		info->port.close_delay = 5*HZ/10;
+		info->port.closing_wait = 30*HZ;
 		init_waitqueue_head(&info->status_event_wait_q);
 		init_waitqueue_head(&info->event_wait_q);
 		spin_lock_init(&info->irq_spinlock);
@@ -6575,7 +6566,7 @@
 	unsigned int framesize = 0;
 	bool ReturnCode = false;
 	unsigned long flags;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	bool return_frame = false;
 	
 	/*
@@ -6773,7 +6764,7 @@
 	unsigned int framesize = 0;
 	bool ReturnCode = false;
 	unsigned long flags;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	/*
  	 * current_rx_buffer points to the 1st buffer of the next available
@@ -7710,7 +7701,7 @@
 	unsigned short new_crctype;
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	switch (encoding)
@@ -7806,7 +7797,7 @@
 
 	/* arbitrate between network and tty opens */
 	spin_lock_irqsave(&info->netlock, flags);
-	if (info->count != 0 || info->netcount != 0) {
+	if (info->port.count != 0 || info->netcount != 0) {
 		printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
 		spin_unlock_irqrestore(&info->netlock, flags);
 		return -EBUSY;
@@ -7892,7 +7883,7 @@
 		printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	if (cmd != SIOCWANDEV)
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index d88a607..2c3e43b 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -244,11 +244,11 @@
  */
 struct slgt_info {
 	void *if_ptr;		/* General purpose pointer (used by SPPP) */
+	struct tty_port port;
 
 	struct slgt_info *next_device;	/* device list link */
 
 	int magic;
-	int flags;
 
 	char device_name[25];
 	struct pci_dev *pdev;
@@ -260,23 +260,15 @@
 	/* array of pointers to port contexts on this adapter */
 	struct slgt_info *port_array[SLGT_MAX_PORTS];
 
-	int			count;		/* count of opens */
 	int			line;		/* tty line instance number */
-	unsigned short		close_delay;
-	unsigned short		closing_wait;	/* time to wait before closing */
 
 	struct mgsl_icount	icount;
 
-	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
-	int			blocked_open;	/* # of blocked opens */
 	unsigned int		read_status_mask;
 	unsigned int 		ignore_status_mask;
 
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-
 	wait_queue_head_t	status_event_wait_q;
 	wait_queue_head_t	event_wait_q;
 	struct timer_list	tx_timer;
@@ -641,8 +633,8 @@
 		return;
 	ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if (ld->receive_buf)
-			ld->receive_buf(tty, data, flags, count);
+		if (ld->ops->receive_buf)
+			ld->ops->receive_buf(tty, data, flags, count);
 		tty_ldisc_deref(ld);
 	}
 }
@@ -672,20 +664,20 @@
 	}
 
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
-	DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count));
+	DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count));
 
 	/* If port is closing, signal caller to try again */
-	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+		if (info->port.flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->port.close_wait);
+		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
 		goto cleanup;
 	}
 
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	spin_lock_irqsave(&info->netlock, flags);
 	if (info->netcount) {
@@ -693,10 +685,10 @@
 		spin_unlock_irqrestore(&info->netlock, flags);
 		goto cleanup;
 	}
-	info->count++;
+	info->port.count++;
 	spin_unlock_irqrestore(&info->netlock, flags);
 
-	if (info->count == 1) {
+	if (info->port.count == 1) {
 		/* 1st open on this device, init hardware */
 		retval = startup(info);
 		if (retval < 0)
@@ -714,9 +706,9 @@
 cleanup:
 	if (retval) {
 		if (tty->count == 1)
-			info->tty = NULL; /* tty layer will release tty struct */
-		if(info->count)
-			info->count--;
+			info->port.tty = NULL; /* tty layer will release tty struct */
+		if(info->port.count)
+			info->port.count--;
 	}
 
 	DBGINFO(("%s open rc=%d\n", info->device_name, retval));
@@ -729,32 +721,32 @@
 
 	if (sanity_check(info, tty->name, "close"))
 		return;
-	DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count));
+	DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count));
 
-	if (!info->count)
+	if (!info->port.count)
 		return;
 
 	if (tty_hung_up_p(filp))
 		goto cleanup;
 
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * tty->count is 1 and the tty structure will be freed.
-		 * info->count should be one in this case.
+		 * info->port.count should be one in this case.
 		 * if it's not, correct it so that the port is shutdown.
 		 */
 		DBGERR(("%s close: bad refcount; tty->count=1, "
-		       "info->count=%d\n", info->device_name, info->count));
-		info->count = 1;
+		       "info->port.count=%d\n", info->device_name, info->port.count));
+		info->port.count = 1;
 	}
 
-	info->count--;
+	info->port.count--;
 
 	/* if at least one open remaining, leave hardware active */
-	if (info->count)
+	if (info->port.count)
 		goto cleanup;
 
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 
 	/* set tty->closing to notify line discipline to
 	 * only process XON/XOFF characters. Only the N_TTY
@@ -764,12 +756,12 @@
 
 	/* wait for transmit data to clear all layers */
 
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+	if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
 		DBGINFO(("%s call tty_wait_until_sent\n", info->device_name));
-		tty_wait_until_sent(tty, info->closing_wait);
+		tty_wait_until_sent(tty, info->port.closing_wait);
 	}
 
- 	if (info->flags & ASYNC_INITIALIZED)
+ 	if (info->port.flags & ASYNC_INITIALIZED)
  		wait_until_sent(tty, info->timeout);
 	flush_buffer(tty);
 	tty_ldisc_flush(tty);
@@ -777,21 +769,21 @@
 	shutdown(info);
 
 	tty->closing = 0;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
+	if (info->port.blocked_open) {
+		if (info->port.close_delay) {
+			msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
 
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 
-	wake_up_interruptible(&info->close_wait);
+	wake_up_interruptible(&info->port.close_wait);
 
 cleanup:
-	DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count));
+	DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count));
 }
 
 static void hangup(struct tty_struct *tty)
@@ -805,11 +797,11 @@
 	flush_buffer(tty);
 	shutdown(info);
 
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
+	info->port.count = 0;
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->port.tty = NULL;
 
-	wake_up_interruptible(&info->open_wait);
+	wake_up_interruptible(&info->port.open_wait);
 }
 
 static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
@@ -959,7 +951,7 @@
 	if (sanity_check(info, tty->name, "wait_until_sent"))
 		return;
 	DBGINFO(("%s wait_until_sent entry\n", info->device_name));
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		goto exit;
 
 	orig_jiffies = jiffies;
@@ -1500,7 +1492,7 @@
 	unsigned short new_crctype;
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	DBGINFO(("%s hdlcdev_attach\n", info->device_name));
@@ -1599,7 +1591,7 @@
 
 	/* arbitrate between network and tty opens */
 	spin_lock_irqsave(&info->netlock, flags);
-	if (info->count != 0 || info->netcount != 0) {
+	if (info->port.count != 0 || info->netcount != 0) {
 		DBGINFO(("%s hdlc_open busy\n", dev->name));
 		spin_unlock_irqrestore(&info->netlock, flags);
 		return -EBUSY;
@@ -1684,7 +1676,7 @@
 	DBGINFO(("%s hdlcdev_ioctl\n", dev->name));
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	if (cmd != SIOCWANDEV)
@@ -1903,7 +1895,7 @@
  */
 static void rx_async(struct slgt_info *info)
 {
- 	struct tty_struct *tty = info->tty;
+ 	struct tty_struct *tty = info->port.tty;
  	struct mgsl_icount *icount = &info->icount;
 	unsigned int start, end;
 	unsigned char *p;
@@ -2054,7 +2046,7 @@
 
 static void bh_transmit(struct slgt_info *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	DBGBH(("%s bh_transmit\n", info->device_name));
 	if (tty)
@@ -2100,17 +2092,17 @@
 	wake_up_interruptible(&info->event_wait_q);
 	info->pending_bh |= BH_STATUS;
 
-	if (info->flags & ASYNC_CTS_FLOW) {
-		if (info->tty) {
-			if (info->tty->hw_stopped) {
+	if (info->port.flags & ASYNC_CTS_FLOW) {
+		if (info->port.tty) {
+			if (info->port.tty->hw_stopped) {
 				if (info->signals & SerialSignal_CTS) {
-		 			info->tty->hw_stopped = 0;
+		 			info->port.tty->hw_stopped = 0;
 					info->pending_bh |= BH_TRANSMIT;
 					return;
 				}
 			} else {
 				if (!(info->signals & SerialSignal_CTS))
-		 			info->tty->hw_stopped = 1;
+		 			info->port.tty->hw_stopped = 1;
 			}
 		}
 	}
@@ -2143,12 +2135,12 @@
 	wake_up_interruptible(&info->event_wait_q);
 	info->pending_bh |= BH_STATUS;
 
-	if (info->flags & ASYNC_CHECK_CD) {
+	if (info->port.flags & ASYNC_CHECK_CD) {
 		if (info->signals & SerialSignal_DCD)
-			wake_up_interruptible(&info->open_wait);
+			wake_up_interruptible(&info->port.open_wait);
 		else {
-			if (info->tty)
-				tty_hangup(info->tty);
+			if (info->port.tty)
+				tty_hangup(info->port.tty);
 		}
 	}
 }
@@ -2191,12 +2183,12 @@
 		if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
 			info->icount.brk++;
 			/* process break detection if tty control allows */
-			if (info->tty) {
+			if (info->port.tty) {
 				if (!(status & info->ignore_status_mask)) {
 					if (info->read_status_mask & MASK_BREAK) {
-						tty_insert_flip_char(info->tty, 0, TTY_BREAK);
-						if (info->flags & ASYNC_SAK)
-							do_SAK(info->tty);
+						tty_insert_flip_char(info->port.tty, 0, TTY_BREAK);
+						if (info->port.flags & ASYNC_SAK)
+							do_SAK(info->port.tty);
 					}
 				}
 			}
@@ -2316,7 +2308,7 @@
 		else
 #endif
 		{
-			if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+			if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
 				tx_stop(info);
 				return;
 			}
@@ -2392,7 +2384,7 @@
 	for(i=0; i < info->port_count ; i++) {
 		struct slgt_info *port = info->port_array[i];
 
-		if (port && (port->count || port->netcount) &&
+		if (port && (port->port.count || port->netcount) &&
 		    port->pending_bh && !port->bh_running &&
 		    !port->bh_requested) {
 			DBGISR(("%s bh queued\n", port->device_name));
@@ -2411,7 +2403,7 @@
 {
 	DBGINFO(("%s startup\n", info->device_name));
 
-	if (info->flags & ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		return 0;
 
 	if (!info->tx_buf) {
@@ -2429,10 +2421,10 @@
 	/* program hardware for current parameters */
 	change_params(info);
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags |= ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 
 	return 0;
 }
@@ -2444,7 +2436,7 @@
 {
 	unsigned long flags;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	DBGINFO(("%s shutdown\n", info->device_name));
@@ -2467,7 +2459,7 @@
 
 	slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
 
- 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 	if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
  		info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
 		set_signals(info);
 	}
@@ -2476,10 +2468,10 @@
 
 	spin_unlock_irqrestore(&info->lock,flags);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 }
 
 static void program_hw(struct slgt_info *info)
@@ -2508,7 +2500,7 @@
 	get_signals(info);
 
 	if (info->netcount ||
-	    (info->tty && info->tty->termios->c_cflag & CREAD))
+	    (info->port.tty && info->port.tty->termios->c_cflag & CREAD))
 		rx_start(info);
 
 	spin_unlock_irqrestore(&info->lock,flags);
@@ -2522,11 +2514,11 @@
 	unsigned cflag;
 	int bits_per_char;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
 	DBGINFO(("%s change_params\n", info->device_name));
 
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 
 	/* if B0 rate (hangup) specified then negate DTR and RTS */
 	/* otherwise assert DTR and RTS */
@@ -2558,7 +2550,7 @@
 	bits_per_char = info->params.data_bits +
 			info->params.stop_bits + 1;
 
-	info->params.data_rate = tty_get_baud_rate(info->tty);
+	info->params.data_rate = tty_get_baud_rate(info->port.tty);
 
 	if (info->params.data_rate) {
 		info->timeout = (32*HZ*bits_per_char) /
@@ -2567,30 +2559,30 @@
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
 
 	if (cflag & CRTSCTS)
-		info->flags |= ASYNC_CTS_FLOW;
+		info->port.flags |= ASYNC_CTS_FLOW;
 	else
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 
 	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
+		info->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		info->flags |= ASYNC_CHECK_CD;
+		info->port.flags |= ASYNC_CHECK_CD;
 
 	/* process tty input control flags */
 
 	info->read_status_mask = IRQ_RXOVER;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= MASK_PARITY | MASK_FRAMING;
- 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ 	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
  		info->read_status_mask |= MASK_BREAK;
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= MASK_BREAK;
 		/* If ignoring parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			info->ignore_status_mask |= MASK_OVERRUN;
 	}
 
@@ -3141,7 +3133,7 @@
 
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -3150,21 +3142,21 @@
 
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
+	 * this loop, info->port.count is dropped by one, so that
 	 * close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 
 	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = true;
-		info->count--;
+		info->port.count--;
 	}
 	spin_unlock_irqrestore(&info->lock, flags);
-	info->blocked_open++;
+	info->port.blocked_open++;
 
 	while (1) {
 		if ((tty->termios->c_cflag & CBAUD)) {
@@ -3176,8 +3168,8 @@
 
 		set_current_state(TASK_INTERRUPTIBLE);
 
-		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
-			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+		if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
+			retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 			break;
 		}
@@ -3186,7 +3178,7 @@
 	 	get_signals(info);
 		spin_unlock_irqrestore(&info->lock,flags);
 
- 		if (!(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->port.flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -3201,14 +3193,14 @@
 	}
 
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 
 	if (extra_count)
-		info->count++;
-	info->blocked_open--;
+		info->port.count++;
+	info->port.blocked_open--;
 
 	if (!retval)
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 
 	DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
 	return retval;
@@ -3451,14 +3443,13 @@
 		DBGERR(("%s device alloc failed adapter=%d port=%d\n",
 			driver_name, adapter_num, port_num));
 	} else {
+		tty_port_init(&info->port);
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, bh_handler);
 		info->max_frame_size = 4096;
 		info->raw_rx_size = DMABUFSIZE;
-		info->close_delay = 5*HZ/10;
-		info->closing_wait = 30*HZ;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
+		info->port.close_delay = 5*HZ/10;
+		info->port.closing_wait = 30*HZ;
 		init_waitqueue_head(&info->status_event_wait_q);
 		init_waitqueue_head(&info->event_wait_q);
 		spin_lock_init(&info->netlock);
@@ -4502,7 +4493,7 @@
 	unsigned short status;
 	unsigned int framesize = 0;
 	unsigned long flags;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	unsigned char addr_field = 0xff;
 	unsigned int crc_size = 0;
 
@@ -4652,7 +4643,7 @@
 	DBGDATA(info, info->rbufs[i].buf, count, "rx");
 	DBGINFO(("rx_get_buf size=%d\n", count));
 	if (count)
-		ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+		ldisc_receive_buf(info->port.tty, info->rbufs[i].buf,
 				  info->flag_buf, count);
 	free_rbufs(info, i, i);
 	return true;
@@ -4761,11 +4752,11 @@
 {
 	unsigned long timeout;
 	unsigned long flags;
-	struct tty_struct *oldtty = info->tty;
+	struct tty_struct *oldtty = info->port.tty;
 	u32 speed = info->params.data_rate;
 
 	info->params.data_rate = 921600;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
 	spin_lock_irqsave(&info->lock, flags);
 	async_mode(info);
@@ -4793,7 +4784,7 @@
 	spin_unlock_irqrestore(&info->lock,flags);
 
 	info->params.data_rate = speed;
-	info->tty = oldtty;
+	info->port.tty = oldtty;
 
 	info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure;
 	return info->irq_occurred ? 0 : -ENODEV;
@@ -4833,7 +4824,7 @@
 	int rc = -ENODEV;
 	unsigned long flags;
 
-	struct tty_struct *oldtty = info->tty;
+	struct tty_struct *oldtty = info->port.tty;
 	MGSL_PARAMS params;
 
 	memcpy(&params, &info->params, sizeof(params));
@@ -4841,7 +4832,7 @@
 	info->params.mode = MGSL_MODE_ASYNC;
 	info->params.data_rate = 921600;
 	info->params.loopback = 1;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
 	/* build and send transmit frame */
 	for (count = 0; count < TESTFRAMESIZE; ++count)
@@ -4879,7 +4870,7 @@
 	spin_unlock_irqrestore(&info->lock,flags);
 
 	memcpy(&info->params, &params, sizeof(info->params));
-	info->tty = oldtty;
+	info->port.tty = oldtty;
 
 	info->init_error = rc ? DiagStatus_DmaFailure : 0;
 	return rc;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 10241ed..5768c41 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -151,18 +151,15 @@
 typedef struct _synclinkmp_info {
 	void *if_ptr;				/* General purpose pointer (used by SPPP) */
 	int			magic;
-	int			flags;
-	int			count;		/* count of opens */
+	struct tty_port		port;
 	int			line;
 	unsigned short		close_delay;
 	unsigned short		closing_wait;	/* time to wait before closing */
 
 	struct mgsl_icount	icount;
 
-	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
-	int			blocked_open;	/* # of blocked opens */
 	u16			read_status_mask1;  /* break detection (SR1 indications) */
 	u16			read_status_mask2;  /* parity/framing/overun (SR2 indications) */
 	unsigned char 		ignore_status_mask1;  /* break detection (SR1 indications) */
@@ -172,9 +169,6 @@
 	int			tx_get;
 	int			tx_count;
 
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-
 	wait_queue_head_t	status_event_wait_q;
 	wait_queue_head_t	event_wait_q;
 	struct timer_list	tx_timer;	/* HDLC transmit timeout timer */
@@ -462,13 +456,13 @@
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-static int break_on_load=0;
+static int break_on_load = 0;
 
 /*
  * Driver major number, defaults to zero to get auto
  * assigned major number. May be forced as module parameter.
  */
-static int ttymajor=0;
+static int ttymajor = 0;
 
 /*
  * Array of user specified options for ISA adapters.
@@ -712,8 +706,8 @@
 		return;
 	ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if (ld->receive_buf)
-			ld->receive_buf(tty, data, flags, count);
+		if (ld->ops->receive_buf)
+			ld->ops->receive_buf(tty, data, flags, count);
 		tty_ldisc_deref(ld);
 	}
 }
@@ -747,22 +741,22 @@
 	}
 
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s open(), old ref count = %d\n",
-			 __FILE__,__LINE__,tty->driver->name, info->count);
+			 __FILE__,__LINE__,tty->driver->name, info->port.count);
 
 	/* If port is closing, signal caller to try again */
-	if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-		retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
+		if (info->port.flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->port.close_wait);
+		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
 		goto cleanup;
 	}
 
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	spin_lock_irqsave(&info->netlock, flags);
 	if (info->netcount) {
@@ -770,10 +764,10 @@
 		spin_unlock_irqrestore(&info->netlock, flags);
 		goto cleanup;
 	}
-	info->count++;
+	info->port.count++;
 	spin_unlock_irqrestore(&info->netlock, flags);
 
-	if (info->count == 1) {
+	if (info->port.count == 1) {
 		/* 1st open on this device, init hardware */
 		retval = startup(info);
 		if (retval < 0)
@@ -796,9 +790,9 @@
 cleanup:
 	if (retval) {
 		if (tty->count == 1)
-			info->tty = NULL; /* tty layer will release tty struct */
-		if(info->count)
-			info->count--;
+			info->port.tty = NULL; /* tty layer will release tty struct */
+		if(info->port.count)
+			info->port.count--;
 	}
 
 	return retval;
@@ -816,33 +810,33 @@
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s close() entry, count=%d\n",
-			 __FILE__,__LINE__, info->device_name, info->count);
+			 __FILE__,__LINE__, info->device_name, info->port.count);
 
-	if (!info->count)
+	if (!info->port.count)
 		return;
 
 	if (tty_hung_up_p(filp))
 		goto cleanup;
 
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (info->port.count != 1)) {
 		/*
 		 * tty->count is 1 and the tty structure will be freed.
-		 * info->count should be one in this case.
+		 * info->port.count should be one in this case.
 		 * if it's not, correct it so that the port is shutdown.
 		 */
 		printk("%s(%d):%s close: bad refcount; tty->count is 1, "
-		       "info->count is %d\n",
-			 __FILE__,__LINE__, info->device_name, info->count);
-		info->count = 1;
+		       "info->port.count is %d\n",
+			 __FILE__,__LINE__, info->device_name, info->port.count);
+		info->port.count = 1;
 	}
 
-	info->count--;
+	info->port.count--;
 
 	/* if at least one open remaining, leave hardware active */
-	if (info->count)
+	if (info->port.count)
 		goto cleanup;
 
-	info->flags |= ASYNC_CLOSING;
+	info->port.flags |= ASYNC_CLOSING;
 
 	/* set tty->closing to notify line discipline to
 	 * only process XON/XOFF characters. Only the N_TTY
@@ -852,14 +846,14 @@
 
 	/* wait for transmit data to clear all layers */
 
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+	if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
 		if (debug_level >= DEBUG_LEVEL_INFO)
 			printk("%s(%d):%s close() calling tty_wait_until_sent\n",
 				 __FILE__,__LINE__, info->device_name );
-		tty_wait_until_sent(tty, info->closing_wait);
+		tty_wait_until_sent(tty, info->port.closing_wait);
 	}
 
- 	if (info->flags & ASYNC_INITIALIZED)
+ 	if (info->port.flags & ASYNC_INITIALIZED)
  		wait_until_sent(tty, info->timeout);
 
 	flush_buffer(tty);
@@ -869,23 +863,23 @@
 	shutdown(info);
 
 	tty->closing = 0;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
+	if (info->port.blocked_open) {
+		if (info->port.close_delay) {
+			msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
 		}
-		wake_up_interruptible(&info->open_wait);
+		wake_up_interruptible(&info->port.open_wait);
 	}
 
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 
-	wake_up_interruptible(&info->close_wait);
+	wake_up_interruptible(&info->port.close_wait);
 
 cleanup:
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__,
-			tty->driver->name, info->count);
+			tty->driver->name, info->port.count);
 }
 
 /* Called by tty_hangup() when a hangup is signaled.
@@ -905,11 +899,11 @@
 	flush_buffer(tty);
 	shutdown(info);
 
-	info->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
+	info->port.count = 0;
+	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	info->port.tty = NULL;
 
-	wake_up_interruptible(&info->open_wait);
+	wake_up_interruptible(&info->port.open_wait);
 }
 
 /* Set new termios settings
@@ -1123,7 +1117,7 @@
 
 	lock_kernel();
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		goto exit;
 
 	orig_jiffies = jiffies;
@@ -1636,7 +1630,7 @@
 	unsigned short new_crctype;
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	switch (encoding)
@@ -1732,7 +1726,7 @@
 
 	/* arbitrate between network and tty opens */
 	spin_lock_irqsave(&info->netlock, flags);
-	if (info->count != 0 || info->netcount != 0) {
+	if (info->port.count != 0 || info->netcount != 0) {
 		printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
 		spin_unlock_irqrestore(&info->netlock, flags);
 		return -EBUSY;
@@ -1818,7 +1812,7 @@
 		printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
 
 	/* return error if TTY interface open */
-	if (info->count)
+	if (info->port.count)
 		return -EBUSY;
 
 	if (cmd != SIOCWANDEV)
@@ -2126,7 +2120,7 @@
 
 static void bh_transmit(SLMP_INFO *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	if ( debug_level >= DEBUG_LEVEL_BH )
 		printk( "%s(%d):%s bh_transmit() entry\n",
@@ -2176,7 +2170,7 @@
 
 static void isr_rxint(SLMP_INFO * info)
 {
- 	struct tty_struct *tty = info->tty;
+ 	struct tty_struct *tty = info->port.tty;
  	struct	mgsl_icount *icount = &info->icount;
 	unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD);
 	unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN;
@@ -2203,7 +2197,7 @@
 				if (!(status & info->ignore_status_mask1)) {
 					if (info->read_status_mask1 & BRKD) {
 						tty_insert_flip_char(tty, 0, TTY_BREAK);
-						if (info->flags & ASYNC_SAK)
+						if (info->port.flags & ASYNC_SAK)
 							do_SAK(tty);
 					}
 				}
@@ -2237,7 +2231,7 @@
 {
 	u16 status;
 	unsigned char DataByte;
- 	struct tty_struct *tty = info->tty;
+ 	struct tty_struct *tty = info->port.tty;
  	struct	mgsl_icount *icount = &info->icount;
 
 	if ( debug_level >= DEBUG_LEVEL_ISR )
@@ -2350,7 +2344,7 @@
 		else
 #endif
 		{
-			if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+			if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
 				tx_stop(info);
 				return;
 			}
@@ -2405,7 +2399,7 @@
 		return;
 	}
 
-	if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+	if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
 		tx_stop(info);
 		return;
 	}
@@ -2552,29 +2546,29 @@
 		wake_up_interruptible(&info->status_event_wait_q);
 		wake_up_interruptible(&info->event_wait_q);
 
-		if ( (info->flags & ASYNC_CHECK_CD) &&
+		if ( (info->port.flags & ASYNC_CHECK_CD) &&
 		     (status & MISCSTATUS_DCD_LATCHED) ) {
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 				printk("%s CD now %s...", info->device_name,
 				       (status & SerialSignal_DCD) ? "on" : "off");
 			if (status & SerialSignal_DCD)
-				wake_up_interruptible(&info->open_wait);
+				wake_up_interruptible(&info->port.open_wait);
 			else {
 				if ( debug_level >= DEBUG_LEVEL_ISR )
 					printk("doing serial hangup...");
-				if (info->tty)
-					tty_hangup(info->tty);
+				if (info->port.tty)
+					tty_hangup(info->port.tty);
 			}
 		}
 
-		if ( (info->flags & ASYNC_CTS_FLOW) &&
+		if ( (info->port.flags & ASYNC_CTS_FLOW) &&
 		     (status & MISCSTATUS_CTS_LATCHED) ) {
-			if ( info->tty ) {
-				if (info->tty->hw_stopped) {
+			if ( info->port.tty ) {
+				if (info->port.tty->hw_stopped) {
 					if (status & SerialSignal_CTS) {
 						if ( debug_level >= DEBUG_LEVEL_ISR )
 							printk("CTS tx start...");
-			 			info->tty->hw_stopped = 0;
+			 			info->port.tty->hw_stopped = 0;
 						tx_start(info);
 						info->pending_bh |= BH_TRANSMIT;
 						return;
@@ -2583,7 +2577,7 @@
 					if (!(status & SerialSignal_CTS)) {
 						if ( debug_level >= DEBUG_LEVEL_ISR )
 							printk("CTS tx stop...");
-			 			info->tty->hw_stopped = 1;
+			 			info->port.tty->hw_stopped = 1;
 						tx_stop(info);
 					}
 				}
@@ -2699,7 +2693,7 @@
 		 * do not request bottom half processing if the
 		 * device is not open in a normal mode.
 		 */
-		if ( port && (port->count || port->netcount) &&
+		if ( port && (port->port.count || port->netcount) &&
 		     port->pending_bh && !port->bh_running &&
 		     !port->bh_requested ) {
 			if ( debug_level >= DEBUG_LEVEL_ISR )
@@ -2725,7 +2719,7 @@
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 		printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
 
-	if (info->flags & ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		return 0;
 
 	if (!info->tx_buf) {
@@ -2748,10 +2742,10 @@
 
 	mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10));
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags |= ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 
 	return 0;
 }
@@ -2762,7 +2756,7 @@
 {
 	unsigned long flags;
 
-	if (!(info->flags & ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2784,17 +2778,17 @@
 
 	reset_port(info);
 
- 	if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ 	if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
  		info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
 		set_signals(info);
 	}
 
 	spin_unlock_irqrestore(&info->lock,flags);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-	info->flags &= ~ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 }
 
 static void program_hw(SLMP_INFO *info)
@@ -2825,7 +2819,7 @@
 
 	get_signals(info);
 
-	if (info->netcount || (info->tty && info->tty->termios->c_cflag & CREAD) )
+	if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) )
 		rx_start(info);
 
 	spin_unlock_irqrestore(&info->lock,flags);
@@ -2838,14 +2832,14 @@
 	unsigned cflag;
 	int bits_per_char;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s change_params()\n",
 			 __FILE__,__LINE__, info->device_name );
 
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 
 	/* if B0 rate (hangup) specified then negate DTR and RTS */
 	/* otherwise assert DTR and RTS */
@@ -2893,7 +2887,7 @@
 	 * current data rate.
 	 */
 	if (info->params.data_rate <= 460800) {
-		info->params.data_rate = tty_get_baud_rate(info->tty);
+		info->params.data_rate = tty_get_baud_rate(info->port.tty);
 	}
 
 	if ( info->params.data_rate ) {
@@ -2903,30 +2897,30 @@
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
 
 	if (cflag & CRTSCTS)
-		info->flags |= ASYNC_CTS_FLOW;
+		info->port.flags |= ASYNC_CTS_FLOW;
 	else
-		info->flags &= ~ASYNC_CTS_FLOW;
+		info->port.flags &= ~ASYNC_CTS_FLOW;
 
 	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
+		info->port.flags &= ~ASYNC_CHECK_CD;
 	else
-		info->flags |= ASYNC_CHECK_CD;
+		info->port.flags |= ASYNC_CHECK_CD;
 
 	/* process tty input control flags */
 
 	info->read_status_mask2 = OVRN;
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask2 |= PE | FRME;
- 	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ 	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
  		info->read_status_mask1 |= BRKD;
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		info->ignore_status_mask2 |= PE | FRME;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask1 |= BRKD;
 		/* If ignoring parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			info->ignore_status_mask2 |= OVRN;
 	}
 
@@ -3346,7 +3340,7 @@
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
 		/* just verify that callout device is not active */
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
@@ -3355,25 +3349,25 @@
 
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
+	 * this loop, info->port.count is dropped by one, so that
 	 * close() knows when to free things.  We restore it upon
 	 * exit, either normal or abnormal.
 	 */
 
 	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s block_til_ready() before block, count=%d\n",
-			 __FILE__,__LINE__, tty->driver->name, info->count );
+			 __FILE__,__LINE__, tty->driver->name, info->port.count );
 
 	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = true;
-		info->count--;
+		info->port.count--;
 	}
 	spin_unlock_irqrestore(&info->lock, flags);
-	info->blocked_open++;
+	info->port.blocked_open++;
 
 	while (1) {
 		if ((tty->termios->c_cflag & CBAUD)) {
@@ -3385,8 +3379,8 @@
 
 		set_current_state(TASK_INTERRUPTIBLE);
 
-		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
-			retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+		if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)){
+			retval = (info->port.flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 			break;
 		}
@@ -3395,7 +3389,7 @@
 	 	get_signals(info);
 		spin_unlock_irqrestore(&info->lock,flags);
 
- 		if (!(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->port.flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -3407,24 +3401,24 @@
 
 		if (debug_level >= DEBUG_LEVEL_INFO)
 			printk("%s(%d):%s block_til_ready() count=%d\n",
-				 __FILE__,__LINE__, tty->driver->name, info->count );
+				 __FILE__,__LINE__, tty->driver->name, info->port.count );
 
 		schedule();
 	}
 
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 
 	if (extra_count)
-		info->count++;
-	info->blocked_open--;
+		info->port.count++;
+	info->port.blocked_open--;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s block_til_ready() after, count=%d\n",
-			 __FILE__,__LINE__, tty->driver->name, info->count );
+			 __FILE__,__LINE__, tty->driver->name, info->port.count );
 
 	if (!retval)
-		info->flags |= ASYNC_NORMAL_ACTIVE;
+		info->port.flags |= ASYNC_NORMAL_ACTIVE;
 
 	return retval;
 }
@@ -3806,13 +3800,12 @@
 		printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
 			__FILE__,__LINE__, adapter_num, port_num);
 	} else {
+		tty_port_init(&info->port);
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, bh_handler);
 		info->max_frame_size = 4096;
-		info->close_delay = 5*HZ/10;
-		info->closing_wait = 30*HZ;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
+		info->port.close_delay = 5*HZ/10;
+		info->port.closing_wait = 30*HZ;
 		init_waitqueue_head(&info->status_event_wait_q);
 		init_waitqueue_head(&info->event_wait_q);
 		spin_lock_init(&info->netlock);
@@ -4883,7 +4876,7 @@
 	unsigned int framesize = 0;
 	bool ReturnCode = false;
 	unsigned long flags;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	unsigned char addr_field = 0xff;
    	SCADESC *desc;
 	SCADESC_EX *desc_ex;
@@ -5290,11 +5283,11 @@
 	bool rc = false;
 	unsigned long flags;
 
-	struct tty_struct *oldtty = info->tty;
+	struct tty_struct *oldtty = info->port.tty;
 	u32 speed = info->params.clock_speed;
 
 	info->params.clock_speed = 3686400;
-	info->tty = NULL;
+	info->port.tty = NULL;
 
 	/* assume failure */
 	info->init_error = DiagStatus_DmaFailure;
@@ -5338,7 +5331,7 @@
 	spin_unlock_irqrestore(&info->lock,flags);
 
 	info->params.clock_speed = speed;
-	info->tty = oldtty;
+	info->port.tty = oldtty;
 
 	return rc;
 }
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 047a173..82f6a8c 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -95,8 +95,9 @@
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/seq_file.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
 
 #include <linux/kbd_kern.h>
@@ -682,7 +683,7 @@
 static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
 /* Line disc dispatch table */
-static struct tty_ldisc tty_ldiscs[NR_LDISCS];
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 
 /**
  *	tty_register_ldisc	-	install a line discipline
@@ -697,7 +698,7 @@
  *		takes tty_ldisc_lock to guard against ldisc races
  */
 
-int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
 {
 	unsigned long flags;
 	int ret = 0;
@@ -706,10 +707,9 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	tty_ldiscs[disc] = *new_ldisc;
-	tty_ldiscs[disc].num = disc;
-	tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
-	tty_ldiscs[disc].refcount = 0;
+	tty_ldiscs[disc] = new_ldisc;
+	new_ldisc->num = disc;
+	new_ldisc->refcount = 0;
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
 	return ret;
@@ -737,19 +737,56 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	if (tty_ldiscs[disc].refcount)
+	if (tty_ldiscs[disc]->refcount)
 		ret = -EBUSY;
 	else
-		tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
+		tty_ldiscs[disc] = NULL;
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
 	return ret;
 }
 EXPORT_SYMBOL(tty_unregister_ldisc);
 
+
+/**
+ *	tty_ldisc_try_get	-	try and reference an ldisc
+ *	@disc: ldisc number
+ *	@ld: tty ldisc structure to complete
+ *
+ *	Attempt to open and lock a line discipline into place. Return
+ *	the line discipline refcounted and assigned in ld. On an error
+ *	report the error code back
+ */
+
+static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
+{
+	unsigned long flags;
+	struct tty_ldisc_ops *ldops;
+	int err = -EINVAL;
+	
+	spin_lock_irqsave(&tty_ldisc_lock, flags);
+	ld->ops = NULL;
+	ldops = tty_ldiscs[disc];
+	/* Check the entry is defined */
+	if (ldops) {
+		/* If the module is being unloaded we can't use it */
+		if (!try_module_get(ldops->owner))
+			err = -EAGAIN;
+		else {
+			/* lock it */
+			ldops->refcount++;
+			ld->ops = ldops;
+			err = 0;
+		}
+	}
+	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	return err;
+}
+
 /**
  *	tty_ldisc_get		-	take a reference to an ldisc
  *	@disc: ldisc number
+ *	@ld: tty line discipline structure to use
  *
  *	Takes a reference to a line discipline. Deals with refcounts and
  *	module locking counts. Returns NULL if the discipline is not available.
@@ -760,32 +797,20 @@
  *		takes tty_ldisc_lock to guard against ldisc races
  */
 
-struct tty_ldisc *tty_ldisc_get(int disc)
+static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
 {
-	unsigned long flags;
-	struct tty_ldisc *ld;
+	int err;
 
 	if (disc < N_TTY || disc >= NR_LDISCS)
-		return NULL;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-
-	ld = &tty_ldiscs[disc];
-	/* Check the entry is defined */
-	if (ld->flags & LDISC_FLAG_DEFINED) {
-		/* If the module is being unloaded we can't use it */
-		if (!try_module_get(ld->owner))
-			ld = NULL;
-		else /* lock it */
-			ld->refcount++;
-	} else
-		ld = NULL;
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-	return ld;
+		return -EINVAL;
+	err = tty_ldisc_try_get(disc, ld);
+	if (err == -EAGAIN) {
+		request_module("tty-ldisc-%d", disc);
+		err = tty_ldisc_try_get(disc, ld);
+	}
+	return err;
 }
 
-EXPORT_SYMBOL_GPL(tty_ldisc_get);
-
 /**
  *	tty_ldisc_put		-	drop ldisc reference
  *	@disc: ldisc number
@@ -797,22 +822,67 @@
  *		takes tty_ldisc_lock to guard against ldisc races
  */
 
-void tty_ldisc_put(int disc)
+static void tty_ldisc_put(struct tty_ldisc_ops *ld)
 {
-	struct tty_ldisc *ld;
 	unsigned long flags;
+	int disc = ld->num;
 
 	BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
 
 	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	ld = &tty_ldiscs[disc];
+	ld = tty_ldiscs[disc];
 	BUG_ON(ld->refcount == 0);
 	ld->refcount--;
 	module_put(ld->owner);
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
 
-EXPORT_SYMBOL_GPL(tty_ldisc_put);
+static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+	return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+	int i = *(loff_t *)v;
+	struct tty_ldisc ld;
+	
+	if (tty_ldisc_get(i, &ld) < 0)
+		return 0;
+	seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
+	tty_ldisc_put(ld.ops);
+	return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+	.start	= tty_ldiscs_seq_start,
+	.next	= tty_ldiscs_seq_next,
+	.stop	= tty_ldiscs_seq_stop,
+	.show	= tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= proc_tty_ldiscs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
 
 /**
  *	tty_ldisc_assign	-	set ldisc on a tty
@@ -829,8 +899,8 @@
 
 static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
 {
+	ld->refcount = 0;
 	tty->ldisc = *ld;
-	tty->ldisc.refcount = 0;
 }
 
 /**
@@ -954,6 +1024,41 @@
 }
 
 /**
+ *	tty_ldisc_restore	-	helper for tty ldisc change
+ *	@tty: tty to recover
+ *	@old: previous ldisc
+ *
+ *	Restore the previous line discipline or N_TTY when a line discipline
+ *	change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+	char buf[64];
+	struct tty_ldisc new_ldisc;
+
+	/* There is an outstanding reference here so this is safe */
+	tty_ldisc_get(old->ops->num, old);
+	tty_ldisc_assign(tty, old);
+	tty_set_termios_ldisc(tty, old->ops->num);
+	if (old->ops->open && (old->ops->open(tty) < 0)) {
+		tty_ldisc_put(old->ops);
+		/* This driver is always present */
+		if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
+			panic("n_tty: get");
+		tty_ldisc_assign(tty, &new_ldisc);
+		tty_set_termios_ldisc(tty, N_TTY);
+		if (new_ldisc.ops->open) {
+			int r = new_ldisc.ops->open(tty);
+				if (r < 0)
+				panic("Couldn't open N_TTY ldisc for "
+				      "%s --- error %d.",
+				      tty_name(tty, buf), r);
+		}
+	}
+}
+
+/**
  *	tty_set_ldisc		-	set line discipline
  *	@tty: the terminal to set
  *	@ldisc: the line discipline
@@ -967,28 +1072,18 @@
 
 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
-	int retval = 0;
-	struct tty_ldisc o_ldisc;
-	char buf[64];
+	int retval;
+	struct tty_ldisc o_ldisc, new_ldisc;
 	int work;
 	unsigned long flags;
-	struct tty_ldisc *ld;
 	struct tty_struct *o_tty;
 
-	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
-		return -EINVAL;
-
 restart:
-
-	ld = tty_ldisc_get(ldisc);
-	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
-	/* Cyrus Durgin <cider@speakeasy.org> */
-	if (ld == NULL) {
-		request_module("tty-ldisc-%d", ldisc);
-		ld = tty_ldisc_get(ldisc);
-	}
-	if (ld == NULL)
-		return -EINVAL;
+	/* This is a bit ugly for now but means we can break the 'ldisc
+	   is part of the tty struct' assumption later */
+	retval = tty_ldisc_get(ldisc, &new_ldisc);
+	if (retval)
+		return retval;
 
 	/*
 	 *	Problem: What do we do if this blocks ?
@@ -996,8 +1091,8 @@
 
 	tty_wait_until_sent(tty, 0);
 
-	if (tty->ldisc.num == ldisc) {
-		tty_ldisc_put(ldisc);
+	if (tty->ldisc.ops->num == ldisc) {
+		tty_ldisc_put(new_ldisc.ops);
 		return 0;
 	}
 
@@ -1024,7 +1119,7 @@
 			/* Free the new ldisc we grabbed. Must drop the lock
 			   first. */
 			spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-			tty_ldisc_put(ldisc);
+			tty_ldisc_put(o_ldisc.ops);
 			/*
 			 * There are several reasons we may be busy, including
 			 * random momentary I/O traffic. We must therefore
@@ -1038,7 +1133,7 @@
 		}
 		if (o_tty && o_tty->ldisc.refcount) {
 			spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-			tty_ldisc_put(ldisc);
+			tty_ldisc_put(o_tty->ldisc.ops);
 			if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
 				return -ERESTARTSYS;
 			goto restart;
@@ -1049,8 +1144,9 @@
 	 *	another ldisc change
 	 */
 	if (!test_bit(TTY_LDISC, &tty->flags)) {
+		struct tty_ldisc *ld;
 		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-		tty_ldisc_put(ldisc);
+		tty_ldisc_put(new_ldisc.ops);
 		ld = tty_ldisc_ref_wait(tty);
 		tty_ldisc_deref(ld);
 		goto restart;
@@ -1060,7 +1156,7 @@
 	if (o_tty)
 		clear_bit(TTY_LDISC, &o_tty->flags);
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
+	
 	/*
 	 *	From this point on we know nobody has an ldisc
 	 *	usage reference, nor can they obtain one until
@@ -1070,45 +1166,30 @@
 	work = cancel_delayed_work(&tty->buf.work);
 	/*
 	 * Wait for ->hangup_work and ->buf.work handlers to terminate
+	 * MUST NOT hold locks here.
 	 */
 	flush_scheduled_work();
 	/* Shutdown the current discipline. */
-	if (tty->ldisc.close)
-		(tty->ldisc.close)(tty);
+	if (o_ldisc.ops->close)
+		(o_ldisc.ops->close)(tty);
 
 	/* Now set up the new line discipline. */
-	tty_ldisc_assign(tty, ld);
+	tty_ldisc_assign(tty, &new_ldisc);
 	tty_set_termios_ldisc(tty, ldisc);
-	if (tty->ldisc.open)
-		retval = (tty->ldisc.open)(tty);
+	if (new_ldisc.ops->open)
+		retval = (new_ldisc.ops->open)(tty);
 	if (retval < 0) {
-		tty_ldisc_put(ldisc);
-		/* There is an outstanding reference here so this is safe */
-		tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num));
-		tty_set_termios_ldisc(tty, tty->ldisc.num);
-		if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
-			tty_ldisc_put(o_ldisc.num);
-			/* This driver is always present */
-			tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
-			tty_set_termios_ldisc(tty, N_TTY);
-			if (tty->ldisc.open) {
-				int r = tty->ldisc.open(tty);
-
-				if (r < 0)
-					panic("Couldn't open N_TTY ldisc for "
-					      "%s --- error %d.",
-					      tty_name(tty, buf), r);
-			}
-		}
+		tty_ldisc_put(new_ldisc.ops);
+		tty_ldisc_restore(tty, &o_ldisc);
 	}
 	/* At this point we hold a reference to the new ldisc and a
 	   a reference to the old ldisc. If we ended up flipping back
 	   to the existing ldisc we have two references to it */
 
-	if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
+	if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
 		tty->ops->set_ldisc(tty);
 
-	tty_ldisc_put(o_ldisc.num);
+	tty_ldisc_put(o_ldisc.ops);
 
 	/*
 	 *	Allow ldisc referencing to occur as soon as the driver
@@ -1335,8 +1416,8 @@
 	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
 		ld = tty_ldisc_ref(tty);
 		if (ld) {
-			if (ld->write_wakeup)
-				ld->write_wakeup(tty);
+			if (ld->ops->write_wakeup)
+				ld->ops->write_wakeup(tty);
 			tty_ldisc_deref(ld);
 		}
 	}
@@ -1357,8 +1438,8 @@
 {
 	struct tty_ldisc *ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if (ld->flush_buffer)
-			ld->flush_buffer(tty);
+		if (ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
 		tty_ldisc_deref(ld);
 	}
 	tty_buffer_flush(tty);
@@ -1386,7 +1467,7 @@
  *	do_tty_hangup		-	actual handler for hangup events
  *	@work: tty device
  *
- *	This can be called by the "eventd" kernel thread.  That is process
+k *	This can be called by the "eventd" kernel thread.  That is process
  *	synchronous but doesn't hold any locks, so we need to make sure we
  *	have the appropriate locks for what we're doing.
  *
@@ -1449,14 +1530,14 @@
 	ld = tty_ldisc_ref(tty);
 	if (ld != NULL) {
 		/* We may have no line discipline at this point */
-		if (ld->flush_buffer)
-			ld->flush_buffer(tty);
+		if (ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
 		tty_driver_flush_buffer(tty);
 		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-		    ld->write_wakeup)
-			ld->write_wakeup(tty);
-		if (ld->hangup)
-			ld->hangup(tty);
+		    ld->ops->write_wakeup)
+			ld->ops->write_wakeup(tty);
+		if (ld->ops->hangup)
+			ld->ops->hangup(tty);
 	}
 	/*
 	 * FIXME: Once we trust the LDISC code better we can wait here for
@@ -1825,8 +1906,8 @@
 	/* We want to wait for the line discipline to sort out in this
 	   situation */
 	ld = tty_ldisc_ref_wait(tty);
-	if (ld->read)
-		i = (ld->read)(tty, file, buf, count);
+	if (ld->ops->read)
+		i = (ld->ops->read)(tty, file, buf, count);
 	else
 		i = -EIO;
 	tty_ldisc_deref(ld);
@@ -1978,10 +2059,10 @@
 		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
 			tty->driver->name);
 	ld = tty_ldisc_ref_wait(tty);
-	if (!ld->write)
+	if (!ld->ops->write)
 		ret = -EIO;
 	else
-		ret = do_tty_write(ld->write, tty, file, buf, count);
+		ret = do_tty_write(ld->ops->write, tty, file, buf, count);
 	tty_ldisc_deref(ld);
 	return ret;
 }
@@ -2007,6 +2088,42 @@
 	return tty_write(file, buf, count, ppos);
 }
 
+void tty_port_init(struct tty_port *port)
+{
+	memset(port, 0, sizeof(*port));
+	init_waitqueue_head(&port->open_wait);
+	init_waitqueue_head(&port->close_wait);
+	mutex_init(&port->mutex);
+	port->close_delay = (50 * HZ) / 100;
+	port->closing_wait = (3000 * HZ) / 100;
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+	/* We may sleep in get_zeroed_page() */
+	mutex_lock(&port->mutex);
+	if (port->xmit_buf == NULL)
+		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+	mutex_unlock(&port->mutex);
+	if (port->xmit_buf == NULL)
+		return -ENOMEM;
+	return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+	mutex_lock(&port->mutex);
+	if (port->xmit_buf != NULL) {
+		free_page((unsigned long)port->xmit_buf);
+		port->xmit_buf = NULL;
+	}
+	mutex_unlock(&port->mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+
 static char ptychar[] = "pqrstuvwxyzabcde";
 
 /**
@@ -2076,6 +2193,7 @@
 	struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
 	struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
 	int retval = 0;
+	struct tty_ldisc *ld;
 
 	/* check whether we're reopening an existing tty */
 	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
@@ -2224,17 +2342,19 @@
 	 * If we fail here just call release_tty to clean up.  No need
 	 * to decrement the use counts, as release_tty doesn't care.
 	 */
+	 
+	ld = &tty->ldisc;
 
-	if (tty->ldisc.open) {
-		retval = (tty->ldisc.open)(tty);
+	if (ld->ops->open) {
+		retval = (ld->ops->open)(tty);
 		if (retval)
 			goto release_mem_out;
 	}
-	if (o_tty && o_tty->ldisc.open) {
-		retval = (o_tty->ldisc.open)(o_tty);
+	if (o_tty && o_tty->ldisc.ops->open) {
+		retval = (o_tty->ldisc.ops->open)(o_tty);
 		if (retval) {
-			if (tty->ldisc.close)
-				(tty->ldisc.close)(tty);
+			if (ld->ops->close)
+				(ld->ops->close)(tty);
 			goto release_mem_out;
 		}
 		tty_ldisc_enable(o_tty);
@@ -2378,6 +2498,7 @@
 static void release_dev(struct file *filp)
 {
 	struct tty_struct *tty, *o_tty;
+	struct tty_ldisc ld;
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	devpts;
 	int	idx;
@@ -2611,26 +2732,27 @@
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 	/*
 	 * Shutdown the current line discipline, and reset it to N_TTY.
-	 * N.B. why reset ldisc when we're releasing the memory??
 	 *
 	 * FIXME: this MUST get fixed for the new reflocking
 	 */
-	if (tty->ldisc.close)
-		(tty->ldisc.close)(tty);
-	tty_ldisc_put(tty->ldisc.num);
+	if (tty->ldisc.ops->close)
+		(tty->ldisc.ops->close)(tty);
+	tty_ldisc_put(tty->ldisc.ops);
 
 	/*
 	 *	Switch the line discipline back
 	 */
-	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+	WARN_ON(tty_ldisc_get(N_TTY, &ld));
+	tty_ldisc_assign(tty, &ld);
 	tty_set_termios_ldisc(tty, N_TTY);
 	if (o_tty) {
 		/* FIXME: could o_tty be in setldisc here ? */
 		clear_bit(TTY_LDISC, &o_tty->flags);
-		if (o_tty->ldisc.close)
-			(o_tty->ldisc.close)(o_tty);
-		tty_ldisc_put(o_tty->ldisc.num);
-		tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY));
+		if (o_tty->ldisc.ops->close)
+			(o_tty->ldisc.ops->close)(o_tty);
+		tty_ldisc_put(o_tty->ldisc.ops);
+		WARN_ON(tty_ldisc_get(N_TTY, &ld));
+		tty_ldisc_assign(o_tty, &ld);
 		tty_set_termios_ldisc(o_tty, N_TTY);
 	}
 	/*
@@ -2899,8 +3021,8 @@
 		return 0;
 
 	ld = tty_ldisc_ref_wait(tty);
-	if (ld->poll)
-		ret = (ld->poll)(tty, filp, wait);
+	if (ld->ops->poll)
+		ret = (ld->ops->poll)(tty, filp, wait);
 	tty_ldisc_deref(ld);
 	return ret;
 }
@@ -2974,7 +3096,7 @@
 	if (get_user(ch, p))
 		return -EFAULT;
 	ld = tty_ldisc_ref_wait(tty);
-	ld->receive_buf(tty, &ch, &mbz, 1);
+	ld->ops->receive_buf(tty, &ch, &mbz, 1);
 	tty_ldisc_deref(ld);
 	return 0;
 }
@@ -3395,35 +3517,31 @@
 static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
 	     unsigned __user *p)
 {
-	int retval = -EINVAL;
+	int retval;
+	unsigned int set, clear, val;
 
-	if (tty->ops->tiocmset) {
-		unsigned int set, clear, val;
+	if (tty->ops->tiocmset == NULL)
+		return -EINVAL;
 
-		retval = get_user(val, p);
-		if (retval)
-			return retval;
-
-		set = clear = 0;
-		switch (cmd) {
-		case TIOCMBIS:
-			set = val;
-			break;
-		case TIOCMBIC:
-			clear = val;
-			break;
-		case TIOCMSET:
-			set = val;
-			clear = ~val;
-			break;
-		}
-
-		set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-		clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-
-		retval = tty->ops->tiocmset(tty, file, set, clear);
+	retval = get_user(val, p);
+	if (retval)
+		return retval;
+	set = clear = 0;
+	switch (cmd) {
+	case TIOCMBIS:
+		set = val;
+		break;
+	case TIOCMBIC:
+		clear = val;
+		break;
+	case TIOCMSET:
+		set = val;
+		clear = ~val;
+		break;
 	}
-	return retval;
+	set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+	clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+	return tty->ops->tiocmset(tty, file, set, clear);
 }
 
 /*
@@ -3528,7 +3646,7 @@
 	case TIOCGSID:
 		return tiocgsid(tty, real_tty, p);
 	case TIOCGETD:
-		return put_user(tty->ldisc.num, (int __user *)p);
+		return put_user(tty->ldisc.ops->num, (int __user *)p);
 	case TIOCSETD:
 		return tiocsetd(tty, p);
 #ifdef CONFIG_VT
@@ -3581,8 +3699,8 @@
 	}
 	ld = tty_ldisc_ref_wait(tty);
 	retval = -EINVAL;
-	if (ld->ioctl) {
-		retval = ld->ioctl(tty, file, cmd, arg);
+	if (ld->ops->ioctl) {
+		retval = ld->ops->ioctl(tty, file, cmd, arg);
 		if (retval == -ENOIOCTLCMD)
 			retval = -EINVAL;
 	}
@@ -3609,8 +3727,8 @@
 	}
 
 	ld = tty_ldisc_ref_wait(tty);
-	if (ld->compat_ioctl)
-		retval = ld->compat_ioctl(tty, file, cmd, arg);
+	if (ld->ops->compat_ioctl)
+		retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
 	tty_ldisc_deref(ld);
 
 	return retval;
@@ -3782,7 +3900,8 @@
 			flag_buf = head->flag_buf_ptr + head->read;
 			head->read += count;
 			spin_unlock_irqrestore(&tty->buf.lock, flags);
-			disc->receive_buf(tty, char_buf, flag_buf, count);
+			disc->ops->receive_buf(tty, char_buf,
+							flag_buf, count);
 			spin_lock_irqsave(&tty->buf.lock, flags);
 		}
 		/* Restore the queue head */
@@ -3843,9 +3962,12 @@
 
 static void initialize_tty_struct(struct tty_struct *tty)
 {
+	struct tty_ldisc ld;
 	memset(tty, 0, sizeof(struct tty_struct));
 	tty->magic = TTY_MAGIC;
-	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+	if (tty_ldisc_get(N_TTY, &ld) < 0)
+		panic("n_tty: init_tty");
+	tty_ldisc_assign(tty, &ld);
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	tty->overrun_time = jiffies;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8f81139..ea9fc5d 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -491,8 +491,8 @@
 
 	ld = tty_ldisc_ref(tty);
 	if (ld != NULL) {
-		if (ld->set_termios)
-			(ld->set_termios)(tty, &old_termios);
+		if (ld->ops->set_termios)
+			(ld->ops->set_termios)(tty, &old_termios);
 		tty_ldisc_deref(ld);
 	}
 	mutex_unlock(&tty->termios_mutex);
@@ -552,8 +552,8 @@
 	ld = tty_ldisc_ref(tty);
 
 	if (ld != NULL) {
-		if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
-			ld->flush_buffer(tty);
+		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
 		tty_ldisc_deref(ld);
 	}
 
@@ -959,12 +959,12 @@
 	ld = tty_ldisc_ref(tty);
 	switch (arg) {
 	case TCIFLUSH:
-		if (ld && ld->flush_buffer)
-			ld->flush_buffer(tty);
+		if (ld && ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
 		break;
 	case TCIOFLUSH:
-		if (ld && ld->flush_buffer)
-			ld->flush_buffer(tty);
+		if (ld && ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
 		/* fall through */
 	case TCOFLUSH:
 		tty_driver_flush_buffer(tty);
diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c
index 8cd8507..9c0c9af 100644
--- a/drivers/dio/dio-driver.c
+++ b/drivers/dio/dio-driver.c
@@ -119,19 +119,7 @@
 	if (!ids)
 		return 0;
 
-	while (ids->id) {
-		if (ids->id == DIO_WILDCARD)
-			return 1;
-		if (DIO_NEEDSSECID(ids->id & 0xff)) {
-			if (ids->id == d->id)
-				return 1;
-		} else {
-			if ((ids->id & 0xff) == (d->id & 0xff))
-				return 1;
-		}
-		ids++;
-	}
-	return 0;
+	return dio_match_device(ids, d) ? 1 : 0;
 }
 
 
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index 4e92100..1839194 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -220,7 +220,7 @@
 	int i, error;
 
 	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
-		return -EIO;
+		return -ENODEV;
 
 	// need to init core driver if not already done so
 	if (atari_keyb_init())
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 7ff71ba..b9694b6 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -216,7 +216,7 @@
  * The line discipline structure.
  */
 
-static struct tty_ldisc serport_ldisc = {
+static struct tty_ldisc_ops serport_ldisc = {
 	.owner =	THIS_MODULE,
 	.name =		"input",
 	.open =		serport_ldisc_open,
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 2095153..8a35029 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -466,7 +466,7 @@
 	ld = tty_ldisc_ref(mp->tty);
 	if (ld == NULL)
 		return -1;
-	if (ld->receive_buf == NULL) {
+	if (ld->ops->receive_buf == NULL) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
 		printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
 #endif
@@ -501,7 +501,7 @@
 	printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
 				datahandle, skb->len);
 #endif
-	ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
+	ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len);
 	kfree_skb(skb);
 	tty_ldisc_deref(ld);
 	return 0;
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 45d1ee9..5e89fa1 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -766,7 +766,7 @@
 	cs_put(cs);
 }
 
-static struct tty_ldisc gigaset_ldisc = {
+static struct tty_ldisc_ops gigaset_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
 	.name		= "ser_gigaset",
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 7a7803b..93ea201 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -38,7 +38,6 @@
 	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	depends on VIDEO_DEV && VIDEO_V4L2_COMMON
 	default VIDEO_DEV && VIDEO_V4L2_COMMON
-	select VIDEO_V4L1_COMPAT
 	---help---
 	  Enables drivers based on the legacy V4L1 API.
 
@@ -49,9 +48,9 @@
 	  If you are unsure as to whether this is required, answer Y.
 
 config VIDEO_V4L1_COMPAT
-	bool "Enable Video For Linux API 1 compatible Layer"
+	bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1
 	depends on VIDEO_DEV
-	default VIDEO_DEV
+	default y
 	---help---
 	  Enables a compatibility API used by most V4L2 devices to allow
 	  its usage with legacy applications that supports only V4L1 api.
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 2665052..16792a6 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -66,7 +66,6 @@
 	if (ir_codes)
 		memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
 
-
 	dev->keycode     = ir->ir_codes;
 	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
 	dev->keycodemax  = IR_KEYTAB_SIZE;
@@ -78,6 +77,7 @@
 	if (repeat)
 		set_bit(EV_REP, dev->evbit);
 }
+EXPORT_SYMBOL_GPL(ir_input_init);
 
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
 {
@@ -86,6 +86,7 @@
 		ir_input_key_event(dev,ir);
 	}
 }
+EXPORT_SYMBOL_GPL(ir_input_nokey);
 
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
 		      u32 ir_key, u32 ir_raw)
@@ -104,6 +105,7 @@
 		ir_input_key_event(dev,ir);
 	}
 }
+EXPORT_SYMBOL_GPL(ir_input_keydown);
 
 /* -------------------------------------------------------------------------- */
 /* extract mask bits out of data and pack them into the result */
@@ -122,6 +124,7 @@
 
 	return value;
 }
+EXPORT_SYMBOL_GPL(ir_extract_bits);
 
 static int inline getbit(u32 *samples, int bit)
 {
@@ -146,6 +149,7 @@
 	printk("\n");
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ir_dump_samples);
 
 /* decode raw samples, pulse distance coding used by NEC remotes */
 int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
@@ -212,6 +216,7 @@
 
 	return value;
 }
+EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
 /* decode raw samples, biphase coding, used by rc5 for example */
 int ir_decode_biphase(u32 *samples, int count, int low, int high)
@@ -253,6 +258,7 @@
 	}
 	return value;
 }
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
 
 /* RC5 decoding stuff, moved from bttv-input.c to share it with
  * saa7134 */
@@ -353,6 +359,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 
 void ir_rc5_timer_keyup(unsigned long data)
 {
@@ -361,21 +368,4 @@
 	dprintk(1, "ir-common: key released\n");
 	ir_input_nokey(ir->dev, &ir->ir);
 }
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 89c7660..d01965e 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -233,7 +233,7 @@
 
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 {
-	u32          *cpu;
+	__le32       *cpu;
 	dma_addr_t   dma_addr;
 
 	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
@@ -250,7 +250,7 @@
 int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
 	struct scatterlist *list, int sglen  )
 {
-	u32 *ptr, fill;
+	__le32 *ptr, fill;
 	int nr_pages = 0;
 	int i,p;
 
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 9c90539..05bde9c 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -338,7 +338,7 @@
 	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
 {
 	struct saa7146_vv *vv = dev->vv_data;
-	u32 *clipping = vv->d_clipping.cpu_addr;
+	__le32 *clipping = vv->d_clipping.cpu_addr;
 
 	int width = fh->ov.win.w.width;
 	int height =  fh->ov.win.w.height;
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 35b01ec..c11da4d 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -24,7 +24,7 @@
    sent through the saa7146. have a look at the specifications p. 122 ff
    to understand this. it returns the number of u32s to send, or -1
    in case of an error. */
-static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
+static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
 {
 	int h1, h2;
 	int i, j, addr;
@@ -47,7 +47,7 @@
 	}
 
 	/* be careful: clear out the i2c-mem first */
-	memset(op,0,sizeof(u32)*mem);
+	memset(op,0,sizeof(__le32)*mem);
 
 	/* loop through all messages */
 	for(i = 0; i < num; i++) {
@@ -57,16 +57,16 @@
 		   so we have to perform a translation */
 		addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
 		h1 = op_count/3; h2 = op_count%3;
-		op[h1] |= (	    (u8)addr << ((3-h2)*8));
-		op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
+		op[h1] |= cpu_to_le32(	    (u8)addr << ((3-h2)*8));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
 		op_count++;
 
 		/* loop through all bytes of message i */
 		for(j = 0; j < m[i].len; j++) {
 			/* insert the data bytes */
 			h1 = op_count/3; h2 = op_count%3;
-			op[h1] |= ( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
-			op[h1] |= (       SAA7146_I2C_CONT << ((3-h2)*2));
+			op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
+			op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
 			op_count++;
 		}
 
@@ -75,9 +75,9 @@
 	/* have a look at the last byte inserted:
 	  if it was: ...CONT change it to ...STOP */
 	h1 = (op_count-1)/3; h2 = (op_count-1)%3;
-	if ( SAA7146_I2C_CONT == (0x3 & (op[h1] >> ((3-h2)*2))) ) {
-		op[h1] &= ~(0x2 << ((3-h2)*2));
-		op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
+	if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
+		op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
+		op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
 	}
 
 	/* return the number of u32s to send */
@@ -88,7 +88,7 @@
    which bytes were read through the adapter and write them back to the corresponding
    i2c-message. but instead, we simply write back all bytes.
    fixme: this could be improved. */
-static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
+static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
 {
 	int i, j;
 	int op_count = 0;
@@ -101,7 +101,7 @@
 		/* loop throgh all bytes of message i */
 		for(j = 0; j < m[i].len; j++) {
 			/* write back all bytes that could have been read */
-			m[i].buf[j] = (op[op_count/3] >> ((3-(op_count%3))*8));
+			m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
 			op_count++;
 		}
 	}
@@ -174,7 +174,7 @@
 /* this functions writes out the data-byte 'dword' to the i2c-device.
    it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
    failed badly (e.g. address error) */
-static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay)
+static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
 {
 	u32 status = 0, mc2 = 0;
 	int trial = 0;
@@ -186,7 +186,7 @@
 	if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
 
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, *dword);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
 
 		dev->i2c_op = 1;
 		SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
@@ -209,7 +209,7 @@
 		status = saa7146_read(dev, I2C_STATUS);
 	} else {
 		saa7146_write(dev, I2C_STATUS,	 dev->i2c_bitrate);
-		saa7146_write(dev, I2C_TRANSFER, *dword);
+		saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 
 		/* do not poll for i2c-status before upload is complete */
@@ -282,7 +282,7 @@
 	}
 
 	/* read back data, just in case we were reading ... */
-	*dword = saa7146_read(dev, I2C_TRANSFER);
+	*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
 
 	DEB_I2C(("after: 0x%08x\n",*dword));
 	return 0;
@@ -291,7 +291,7 @@
 static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 {
 	int i = 0, count = 0;
-	u32* buffer = dev->d_i2c.cpu_addr;
+	__le32 *buffer = dev->d_i2c.cpu_addr;
 	int err = 0;
 	int address_err = 0;
 	int short_delay = 0;
@@ -376,7 +376,7 @@
 	/* another bug in revision 0: the i2c-registers get uploaded randomly by other
 	   uploads, so we better clear them out before continueing */
 	if( 0 == dev->revision ) {
-		u32 zero = 0;
+		__le32 zero = 0;
 		saa7146_i2c_reset(dev);
 		if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
 			INFO(("revision 0 error. this should never happen.\n"));
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 3cbc6eb..a5e6275 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -605,8 +605,8 @@
 		struct saa7146_pgtable *pt1 = &buf->pt[0];
 		struct saa7146_pgtable *pt2 = &buf->pt[1];
 		struct saa7146_pgtable *pt3 = &buf->pt[2];
-		u32  *ptr1, *ptr2, *ptr3;
-		u32 fill;
+		__le32  *ptr1, *ptr2, *ptr3;
+		__le32 fill;
 
 		int size = buf->fmt->width*buf->fmt->height;
 		int i,p,m1,m2,m3,o1,o2;
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 8548296..850d568 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -34,6 +34,7 @@
 menuconfig MEDIA_TUNER_CUSTOMIZE
 	bool "Customize analog and hybrid tuner modules to build"
 	depends on MEDIA_TUNER
+	default n
 	help
 	  This allows the user to deselect tuner drivers unnecessary
 	  for their hardware from the build. Use this option with care
diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c
index 83e7561..ab14ceb 100644
--- a/drivers/media/common/tuners/tda18271-maps.c
+++ b/drivers/media/common/tuners/tda18271-maps.c
@@ -1,5 +1,5 @@
 /*
-    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
+    tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner
 
     Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
 
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 30eb07b..4dd1d24 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <media/tuner.h>
 #include <linux/mutex.h>
+#include <asm/unaligned.h>
 #include "tuner-i2c.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028-types.h"
@@ -292,10 +293,10 @@
 	name[sizeof(name) - 1] = 0;
 	p += sizeof(name) - 1;
 
-	priv->firm_version = le16_to_cpu(*(__u16 *) p);
+	priv->firm_version = get_unaligned_le16(p);
 	p += 2;
 
-	n_array = le16_to_cpu(*(__u16 *) p);
+	n_array = get_unaligned_le16(p);
 	p += 2;
 
 	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
@@ -324,26 +325,26 @@
 		}
 
 		/* Checks if there's enough bytes to read */
-		if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
-			tuner_err("Firmware header is incomplete!\n");
-			goto corrupt;
-		}
+		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+			goto header;
 
-		type = le32_to_cpu(*(__u32 *) p);
+		type = get_unaligned_le32(p);
 		p += sizeof(type);
 
-		id = le64_to_cpu(*(v4l2_std_id *) p);
+		id = get_unaligned_le64(p);
 		p += sizeof(id);
 
 		if (type & HAS_IF) {
-			int_freq = le16_to_cpu(*(__u16 *) p);
+			int_freq = get_unaligned_le16(p);
 			p += sizeof(int_freq);
+			if (endp - p < sizeof(size))
+				goto header;
 		}
 
-		size = le32_to_cpu(*(__u32 *) p);
+		size = get_unaligned_le32(p);
 		p += sizeof(size);
 
-		if ((!size) || (size + p > endp)) {
+		if (!size || size > endp - p) {
 			tuner_err("Firmware type ");
 			dump_firm_type(type);
 			printk("(%x), id %llx is corrupted "
@@ -382,6 +383,8 @@
 
 	goto done;
 
+header:
+	tuner_err("Firmware header is incomplete!\n");
 corrupt:
 	rc = -EINVAL;
 	tuner_err("Error: firmware file is corrupted!\n");
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 4878d64..5f99de0 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -36,6 +36,10 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+static int xc5000_load_fw_on_attach;
+module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
+MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
+
 #define dprintk(level,fmt, arg...) if (debug >= level) \
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
@@ -972,6 +976,9 @@
 
 	fe->tuner_priv = priv;
 
+	if (xc5000_load_fw_on_attach)
+		xc5000_init(fe);
+
 	return fe;
 }
 EXPORT_SYMBOL(xc5000_attach);
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 7b21b49..8bc1445 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -21,6 +21,7 @@
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
 source "drivers/media/dvb/cinergyT2/Kconfig"
+source "drivers/media/dvb/siano/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
 	depends on DVB_CORE && (PCI || USB) && I2C
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index a7ad084..d6ba4d1 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index 375fd28..d19b592 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -128,7 +128,7 @@
 	dma_addr_t buf_dma;
 
 	u32 risc_size;
-	u32 *risc_cpu;
+	__le32 *risc_cpu;
 	dma_addr_t risc_dma;
 	u32 risc_pos;
 
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index b0d347d..eb91fd8 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -247,7 +247,7 @@
 	void* priv;                  /* Pointer to private data of the API client */
 	int (*open) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
-	int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
+	int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
 	int (*allocate_ts_feed) (struct dmx_demux* demux,
 				 struct dmx_ts_feed** feed,
 				 dmx_ts_cb callback);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index df5bef6..1cf9fcb 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -96,7 +96,7 @@
 		if (avail > todo)
 			avail = todo;
 
-		ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
+		ret = dvb_ringbuffer_read_user(src, buf, avail);
 		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 588fbe1..8e5dd7b 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1357,7 +1357,7 @@
 
 		idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
 		while (idx != -1) {
-			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+			dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
 			if (connection_id == -1)
 				connection_id = hdr[0];
 			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
@@ -1438,7 +1438,7 @@
 			goto exit;
 		}
 
-		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+		dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
 		if (connection_id == -1)
 			connection_id = hdr[0];
 		if (hdr[0] == connection_id) {
@@ -1449,8 +1449,8 @@
 					fraglen -= 2;
 				}
 
-				if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-								      (u8 *)buf + pktlen, fraglen, 1)) < 0) {
+				if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+								      buf + pktlen, fraglen)) < 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 934e15f..e2eca0b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1056,16 +1056,27 @@
 	return 0;
 }
 
-static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+	void *p;
 
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 
-	if (mutex_lock_interruptible(&dvbdemux->mutex))
+	p = kmalloc(count, GFP_USER);
+	if (!p)
+		return -ENOMEM;
+	if (copy_from_user(p, buf, count)) {
+		kfree(p);
+		return -EFAULT;
+	}
+	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+		kfree(p);
 		return -ERESTARTSYS;
-	dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
+	}
+	dvb_dmx_swfilter(dvbdemux, p, count);
+	kfree(p);
 	mutex_unlock(&dvbdemux->mutex);
 
 	if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index c2c0337..c93019c 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -606,7 +606,7 @@
 			if (priv->ule_dbit) {
 				/* Set D-bit for CRC32 verification,
 				 * if it was set originally. */
-				ulen |= 0x0080;
+				ulen |= htons(0x8000);
 			}
 
 			ule_crc = iov_crc32(ule_crc, iov, 3);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 872985b..584bbd1 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -107,35 +107,43 @@
 	wake_up(&rbuf->queue);
 }
 
-
-
-ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
 {
 	size_t todo = len;
 	size_t split;
 
 	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
 	if (split > 0) {
-		if (!usermem)
-			memcpy(buf, rbuf->data+rbuf->pread, split);
-		else
-			if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-				return -EFAULT;
+		if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+			return -EFAULT;
 		buf += split;
 		todo -= split;
 		rbuf->pread = 0;
 	}
-	if (!usermem)
-		memcpy(buf, rbuf->data+rbuf->pread, todo);
-	else
-		if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-			return -EFAULT;
+	if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+		return -EFAULT;
 
 	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 
 	return len;
 }
 
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+rbuf->pread, split);
+		buf += split;
+		todo -= split;
+		rbuf->pread = 0;
+	}
+	memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+}
 
 
 ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
@@ -171,8 +179,8 @@
 	return status;
 }
 
-ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				int offset, u8* buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8 __user *buf, size_t len)
 {
 	size_t todo;
 	size_t split;
@@ -187,24 +195,43 @@
 	todo = len;
 	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
 	if (split > 0) {
-		if (!usermem)
-			memcpy(buf, rbuf->data+idx, split);
-		else
-			if (copy_to_user(buf, rbuf->data+idx, split))
-				return -EFAULT;
+		if (copy_to_user(buf, rbuf->data+idx, split))
+			return -EFAULT;
 		buf += split;
 		todo -= split;
 		idx = 0;
 	}
-	if (!usermem)
-		memcpy(buf, rbuf->data+idx, todo);
-	else
-		if (copy_to_user(buf, rbuf->data+idx, todo))
-			return -EFAULT;
+	if (copy_to_user(buf, rbuf->data+idx, todo))
+		return -EFAULT;
 
 	return len;
 }
 
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+				int offset, u8* buf, size_t len)
+{
+	size_t todo;
+	size_t split;
+	size_t pktlen;
+
+	pktlen = rbuf->data[idx] << 8;
+	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+	if (offset > pktlen) return -EINVAL;
+	if ((offset + len) > pktlen) len = pktlen - offset;
+
+	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+	todo = len;
+	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+	if (split > 0) {
+		memcpy(buf, rbuf->data+idx, split);
+		buf += split;
+		todo -= split;
+		idx = 0;
+	}
+	memcpy(buf, rbuf->data+idx, todo);
+	return len;
+}
+
 void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
 {
 	size_t pktlen;
@@ -266,5 +293,6 @@
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 8908262..41f04da 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -61,7 +61,7 @@
 **     *** read min. 1000, max. <bufsize> bytes ***
 **     avail = dvb_ringbuffer_avail(rbuf);
 **     if (avail >= 1000)
-**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
+**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
 **     else
 **         ...
 **
@@ -114,8 +114,10 @@
 ** <usermem> specifies whether <buf> resides in user space
 ** returns number of bytes transferred or -EFAULT
 */
-extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
-				   size_t len, int usermem);
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+				   u8 __user *buf, size_t len);
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+				   u8 *buf, size_t len);
 
 
 /* write routines & macros */
@@ -157,8 +159,10 @@
  * <usermem> Set to 1 if <buf> is in userspace.
  * returns Number of bytes read, or -EFAULT.
  */
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+				       int offset, u8 __user *buf, size_t len);
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-				       int offset, u8* buf, size_t len, int usermem);
+				       int offset, u8 *buf, size_t len);
 
 /**
  * Dispose of a packet in the ring buffer.
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index f00a0eb..a577c0f 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -76,6 +76,7 @@
 	select DVB_DIB3000MC
 	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_DIB0070
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -107,6 +108,8 @@
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -120,6 +123,8 @@
 	depends on DVB_USB
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Currently, only devices with a product id of
@@ -241,3 +246,13 @@
 	  Say Y here to support the default remote control decoding for the
 	  Afatech AF9005 based receiver.
 
+config DVB_USB_ANYSEE
+	tristate "Anysee DVB-T/C USB2.0 support"
+	depends on DVB_USB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Anysee E30, Anysee E30 Plus or
+	  Anysee E30 C Plus DVB USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index c6511a6..44c11e4 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -61,6 +61,9 @@
 dvb-usb-af9005-remote-objs = af9005-remote.o
 obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 
+dvb-usb-anysee-objs = anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
new file mode 100644
index 0000000..adfd4fc
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -0,0 +1,553 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#include "anysee.h"
+#include "tda1002x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+
+/* debug */
+static int dvb_usb_anysee_debug;
+module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct mutex anysee_usb_mutex;
+
+static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
+	u8 *rbuf, u8 rlen)
+{
+	struct anysee_state *state = d->priv;
+	int act_len, ret;
+	u8 buf[64];
+
+	if (slen > sizeof(buf))
+		slen = sizeof(buf);
+	memcpy(&buf[0], sbuf, slen);
+	buf[60] = state->seq++;
+
+	if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
+		return -EAGAIN;
+
+	/* We need receive one message more after dvb_usb_generic_rw due
+	   to weird transaction flow, which is 1 x send + 2 x receive. */
+	ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
+
+	if (!ret) {
+		/* receive 2nd answer */
+		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+			d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
+			&act_len, 2000);
+		if (ret)
+			err("%s: recv bulk message failed: %d", __func__, ret);
+		else {
+			deb_xfer("<<< ");
+			debug_dump(buf, act_len, deb_xfer);
+		}
+	}
+
+	/* read request, copy returned data to return buf */
+	if (!ret && rbuf && rlen)
+		memcpy(rbuf, buf, rlen);
+
+	mutex_unlock(&anysee_usb_mutex);
+
+	return ret;
+}
+
+static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+	u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
+	int ret;
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
+	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
+	return ret;
+}
+
+static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+	u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
+	deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
+{
+	u8 buf[] = {CMD_GET_HW_INFO};
+	return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
+}
+
+static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
+	deb_info("%s: onoff:%02x\n", __func__, onoff);
+	return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
+	deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+	u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
+	deb_info("%s: onoff:%02x\n", __func__, onoff);
+	return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+	int ret;
+	/* LED light */
+	ret = anysee_led_ctrl(d, 0x01, 0x03);
+	if (ret)
+		return ret;
+
+	/* enable IR */
+	ret = anysee_ir_ctrl(d, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* I2C */
+static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret, inc, i = 0;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	while (i < num) {
+		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+			u8 buf[6];
+			buf[0] = CMD_I2C_READ;
+			buf[1] = msg[i].addr + 1;
+			buf[2] = msg[i].buf[0];
+			buf[3] = 0x00;
+			buf[4] = 0x00;
+			buf[5] = 0x01;
+			ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
+				msg[i+1].len);
+			inc = 2;
+		} else {
+			u8 buf[4+msg[i].len];
+			buf[0] = CMD_I2C_WRITE;
+			buf[1] = msg[i].addr;
+			buf[2] = msg[i].len;
+			buf[3] = 0x01;
+			memcpy(&buf[4], msg[i].buf, msg[i].len);
+			ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+			inc = 1;
+		}
+		if (ret)
+			return ret;
+
+		i += inc;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+
+	return i;
+}
+
+static u32 anysee_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm anysee_i2c_algo = {
+	.master_xfer   = anysee_master_xfer,
+	.functionality = anysee_i2c_func,
+};
+
+static int anysee_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+/* Callbacks for DVB USB */
+static struct tda10023_config anysee_tda10023_config = {
+	.demod_address = 0x1a,
+	.invert = 0,
+	.xtal   = 16000000,
+	.pll_m  = 11,
+	.pll_p  = 3,
+	.pll_n  = 1,
+	.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+	.deltaf = 0xfeeb,
+};
+
+static struct mt352_config anysee_mt352_config = {
+	.demod_address = 0x1e,
+	.demod_init    = anysee_mt352_demod_init,
+};
+
+static struct zl10353_config anysee_zl10353_config = {
+	.demod_address = 0x1e,
+	.parallel_ts = 1,
+};
+
+static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct anysee_state *state = adap->dev->priv;
+	u8 hw_info[3];
+	u8 io_d; /* IO port D */
+
+	/* check which hardware we have
+	   We must do this call two times to get reliable values (hw bug). */
+	ret = anysee_get_hw_info(adap->dev, hw_info);
+	if (ret)
+		return ret;
+	ret = anysee_get_hw_info(adap->dev, hw_info);
+	if (ret)
+		return ret;
+
+	/* Meaning of these info bytes are guessed. */
+	info("firmware version:%d.%d.%d hardware id:%d",
+		0, hw_info[1], hw_info[2], hw_info[0]);
+
+	ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
+	if (ret)
+		return ret;
+	deb_info("%s: IO port D:%02x\n", __func__, io_d);
+
+	/* Select demod using trial and error method. */
+
+	/* Try to attach demodulator in following order:
+	      model      demod     hw  firmware
+	   1. E30        MT352     02  0.2.1
+	   2. E30        ZL10353   02  0.2.1
+	   3. E30 Plus   ZL10353   06  0.1.0
+	   4. E30C Plus  TDA10023  0a  0.1.0    rev 0.2
+	   4. E30C Plus  TDA10023  0f  0.1.2    rev 0.4
+	*/
+
+	/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
+	adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+	adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* connect demod on IO port D for TDA10023 & ZL10353 */
+	ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
+	if (ret)
+		return ret;
+
+	/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+	adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_THOMSON_DTT7579;
+		return 0;
+	}
+
+	/* IO port E - E30C rev 0.4 board requires this */
+	ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
+	if (ret)
+		return ret;
+
+	/* Philips TDA10023 DVB-C demod */
+	adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
+			      &adap->dev->i2c_adap, 0x48);
+	if (adap->fe != NULL) {
+		state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
+		return 0;
+	}
+
+	/* return IO port D to init value for safe */
+	ret = anysee_write_reg(adap->dev, 0xb0, io_d);
+	if (ret)
+		return ret;
+
+	err("Unkown Anysee version: %02x %02x %02x. "\
+	    "Please report the <linux-dvb@linuxtv.org>.",
+	    hw_info[0], hw_info[1], hw_info[2]);
+
+	return -ENODEV;
+}
+
+static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct anysee_state *state = adap->dev->priv;
+	deb_info("%s: \n", __func__);
+
+	switch (state->tuner) {
+	case DVB_PLL_THOMSON_DTT7579:
+		/* Thomson dtt7579 (not sure) PLL inside of:
+		   Samsung DNOS404ZH102A NIM
+		   Samsung DNOS404ZH103A NIM */
+		dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+			   NULL, DVB_PLL_THOMSON_DTT7579);
+		break;
+	case DVB_PLL_SAMSUNG_DTOS403IH102A:
+		/* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
+		dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+			   &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+		break;
+	}
+
+	return 0;
+}
+
+static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 buf[] = {CMD_GET_IR_CODE};
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[2];
+	int i, ret;
+
+	ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+	if (ret)
+		return ret;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[0] &&
+		    keymap[i].data == ircode[1]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+			return 0;
+		}
+	}
+	return 0;
+}
+
+static struct dvb_usb_rc_key anysee_rc_keys[] = {
+	{ 0x01, 0x00, KEY_0 },
+	{ 0x01, 0x01, KEY_1 },
+	{ 0x01, 0x02, KEY_2 },
+	{ 0x01, 0x03, KEY_3 },
+	{ 0x01, 0x04, KEY_4 },
+	{ 0x01, 0x05, KEY_5 },
+	{ 0x01, 0x06, KEY_6 },
+	{ 0x01, 0x07, KEY_7 },
+	{ 0x01, 0x08, KEY_8 },
+	{ 0x01, 0x09, KEY_9 },
+	{ 0x01, 0x0a, KEY_POWER },
+	{ 0x01, 0x0b, KEY_DOCUMENTS },    /* * */
+	{ 0x01, 0x19, KEY_FAVORITES },
+	{ 0x01, 0x20, KEY_SLEEP },
+	{ 0x01, 0x21, KEY_MODE },         /* 4:3 / 16:9 select */
+	{ 0x01, 0x22, KEY_ZOOM },
+	{ 0x01, 0x47, KEY_TEXT },
+	{ 0x01, 0x16, KEY_TV },           /* TV / radio select */
+	{ 0x01, 0x1e, KEY_LANGUAGE },     /* Second Audio Program */
+	{ 0x01, 0x1a, KEY_SUBTITLE },
+	{ 0x01, 0x1b, KEY_CAMERA },       /* screenshot */
+	{ 0x01, 0x42, KEY_MUTE },
+	{ 0x01, 0x0e, KEY_MENU },
+	{ 0x01, 0x0f, KEY_EPG },
+	{ 0x01, 0x17, KEY_INFO },
+	{ 0x01, 0x10, KEY_EXIT },
+	{ 0x01, 0x13, KEY_VOLUMEUP },
+	{ 0x01, 0x12, KEY_VOLUMEDOWN },
+	{ 0x01, 0x11, KEY_CHANNELUP },
+	{ 0x01, 0x14, KEY_CHANNELDOWN },
+	{ 0x01, 0x15, KEY_OK },
+	{ 0x01, 0x1d, KEY_RED },
+	{ 0x01, 0x1f, KEY_GREEN },
+	{ 0x01, 0x1c, KEY_YELLOW },
+	{ 0x01, 0x44, KEY_BLUE },
+	{ 0x01, 0x0c, KEY_SHUFFLE },      /* snapshot */
+	{ 0x01, 0x48, KEY_STOP },
+	{ 0x01, 0x50, KEY_PLAY },
+	{ 0x01, 0x51, KEY_PAUSE },
+	{ 0x01, 0x49, KEY_RECORD },
+	{ 0x01, 0x18, KEY_PREVIOUS },     /* |<< */
+	{ 0x01, 0x0d, KEY_NEXT },         /* >>| */
+	{ 0x01, 0x24, KEY_PROG1 },        /* F1 */
+	{ 0x01, 0x25, KEY_PROG2 },        /* F2 */
+};
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_properties;
+
+static int anysee_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct usb_host_interface *alt;
+	int ret;
+
+	mutex_init(&anysee_usb_mutex);
+
+	/* There is one interface with two alternate settings.
+	   Alternate setting 0 is for bulk transfer.
+	   Alternate setting 1 is for isochronous transfer.
+	   We use bulk transfer (alternate setting 0). */
+	if (intf->num_altsetting < 1)
+		return -ENODEV;
+
+	ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
+		adapter_nr);
+	if (ret)
+		return ret;
+
+	alt = usb_altnum_to_altsetting(intf, 0);
+	if (alt == NULL) {
+		deb_info("%s: no alt found!\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+		alt->desc.bAlternateSetting);
+	if (ret)
+		return ret;
+
+	if (d)
+		ret = anysee_init(d);
+
+	return ret;
+}
+
+static struct usb_device_id anysee_table [] = {
+	{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
+	{ USB_DEVICE(USB_VID_AMT,     USB_PID_ANYSEE) },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, anysee_table);
+
+static struct dvb_usb_device_properties anysee_properties = {
+	.caps             = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct anysee_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = anysee_streaming_ctrl,
+			.frontend_attach  = anysee_frontend_attach,
+			.tuner_attach     = anysee_tuner_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 512,
+					}
+				}
+			},
+		}
+	},
+
+	.rc_key_map       = anysee_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(anysee_rc_keys),
+	.rc_query         = anysee_rc_query,
+	.rc_interval      = 200,  /* windows driver uses 500ms */
+
+	.i2c_algo         = &anysee_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "Anysee DVB USB2.0",
+			.cold_ids = {NULL},
+			.warm_ids = {&anysee_table[0],
+				     &anysee_table[1], NULL},
+		},
+	}
+};
+
+static struct usb_driver anysee_driver = {
+	.name       = "dvb_usb_anysee",
+	.probe      = anysee_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table   = anysee_table,
+};
+
+/* module stuff */
+static int __init anysee_module_init(void)
+{
+	int ret;
+
+	ret = usb_register(&anysee_driver);
+	if (ret)
+		err("%s: usb_register failed. Error number %d", __func__, ret);
+
+	return ret;
+}
+
+static void __exit anysee_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&anysee_driver);
+}
+
+module_init(anysee_module_init);
+module_exit(anysee_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
new file mode 100644
index 0000000..7ca01ff
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/anysee.h
@@ -0,0 +1,304 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#ifndef _DVB_USB_ANYSEE_H_
+#define _DVB_USB_ANYSEE_H_
+
+#define DVB_USB_LOG_PREFIX "anysee"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_anysee_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_anysee_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_anysee_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_anysee_debug, 0x20, args)
+
+enum cmd {
+	CMD_I2C_READ            = 0x33,
+	CMD_I2C_WRITE           = 0x31,
+	CMD_REG_READ            = 0xb0,
+	CMD_REG_WRITE           = 0xb1,
+	CMD_STREAMING_CTRL      = 0x12,
+	CMD_LED_AND_IR_CTRL     = 0x16,
+	CMD_GET_IR_CODE         = 0x41,
+	CMD_GET_HW_INFO         = 0x19,
+	CMD_SMARTCARD           = 0x34,
+};
+
+struct anysee_state {
+	u8 tuner;
+	u8 seq;
+};
+
+#endif
+
+/***************************************************************************
+ * USB API description (reverse engineered)
+ ***************************************************************************
+
+Transaction flow:
+=================
+BULK[00001] >>> REQUEST PACKET 64 bytes
+BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
+BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
+
+General reply packet(s) are always used if not own reply defined.
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
+============================================================================
+|    00 | reply data (if any) from previous transaction
+|       | Just same reply packet as returned during previous transaction.
+|       | Needed only if reply is missed in previous transaction.
+|       | Just skip normally.
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
+============================================================================
+|    00 | reply data (if any)
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C WRITE REQUEST PACKET
+============================================================================
+|    00 | 0x31 I2C write command
+----------------------------------------------------------------------------
+|    01 | i2c address
+----------------------------------------------------------------------------
+|    02 | data length
+|       | 0x02 (for typical I2C reg / val pair)
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-   | data
+----------------------------------------------------------------------------
+|   -59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C READ REQUEST PACKET
+============================================================================
+|    00 | 0x33 I2C read command
+----------------------------------------------------------------------------
+|    01 | i2c address + 1
+----------------------------------------------------------------------------
+|    02 | register
+----------------------------------------------------------------------------
+|    03 | 0x00
+----------------------------------------------------------------------------
+|    04 | 0x00
+----------------------------------------------------------------------------
+|    05 | 0x01
+----------------------------------------------------------------------------
+| 06-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
+============================================================================
+|    00 | 0xb1 register write command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+|    04 | value
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
+============================================================================
+|    00 | 0xb0 register read command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+|    03 | 0x01
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | LED CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x01 (LED)
+----------------------------------------------------------------------------
+|    03 | 0x00 blink
+|       | 0x01 lights continuously
+----------------------------------------------------------------------------
+|    04 | blink interval
+|       | 0x00 fastest (looks like LED lights continuously)
+|       | 0xff slowest
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | IR CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+|    01 | 0x02 (IR)
+----------------------------------------------------------------------------
+|    03 | 0x00 IR disabled
+|       | 0x01 IR enabled
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | STREAMING CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x12 streaming control command
+----------------------------------------------------------------------------
+|    01 | 0x00 streaming disabled
+|       | 0x01 streaming enabled
+----------------------------------------------------------------------------
+|    02 | 0x00
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REQUEST PACKET
+============================================================================
+|    00 | 0x41 remote control command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REPLY PACKET
+============================================================================
+|    00 | 0x00 code not received
+|       | 0x01 code received
+----------------------------------------------------------------------------
+|    01 | remote control code
+----------------------------------------------------------------------------
+| 02-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REQUEST PACKET
+============================================================================
+|    00 | 0x19 get hardware info command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REPLY PACKET
+============================================================================
+|    00 | hardware id
+----------------------------------------------------------------------------
+| 01-02 | firmware version
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | SMART CARD READER PACKET
+============================================================================
+|    00 | 0x34 smart card reader command
+----------------------------------------------------------------------------
+|    xx |
+----------------------------------------------------------------------------
+| xx-59 | don't care
+----------------------------------------------------------------------------
+|    60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+*/
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index 2ccb90f..eb34cc3 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -1,24 +1,31 @@
-/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
  *
  * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
  *
- *	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, version 2.
+ *    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.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "au6610.h"
-
 #include "zl10353.h"
 #include "qt1010.h"
 
 /* debug */
 static int dvb_usb_au6610_debug;
 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
@@ -42,9 +49,8 @@
 	}
 
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
-			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
-			      sizeof(usb_buf), AU6610_USB_TIMEOUT);
-
+			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
+			      usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
 	if (ret < 0)
 		return ret;
 
@@ -116,15 +122,6 @@
 };
 
 /* Callbacks for DVB USB */
-static int au6610_identify_state(struct usb_device *udev,
-				 struct dvb_usb_device_properties *props,
-				 struct dvb_usb_device_description **desc,
-				 int *cold)
-{
-	*cold = 0;
-	return 0;
-}
-
 static struct zl10353_config au6610_zl10353_config = {
 	.demod_address = 0x0f,
 	.no_tuner = 1,
@@ -133,12 +130,12 @@
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
-				   &adap->dev->i2c_adap)) != NULL) {
-		return 0;
-	}
+	adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -ENODEV;
 
-	return -EIO;
+	return 0;
 }
 
 static struct qt1010_config au6610_qt1010_config = {
@@ -171,7 +168,7 @@
 		alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
 
 		if (alt == NULL) {
-			deb_rc("no alt found!\n");
+			deb_info("%s: no alt found!\n", __func__);
 			return -ENODEV;
 		}
 		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
@@ -181,18 +178,19 @@
 	return ret;
 }
 
-
 static struct usb_device_id au6610_table [] = {
 	{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
 	{ }		/* Terminating entry */
 };
-MODULE_DEVICE_TABLE (usb, au6610_table);
+MODULE_DEVICE_TABLE(usb, au6610_table);
 
 static struct dvb_usb_device_properties au6610_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
 	.usb_ctrl = DEVICE_SPECIFIC,
-	.size_of_priv     = 0,
-	.identify_state   = au6610_identify_state,
+
+	.size_of_priv = 0,
+
 	.num_adapters = 1,
 	.adapter = {
 		{
@@ -206,20 +204,22 @@
 				.u = {
 					.isoc = {
 						.framesperurb = 40,
-						.framesize = 942,   /* maximum packet size */
-						.interval = 1.25,   /* 125 us */
+						.framesize = 942,
+						.interval = 1,
 					}
 				}
 			},
 		}
 	},
+
 	.i2c_algo = &au6610_i2c_algo,
+
 	.num_device_descs = 1,
 	.devices = {
 		{
-			"Sigmatek DVB-110 DVB-T USB2.0",
-			{ &au6610_table[0], NULL },
-			{ NULL },
+			.name = "Sigmatek DVB-110 DVB-T USB2.0",
+			.cold_ids = {NULL},
+			.warm_ids = {&au6610_table[0], NULL},
 		},
 	}
 };
@@ -236,12 +236,11 @@
 {
 	int ret;
 
-	if ((ret = usb_register(&au6610_driver))) {
+	ret = usb_register(&au6610_driver);
+	if (ret)
 		err("usb_register failed. Error number %d", ret);
-		return ret;
-	}
 
-	return 0;
+	return ret;
 }
 
 static void __exit au6610_module_exit(void)
@@ -250,10 +249,10 @@
 	usb_deregister(&au6610_driver);
 }
 
-module_init (au6610_module_init);
-module_exit (au6610_module_exit);
+module_init(au6610_module_init);
+module_exit(au6610_module_exit);
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
index 4161b05..7849abe 100644
--- a/drivers/media/dvb/dvb-usb/au6610.h
+++ b/drivers/media/dvb/dvb-usb/au6610.h
@@ -1,10 +1,30 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 _DVB_USB_AU6610_H_
 #define _DVB_USB_AU6610_H_
 
 #define DVB_USB_LOG_PREFIX "au6610"
 #include "dvb-usb.h"
 
-#define deb_rc(args...)   dprintk(dvb_usb_au6610_debug,0x01,args)
+#define deb_info(args...)   dprintk(dvb_usb_au6610_debug, 0x01, args)
 
 #define AU6610_REQ_I2C_WRITE	0x14
 #define AU6610_REQ_I2C_READ	0x13
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 0286156..578afce 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -35,6 +35,7 @@
 #include "zl10353.h"
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
+#include "mxl5005s.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -43,9 +44,8 @@
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-				dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug, 0x03, args)
+#define deb_i2c(args...)    dprintk(dvb_usb_cxusb_debug, 0x02, args)
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -202,6 +202,46 @@
 		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
 }
 
+static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	if (!onoff)
+		return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
+	if (d->state == DVB_USB_STATE_INIT &&
+	    usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+	do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
+		   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+	if (!ret) {
+		/* FIXME: We don't know why, but we need to configure the
+		 * lgdt3303 with the register settings below on resume */
+		int i;
+		u8 buf, bufs[] = {
+			0x0e, 0x2, 0x00, 0x7f,
+			0x0e, 0x2, 0x02, 0xfe,
+			0x0e, 0x2, 0x02, 0x01,
+			0x0e, 0x2, 0x00, 0x03,
+			0x0e, 0x2, 0x0d, 0x40,
+			0x0e, 0x2, 0x0e, 0x87,
+			0x0e, 0x2, 0x0f, 0x8e,
+			0x0e, 0x2, 0x10, 0x01,
+			0x0e, 0x2, 0x14, 0xd7,
+			0x0e, 0x2, 0x47, 0x88,
+		};
+		msleep(20);
+		for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
+			ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
+					     bufs+i, 4, &buf, 1);
+			if (ret)
+				break;
+			if (buf != 0x8)
+				return -EREMOTEIO;
+		}
+	}
+	return ret;
+}
+
 static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	u8 b = 0;
@@ -233,6 +273,16 @@
 	return 0;
 }
 
+static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff)
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
+	else
+		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
+			       NULL, 0, NULL, 0);
+	return 0;
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -423,6 +473,12 @@
 	.demod_chip    = LGDT3303,
 };
 
+static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
+	.demod_address       = 0x0e,
+	.demod_chip          = LGDT3303,
+	.clock_polarity_flip = 2,
+};
+
 static struct mt352_config cxusb_dee1601_config = {
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_dee1601_demod_init,
@@ -453,6 +509,24 @@
 	.demod_init = cxusb_mt352_demod_init,
 };
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config aver_a868r_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 6000000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -533,6 +607,13 @@
 	return 0;
 }
 
+static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(mxl5005s_attach, adap->fe,
+		   &adap->dev->i2c_adap, &aver_a868r_tuner);
+	return 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	u8 b;
@@ -562,6 +643,16 @@
 	return -EIO;
 }
 
+static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
+			      &adap->dev->i2c_adap);
+	if (adap->fe != NULL)
+		return 0;
+
+	return -EIO;
+}
+
 static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	/* used in both lgz201 and th7579 */
@@ -736,6 +827,7 @@
 static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -756,7 +848,10 @@
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf,
 				&cxusb_bluebird_nano2_needsfirmware_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0)
 		return 0;
 
 	return -EINVAL;
@@ -779,6 +874,7 @@
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
+	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1182,6 +1278,48 @@
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_aver_streaming_ctrl,
+			.frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
+			.tuner_attach     = cxusb_mxl5003s_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x04,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+
+		},
+	},
+	.power_ctrl       = cxusb_aver_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "AVerMedia AVerTVHD Volar (A868R)",
+			{ NULL },
+			{ &cxusb_table[16], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
index 4768a2c..1a51eaf 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -20,6 +20,9 @@
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_OFF 0x37
 
+#define CMD_AVER_STREAM_ON  0x18
+#define CMD_AVER_STREAM_OFF 0x19
+
 #define CMD_GET_IR_CODE   0x47
 
 #define CMD_ANALOG        0x50
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index c4d40fe..3dd20bf 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1117,6 +1117,7 @@
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
 	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1372,7 +1373,7 @@
 			}
 		},
 
-		.num_device_descs = 2,
+		.num_device_descs = 3,
 		.devices = {
 			{   "DiBcom STK7070PD reference design",
 				{ &dib0700_usb_id_table[17], NULL },
@@ -1381,6 +1382,10 @@
 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
 				{ &dib0700_usb_id_table[18], NULL },
 				{ NULL },
+			},
+			{   "Hauppauge Nova-TD Stick (52009)",
+				{ &dib0700_usb_id_table[35], NULL },
+				{ NULL },
 			}
 		}
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 23428cd..326f760 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -20,11 +20,7 @@
 	}
 
 	strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
 	d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
 	d->i2c_adap.algo      = d->props.i2c_algo;
 	d->i2c_adap.algo_data = NULL;
 	d->i2c_adap.dev.parent = &d->udev->dev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 34245d1..e5238b3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -14,6 +14,7 @@
 #define USB_VID_AFATECH				0x15a4
 #define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALINK				0x05e3
+#define USB_VID_AMT				0x1c73
 #define USB_VID_ANCHOR				0x0547
 #define USB_VID_ANSONIC				0x10b9
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
@@ -57,6 +58,7 @@
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_VID_ALINK_DTU				0xf170
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
+#define USB_PID_ANYSEE					0x861f
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -132,9 +134,15 @@
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
 #define USB_PID_HAUPPAUGE_MYTV_T			0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009		0x5200
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_AVERMEDIA_VOLAR_A868R			0xa868
+#define USB_PID_AVERMEDIA_MCE_USB_M038			0x1228
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R	0x0039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC	0x1039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT	0x2039
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index 037f7ff..6f596ed 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -1,8 +1,8 @@
 /* DVB USB compliant linux driver for GL861 USB2.0 devices.
  *
  *	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, version 2.
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation, version 2.
  *
  * see Documentation/dvb/README.dvb-usb for more information
  */
@@ -13,9 +13,9 @@
 
 /* debug */
 static int dvb_usb_gl861_debug;
-module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
+	DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
@@ -70,7 +70,7 @@
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
 			if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
-					  msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+				msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
 				break;
 			i++;
 		} else
@@ -102,12 +102,13 @@
 
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
-				   &adap->dev->i2c_adap)) != NULL) {
-		return 0;
-	}
 
-	return -EIO;
+	adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
 }
 
 static struct qt1010_config gl861_qt1010_config = {
@@ -156,7 +157,7 @@
 		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 		{ }		/* Terminating entry */
 };
-MODULE_DEVICE_TABLE (usb, gl861_table);
+MODULE_DEVICE_TABLE(usb, gl861_table);
 
 static struct dvb_usb_device_properties gl861_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -180,7 +181,7 @@
 				}
 			}
 		},
-	}},
+	} },
 	.i2c_algo         = &gl861_i2c_algo,
 
 	.num_device_descs = 2,
@@ -210,12 +211,11 @@
 {
 	int ret;
 
-	if ((ret = usb_register(&gl861_driver))) {
+	ret = usb_register(&gl861_driver);
+	if (ret)
 		err("usb_register failed. Error number %d", ret);
-		return ret;
-	}
 
-	return 0;
+	return ret;
 }
 
 static void __exit gl861_module_exit(void)
@@ -224,8 +224,8 @@
 	usb_deregister(&gl861_driver);
 }
 
-module_init (gl861_module_init);
-module_exit (gl861_module_exit);
+module_init(gl861_module_init);
+module_exit(gl861_module_exit);
 
 MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
 MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
index 72a51af..c54855e 100644
--- a/drivers/media/dvb/dvb-usb/gl861.h
+++ b/drivers/media/dvb/dvb-usb/gl861.h
@@ -4,7 +4,7 @@
 #define DVB_USB_LOG_PREFIX "gl861"
 #include "dvb-usb.h"
 
-#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug,0x01,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug, 0x01, args)
 
 #define GL861_WRITE		0x40
 #define GL861_READ		0xc0
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 03900d2..f7b7165 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "au8522.h"
 
 struct au8522_state {
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index a054894..ea05815 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -343,6 +343,52 @@
 	}
 };
 
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = {
+		.addr = priv->pll_i2c_address,
+		.flags = 0,
+		.buf = buf,
+		.len = 4
+	};
+	int result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	result = i2c_transfer(priv->i2c, &msg, 1);
+	if (result != 1)
+		printk(KERN_ERR "%s: i2c_transfer failed:%d",
+			__func__, result);
+
+	buf[2] = 0x9e;
+	buf[3] = 0x90;
+
+	return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+	.name   = "Samsung DTOS403IH102A",
+	.min    =  44250000,
+	.max    = 858000000,
+	.iffreq =  36125000,
+	.count  = 8,
+	.set    = samsung_dtos403ih102a_set,
+	.entries = {
+		{ 135000000, 62500, 0xbe, 0x01 },
+		{ 177000000, 62500, 0xf6, 0x01 },
+		{ 370000000, 62500, 0xbe, 0x02 },
+		{ 450000000, 62500, 0xf6, 0x02 },
+		{ 466000000, 62500, 0xfe, 0x02 },
+		{ 538000000, 62500, 0xbe, 0x08 },
+		{ 826000000, 62500, 0xf6, 0x08 },
+		{ 999999999, 62500, 0xfe, 0x08 },
+	}
+};
+
 /* ----------------------------------------------------------- */
 
 static struct dvb_pll_desc *pll_list[] = {
@@ -360,6 +406,7 @@
 	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
 	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
 	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+	[DVB_PLL_SAMSUNG_DTOS403IH102A]  = &dvb_pll_samsung_dtos403ih102a,
 };
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 872ca29..05239f5 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -22,6 +22,7 @@
 #define DVB_PLL_SAMSUNG_TBMV           11
 #define DVB_PLL_PHILIPS_SD1878_TDA8261 12
 #define DVB_PLL_OPERA1                 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A  14
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index f0195c8..056387b 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -226,11 +226,16 @@
 		0x4c, 0x14
 	};
 
-	static u8 flip_lgdt3303_init_data[] = {
+	static u8 flip_1_lgdt3303_init_data[] = {
 		0x4c, 0x14,
 		0x87, 0xf3
 	};
 
+	static u8 flip_2_lgdt3303_init_data[] = {
+		0x4c, 0x14,
+		0x87, 0xda
+	};
+
 	struct lgdt330x_state* state = fe->demodulator_priv;
 	char  *chip_name;
 	int    err;
@@ -243,10 +248,19 @@
 		break;
 	case LGDT3303:
 		chip_name = "LGDT3303";
-		if (state->config->clock_polarity_flip) {
-			err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
-						    sizeof(flip_lgdt3303_init_data));
-		} else {
+		switch (state->config->clock_polarity_flip) {
+		case 2:
+			err = i2c_write_demod_bytes(state,
+					flip_2_lgdt3303_init_data,
+					sizeof(flip_2_lgdt3303_init_data));
+			break;
+		case 1:
+			err = i2c_write_demod_bytes(state,
+					flip_1_lgdt3303_init_data,
+					sizeof(flip_1_lgdt3303_init_data));
+			break;
+		case 0:
+		default:
 			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
 						    sizeof(lgdt3303_init_data));
 		}
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index b999ec4..5ddb2dc 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "s5h1409.h"
 
 struct s5h1409_state {
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index eb5bfc9..cff360c 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "s5h1411.h"
 
 struct s5h1411_state {
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index c6ff5b8..a3c34ee 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -38,75 +38,29 @@
 #include "dvb_frontend.h"
 #include "tda1002x.h"
 
+#define REG0_INIT_VAL 0x23
 
 struct tda10023_state {
 	struct i2c_adapter* i2c;
 	/* configuration settings */
-	const struct tda1002x_config* config;
+	const struct tda10023_config *config;
 	struct dvb_frontend frontend;
 
 	u8 pwm;
 	u8 reg0;
-};
 
+	/* clock settings */
+	u32 xtal;
+	u8 pll_m;
+	u8 pll_p;
+	u8 pll_n;
+	u32 sysclk;
+};
 
 #define dprintk(x...)
 
 static int verbose;
 
-#define XTAL   28920000UL
-#define PLL_M  8UL
-#define PLL_P  4UL
-#define PLL_N  1UL
-#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P))  // -> 57840000
-
-static u8 tda10023_inittab[]={
-	// reg mask val
-	0x2a,0xff,0x02,  // PLL3, Bypass, Power Down
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x2a,0xff,0x03,  // PLL3, Bypass, Power Down
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x28,0xff,PLL_M-1,  // PLL1 M=8
-	0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1),  // PLL2
-	0x00,0xff,0x23,  // GPR FSAMPLING=1
-	0x2a,0xff,0x08,  // PLL3 PSACLK=1
-	0xff,0x64,0x00,  // Sleep 100ms
-	0x1f,0xff,0x00,  // RESET
-	0xff,0x64,0x00,  // Sleep 100ms
-	0xe6,0x0c,0x04,  // RSCFG_IND
-	0x10,0xc0,0x80,  // DECDVBCFG1 PBER=1
-
-	0x0e,0xff,0x82,  // GAIN1
-	0x03,0x08,0x08,  // CLKCONF DYN=1
-	0x2e,0xbf,0x30,  // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
-	0x01,0xff,0x30,  // AGCREF
-	0x1e,0x84,0x84,  // CONTROL SACLK_ON=1
-	0x1b,0xff,0xc8,  // ADC TWOS=1
-	0x3b,0xff,0xff,  // IFMAX
-	0x3c,0xff,0x00,  // IFMIN
-	0x34,0xff,0x00,  // PWMREF
-	0x35,0xff,0xff,  // TUNMAX
-	0x36,0xff,0x00,  // TUNMIN
-	0x06,0xff,0x7f,  // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1    // 0x77
-	0x1c,0x30,0x30,  // EQCONF2 STEPALGO=SGNALGO=1
-	0x37,0xff,0xf6,  // DELTAF_LSB
-	0x38,0xff,0xff,  // DELTAF_MSB
-	0x02,0xff,0x93,  // AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3
-	0x2d,0xff,0xf6,  // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
-	0x04,0x10,0x00,   // SWRAMP=1
-	0x12,0xff,0xa1,  // INTP1 POCLKP=1 FEL=1 MFS=0
-	0x2b,0x01,0xa1,  // INTS1
-	0x20,0xff,0x04,  // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
-	0x2c,0xff,0x0d,  // INTP/S TRIP=0 TRIS=0
-	0xc4,0xff,0x00,
-	0xc3,0x30,0x00,
-	0xb5,0xff,0x19,  // ERAGC_THD
-	0x00,0x03,0x01,  // GPR, CLBS soft reset
-	0x00,0x03,0x03,  // GPR, CLBS soft reset
-	0xff,0x64,0x00,  // Sleep 100ms
-	0xff,0xff,0xff
-};
-
 static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
 {
 	u8 b0 [] = { reg };
@@ -219,30 +173,34 @@
 	s16 SFIL=0;
 	u16 NDEC = 0;
 
-	if (sr < (u32)(SYSCLK/98.40)) {
+	/* avoid floating point operations multiplying syscloc and divider
+	   by 10 */
+	u32 sysclk_x_10 = state->sysclk * 10;
+
+	if (sr < (u32)(sysclk_x_10/984)) {
 		NDEC=3;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/64.0)) {
+	} else if (sr < (u32)(sysclk_x_10/640)) {
 		NDEC=3;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/49.2)) {
+	} else if (sr < (u32)(sysclk_x_10/492)) {
 		NDEC=2;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/32.0)) {
+	} else if (sr < (u32)(sysclk_x_10/320)) {
 		NDEC=2;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/24.6)) {
+	} else if (sr < (u32)(sysclk_x_10/246)) {
 		NDEC=1;
 		SFIL=1;
-	} else if (sr<(u32)(SYSCLK/16.0)) {
+	} else if (sr < (u32)(sysclk_x_10/160)) {
 		NDEC=1;
 		SFIL=0;
-	} else if (sr<(u32)(SYSCLK/12.3)) {
+	} else if (sr < (u32)(sysclk_x_10/123)) {
 		NDEC=0;
 		SFIL=1;
 	}
 
-	BDRI=SYSCLK*16;
+	BDRI = (state->sysclk)*16;
 	BDRI>>=NDEC;
 	BDRI +=sr/2;
 	BDRI /=sr;
@@ -255,11 +213,12 @@
 
 		BDRX=1<<(24+NDEC);
 		BDRX*=sr;
-		do_div(BDRX,SYSCLK); 	// BDRX/=SYSCLK;
+		do_div(BDRX, state->sysclk); 	/* BDRX/=SYSCLK; */
 
 		BDR=(s32)BDRX;
 	}
-//	printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+	dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
+		sr, BDR, BDRI, NDEC);
 	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
 	tda10023_writereg (state, 0x0a, BDR&255);
 	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
@@ -272,8 +231,67 @@
 static int tda10023_init (struct dvb_frontend *fe)
 {
 	struct tda10023_state* state = fe->demodulator_priv;
+	u8 tda10023_inittab[] = {
+/*        reg  mask val */
+/* 000 */ 0x2a, 0xff, 0x02,  /* PLL3, Bypass, Power Down */
+/* 003 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 006 */ 0x2a, 0xff, 0x03,  /* PLL3, Bypass, Power Down */
+/* 009 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+			   /* PLL1 */
+/* 012 */ 0x28, 0xff, (state->pll_m-1),
+			   /* PLL2 */
+/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
+			   /* GPR FSAMPLING=1 */
+/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
+/* 021 */ 0x2a, 0xff, 0x08,  /* PLL3 PSACLK=1 */
+/* 024 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 027 */ 0x1f, 0xff, 0x00,  /* RESET */
+/* 030 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 033 */ 0xe6, 0x0c, 0x04,  /* RSCFG_IND */
+/* 036 */ 0x10, 0xc0, 0x80,  /* DECDVBCFG1 PBER=1 */
 
-	dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+/* 039 */ 0x0e, 0xff, 0x82,  /* GAIN1 */
+/* 042 */ 0x03, 0x08, 0x08,  /* CLKCONF DYN=1 */
+/* 045 */ 0x2e, 0xbf, 0x30,  /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
+				       PPWMTUN=0 PPWMIF=0 */
+/* 048 */ 0x01, 0xff, 0x30,  /* AGCREF */
+/* 051 */ 0x1e, 0x84, 0x84,  /* CONTROL SACLK_ON=1 */
+/* 054 */ 0x1b, 0xff, 0xc8,  /* ADC TWOS=1 */
+/* 057 */ 0x3b, 0xff, 0xff,  /* IFMAX */
+/* 060 */ 0x3c, 0xff, 0x00,  /* IFMIN */
+/* 063 */ 0x34, 0xff, 0x00,  /* PWMREF */
+/* 066 */ 0x35, 0xff, 0xff,  /* TUNMAX */
+/* 069 */ 0x36, 0xff, 0x00,  /* TUNMIN */
+/* 072 */ 0x06, 0xff, 0x7f,  /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
+/* 075 */ 0x1c, 0x30, 0x30,  /* EQCONF2 STEPALGO=SGNALGO=1 */
+/* 078 */ 0x37, 0xff, 0xf6,  /* DELTAF_LSB */
+/* 081 */ 0x38, 0xff, 0xff,  /* DELTAF_MSB */
+/* 084 */ 0x02, 0xff, 0x93,  /* AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3 */
+/* 087 */ 0x2d, 0xff, 0xf6,  /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
+/* 090 */ 0x04, 0x10, 0x00,  /* SWRAMP=1 */
+/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
+				INTP1 POCLKP=1 FEL=1 MFS=0 */
+/* 096 */ 0x2b, 0x01, 0xa1,  /* INTS1 */
+/* 099 */ 0x20, 0xff, 0x04,  /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
+/* 102 */ 0x2c, 0xff, 0x0d,  /* INTP/S TRIP=0 TRIS=0 */
+/* 105 */ 0xc4, 0xff, 0x00,
+/* 108 */ 0xc3, 0x30, 0x00,
+/* 111 */ 0xb5, 0xff, 0x19,  /* ERAGC_THD */
+/* 114 */ 0x00, 0x03, 0x01,  /* GPR, CLBS soft reset */
+/* 117 */ 0x00, 0x03, 0x03,  /* GPR, CLBS soft reset */
+/* 120 */ 0xff, 0x64, 0x00,  /* Sleep 100ms */
+/* 123 */ 0xff, 0xff, 0xff
+};
+	dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+	/* override default values if set in config */
+	if (state->config->deltaf) {
+		tda10023_inittab[80] = (state->config->deltaf & 0xff);
+		tda10023_inittab[83] = (state->config->deltaf >> 8);
+	}
+
+	if (state->config->output_mode)
+		tda10023_inittab[95] = state->config->output_mode;
 
 	tda10023_writetab(state, tda10023_inittab);
 
@@ -460,12 +478,11 @@
 
 static struct dvb_frontend_ops tda10023_ops;
 
-struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-				     struct i2c_adapter* i2c,
+struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
+				     struct i2c_adapter *i2c,
 				     u8 pwm)
 {
 	struct tda10023_state* state = NULL;
-	int i;
 
 	/* allocate memory for the internal state */
 	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
@@ -474,22 +491,40 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
-	state->pwm = pwm;
-	for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
-		if (tda10023_inittab[i] == 0x00) {
-			state->reg0 = tda10023_inittab[i+2];
-			break;
-		}
-	}
 
-	// Wakeup if in standby
+	/* wakeup if in standby */
 	tda10023_writereg (state, 0x00, 0x33);
 	/* check if the demod is there */
 	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
 
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->pwm = pwm;
+	state->reg0 = REG0_INIT_VAL;
+	if (state->config->xtal) {
+		state->xtal  = state->config->xtal;
+		state->pll_m = state->config->pll_m;
+		state->pll_p = state->config->pll_p;
+		state->pll_n = state->config->pll_n;
+	} else {
+		/* set default values if not defined in config */
+		state->xtal  = 28920000;
+		state->pll_m = 8;
+		state->pll_p = 4;
+		state->pll_n = 1;
+	}
+
+	/* calc sysclk */
+	state->sysclk = (state->xtal * state->pll_m / \
+			(state->pll_n * state->pll_p));
+
+	state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
+	state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
+
+	dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
+		__func__, state->xtal, state->pll_m, state->pll_p,
+		state->pll_n);
+
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -504,10 +539,10 @@
 		.name = "Philips TDA10023 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 47000000,
+		.frequency_min =  47000000,
 		.frequency_max = 862000000,
-		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
-		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
+		.symbol_rate_min = 0,  /* set in tda10023_attach */
+		.symbol_rate_max = 0,  /* set in tda10023_attach */
 		.caps = 0x400 | //FE_CAN_QAM_4
 			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
 			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
index 1bcc0d4..04d1941 100644
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ b/drivers/media/dvb/frontends/tda1002x.h
@@ -26,13 +26,37 @@
 
 #include <linux/dvb/frontend.h>
 
-struct tda1002x_config
-{
+struct tda1002x_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
 	u8 invert;
 };
 
+enum tda10023_output_mode {
+	TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
+	TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
+	TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
+	TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
+};
+
+struct tda10023_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 invert;
+
+	/* clock settings */
+	u32 xtal; /* defaults: 28920000 */
+	u8 pll_m; /* defaults: 8 */
+	u8 pll_p; /* defaults: 4 */
+	u8 pll_n; /* defaults: 1 */
+
+	/* MPEG2 TS output mode */
+	u8 output_mode;
+
+	/* input freq offset + baseband conversion type */
+	u16 deltaf;
+};
+
 #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
 extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 					    struct i2c_adapter* i2c, u8 pwm);
@@ -45,12 +69,15 @@
 }
 #endif // CONFIG_DVB_TDA10021
 
-#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm);
+#if defined(CONFIG_DVB_TDA10023) || \
+	(defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm);
 #else
-static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
-					    struct i2c_adapter* i2c, u8 pwm)
+static inline struct dvb_frontend *tda10023_attach(
+	const struct tda10023_config *config,
+	struct i2c_adapter *i2c, u8 pwm)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 960ed57..1360403 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -234,7 +234,7 @@
 
 static void pluto_set_dma_addr(struct pluto *pluto)
 {
-	pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+	pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
 }
 
 static int __devinit pluto_dma_map(struct pluto *pluto)
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
new file mode 100644
index 0000000..dd863f2
--- /dev/null
+++ b/drivers/media/dvb/siano/Kconfig
@@ -0,0 +1,26 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config DVB_SIANO_SMS1XXX
+	tristate "Siano SMS1XXX USB dongle support"
+	depends on DVB_CORE && USB
+	---help---
+	  Choose Y here if you have a USB dongle with a SMS1XXX chipset.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sms1xxx.
+
+config DVB_SIANO_SMS1XXX_SMS_IDS
+	bool "Enable support for Siano Mobile Silicon default USB IDs"
+	depends on DVB_SIANO_SMS1XXX
+	default y
+	---help---
+	  Choose Y here if you have a USB dongle with a SMS1XXX chipset
+	  that uses Siano Mobile Silicon's default usb vid:pid.
+
+	  Choose N here if you would prefer to use Siano's external driver.
+
+	  Further documentation on this driver can be found on the WWW at
+	  <http://www.siano-ms.com/>.
+
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
new file mode 100644
index 0000000..ee0737a
--- /dev/null
+++ b/drivers/media/dvb/siano/Makefile
@@ -0,0 +1,8 @@
+sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
+
+obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
new file mode 100644
index 0000000..e7a8ac0
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -0,0 +1,102 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sms-cards.h"
+
+struct usb_device_id smsusb_id_table[] = {
+#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
+	{ USB_DEVICE(0x187f, 0x0010),
+		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+	{ USB_DEVICE(0x187f, 0x0100),
+		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+	{ USB_DEVICE(0x187f, 0x0200),
+		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+	{ USB_DEVICE(0x187f, 0x0201),
+		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+	{ USB_DEVICE(0x187f, 0x0300),
+		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+#endif
+	{ USB_DEVICE(0x2040, 0x1700),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+	{ USB_DEVICE(0x2040, 0x1800),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+	{ USB_DEVICE(0x2040, 0x1801),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+	{ USB_DEVICE(0x2040, 0x5500),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0x5580),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ USB_DEVICE(0x2040, 0x5590),
+		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+
+static struct sms_board sms_boards[] = {
+	[SMS_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+	},
+	[SMS1XXX_BOARD_SIANO_STELLAR] = {
+		.name	= "Siano Stellar Digital Receiver",
+		.type	= SMS_STELLAR,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
+		.name	= "Siano Nova A Digital Receiver",
+		.type	= SMS_NOVA_A0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
+		.name	= "Siano Nova B Digital Receiver",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_SIANO_VEGA] = {
+		.name	= "Siano Vega Digital Receiver",
+		.type	= SMS_VEGA,
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
+		.name	= "Hauppauge Catamount",
+		.type	= SMS_STELLAR,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
+		.name	= "Hauppauge Okemo-A",
+		.type	= SMS_NOVA_A0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
+		.name	= "Hauppauge Okemo-B",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+	},
+	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
+		.name	= "Hauppauge WinTV-Nova-T-MiniStick",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
+	},
+};
+
+struct sms_board *sms_get_board(int id)
+{
+	BUG_ON(id >= ARRAY_SIZE(sms_boards));
+
+	return &sms_boards[id];
+}
+
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
new file mode 100644
index 0000000..83b39bc
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -0,0 +1,45 @@
+/*
+ *  Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  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 __SMS_CARDS_H__
+#define __SMS_CARDS_H__
+
+#include <linux/usb.h>
+#include "smscoreapi.h"
+
+#define SMS_BOARD_UNKNOWN 0
+#define SMS1XXX_BOARD_SIANO_STELLAR 1
+#define SMS1XXX_BOARD_SIANO_NOVA_A  2
+#define SMS1XXX_BOARD_SIANO_NOVA_B  3
+#define SMS1XXX_BOARD_SIANO_VEGA    4
+#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
+#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+
+struct sms_board {
+	enum sms_device_type_st type;
+	char *name, *fw[DEVICE_MODE_MAX];
+};
+
+struct sms_board *sms_get_board(int id);
+
+extern struct usb_device_id smsusb_id_table[];
+
+#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
new file mode 100644
index 0000000..b4b8ed7
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -0,0 +1,1251 @@
+/*
+ *  Siano core API module
+ *
+ *  This file contains implementation for the interface to sms core component
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+int sms_debug;
+module_param_named(debug, sms_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+struct smscore_device_notifyee_t {
+	struct list_head entry;
+	hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+	struct list_head entry;
+	int		id;
+	int		data_type;
+};
+
+struct smscore_client_t {
+	struct list_head entry;
+	struct smscore_device_t *coredev;
+	void			*context;
+	struct list_head 	idlist;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+};
+
+struct smscore_device_t {
+	struct list_head entry;
+
+	struct list_head clients;
+	struct list_head subclients;
+	spinlock_t		clientslock;
+
+	struct list_head buffers;
+	spinlock_t		bufferslock;
+	int				num_buffers;
+
+	void			*common_buffer;
+	int				common_buffer_size;
+	dma_addr_t		common_buffer_phys;
+
+	void			*context;
+	struct device	*device;
+
+	char			devpath[32];
+	unsigned long	device_flags;
+
+	setmode_t		setmode_handler;
+	detectmode_t	detectmode_handler;
+	sendrequest_t	sendrequest_handler;
+	preload_t		preload_handler;
+	postload_t		postload_handler;
+
+	int				mode, modes_supported;
+
+	struct completion version_ex_done, data_download_done, trigger_done;
+	struct completion init_device_done, reload_start_done, resume_done;
+
+	int board_id;
+};
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+	core->board_id = id;
+}
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+	return core->board_id;
+}
+
+struct smscore_registry_entry_t {
+	struct list_head entry;
+	char			devpath[32];
+	int				mode;
+	enum sms_device_type_st	type;
+};
+
+struct list_head g_smscore_notifyees;
+struct list_head g_smscore_devices;
+struct mutex g_smscore_deviceslock;
+
+struct list_head g_smscore_registry;
+struct mutex g_smscore_registrylock;
+
+static int default_mode = 4;
+
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+	struct list_head *next;
+
+	kmutex_lock(&g_smscore_registrylock);
+	for (next = g_smscore_registry.next;
+	     next != &g_smscore_registry;
+	     next = next->next) {
+		entry = (struct smscore_registry_entry_t *) next;
+		if (!strcmp(entry->devpath, devpath)) {
+			kmutex_unlock(&g_smscore_registrylock);
+			return entry;
+		}
+	}
+	entry = (struct smscore_registry_entry_t *)
+			kmalloc(sizeof(struct smscore_registry_entry_t),
+				GFP_KERNEL);
+	if (entry) {
+		entry->mode = default_mode;
+		strcpy(entry->devpath, devpath);
+		list_add(&entry->entry, &g_smscore_registry);
+	} else
+		sms_err("failed to create smscore_registry.");
+	kmutex_unlock(&g_smscore_registrylock);
+	return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->mode;
+	else
+		sms_err("No registry found.");
+
+	return default_mode;
+}
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		return entry->type;
+	else
+		sms_err("No registry found.");
+
+	return -1;
+}
+
+void smscore_registry_setmode(char *devpath, int mode)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->mode = mode;
+	else
+		sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+				     enum sms_device_type_st type)
+{
+	struct smscore_registry_entry_t *entry;
+
+	entry = smscore_find_registry(devpath);
+	if (entry)
+		entry->type = type;
+	else
+		sms_err("No registry found.");
+}
+
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+			    spinlock_t *lock)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+
+	list_add(new, head);
+
+	spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+	struct smscore_device_notifyee_t *notifyee;
+	struct list_head *next, *first;
+	int rc = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+			   GFP_KERNEL);
+	if (notifyee) {
+		/* now notify callback about existing devices */
+		first = &g_smscore_devices;
+		for (next = first->next;
+		     next != first && !rc;
+		     next = next->next) {
+			struct smscore_device_t *coredev =
+				(struct smscore_device_t *) next;
+			rc = hotplug(coredev, coredev->device, 1);
+		}
+
+		if (rc >= 0) {
+			notifyee->hotplug = hotplug;
+			list_add(&notifyee->entry, &g_smscore_notifyees);
+		} else
+			kfree(notifyee);
+	} else
+		rc = -ENOMEM;
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+	struct list_head *next, *first;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	first = &g_smscore_notifyees;
+
+	for (next = first->next; next != first;) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *) next;
+		next = next->next;
+
+		if (notifyee->hotplug == hotplug) {
+			list_del(&notifyee->entry);
+			kfree(notifyee);
+		}
+	}
+
+	kmutex_unlock(&g_smscore_deviceslock);
+}
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+	struct smscore_client_t *client;
+
+	/* the client must call smscore_unregister_client from remove handler */
+	while (!list_empty(&coredev->clients)) {
+		client = (struct smscore_client_t *) coredev->clients.next;
+		client->onremove_handler(client->context);
+	}
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+				    struct device *device, int arrival)
+{
+	struct list_head *next, *first;
+	int rc = 0;
+
+	/* note: must be called under g_deviceslock */
+
+	first = &g_smscore_notifyees;
+
+	for (next = first->next; next != first; next = next->next) {
+		rc = ((struct smscore_device_notifyee_t *) next)->
+				hotplug(coredev, device, arrival);
+		if (rc < 0)
+			break;
+	}
+
+	return rc;
+}
+
+static struct
+smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
+				       dma_addr_t common_buffer_phys)
+{
+	struct smscore_buffer_t *cb =
+		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+	if (!cb) {
+		sms_info("kmalloc(...) failed");
+		return NULL;
+	}
+
+	cb->p = buffer;
+	cb->offset_in_common = buffer - (u8 *) common_buffer;
+	cb->phys = common_buffer_phys + cb->offset_in_common;
+
+	return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ *               and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+			    struct smscore_device_t **coredev)
+{
+	struct smscore_device_t *dev;
+	u8 *buffer;
+
+	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+	if (!dev) {
+		sms_info("kzalloc(...) failed");
+		return -ENOMEM;
+	}
+
+	/* init list entry so it could be safe in smscore_unregister_device */
+	INIT_LIST_HEAD(&dev->entry);
+
+	/* init queues */
+	INIT_LIST_HEAD(&dev->clients);
+	INIT_LIST_HEAD(&dev->buffers);
+
+	/* init locks */
+	spin_lock_init(&dev->clientslock);
+	spin_lock_init(&dev->bufferslock);
+
+	/* init completion events */
+	init_completion(&dev->version_ex_done);
+	init_completion(&dev->data_download_done);
+	init_completion(&dev->trigger_done);
+	init_completion(&dev->init_device_done);
+	init_completion(&dev->reload_start_done);
+	init_completion(&dev->resume_done);
+
+	/* alloc common buffer */
+	dev->common_buffer_size = params->buffer_size * params->num_buffers;
+	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+						&dev->common_buffer_phys,
+						GFP_KERNEL | GFP_DMA);
+	if (!dev->common_buffer) {
+		smscore_unregister_device(dev);
+		return -ENOMEM;
+	}
+
+	/* prepare dma buffers */
+	for (buffer = dev->common_buffer;
+	     dev->num_buffers < params->num_buffers;
+	     dev->num_buffers++, buffer += params->buffer_size) {
+		struct smscore_buffer_t *cb =
+			smscore_createbuffer(buffer, dev->common_buffer,
+					     dev->common_buffer_phys);
+		if (!cb) {
+			smscore_unregister_device(dev);
+			return -ENOMEM;
+		}
+
+		smscore_putbuffer(dev, cb);
+	}
+
+	sms_info("allocated %d buffers", dev->num_buffers);
+
+	dev->mode = DEVICE_MODE_NONE;
+	dev->context = params->context;
+	dev->device = params->device;
+	dev->setmode_handler = params->setmode_handler;
+	dev->detectmode_handler = params->detectmode_handler;
+	dev->sendrequest_handler = params->sendrequest_handler;
+	dev->preload_handler = params->preload_handler;
+	dev->postload_handler = params->postload_handler;
+
+	dev->device_flags = params->flags;
+	strcpy(dev->devpath, params->devpath);
+
+	smscore_registry_settype(dev->devpath, params->device_type);
+
+	/* add device to devices list */
+	kmutex_lock(&g_smscore_deviceslock);
+	list_add(&dev->entry, &g_smscore_devices);
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	*coredev = dev;
+
+	sms_info("device %p created", dev);
+
+	return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ * 		  smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+	int rc = smscore_set_device_mode(
+			coredev, smscore_registry_getmode(coredev->devpath));
+	if (rc < 0) {
+		sms_info("set device mode faile , rc %d", rc);
+		return rc;
+	}
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+
+	sms_info("device %p started, rc %d", coredev, rc);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	return rc;
+}
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+					void *buffer, size_t size,
+					struct completion *completion)
+{
+	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+	if (rc < 0) {
+		sms_info("sendrequest returned error %d", rc);
+		return rc;
+	}
+
+	return wait_for_completion_timeout(completion,
+					   msecs_to_jiffies(10000)) ?
+						0 : -ETIME;
+}
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+					 void *buffer, size_t size)
+{
+	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+	struct SmsMsgHdr_ST *msg;
+	u32 mem_address = firmware->StartAddress;
+	u8 *payload = firmware->Payload;
+	int rc = 0;
+
+	sms_info("loading FW to addr 0x%x size %d",
+		 mem_address, firmware->Length);
+	if (coredev->preload_handler) {
+		rc = coredev->preload_handler(coredev->context);
+		if (rc < 0)
+			return rc;
+	}
+
+	/* PAGE_SIZE buffer shall be enough and dma aligned */
+	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!msg)
+		return -ENOMEM;
+
+	if (coredev->mode != DEVICE_MODE_NONE) {
+		sms_debug("sending reload command.");
+		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
+			     sizeof(struct SmsMsgHdr_ST));
+		rc = smscore_sendrequest_and_wait(coredev, msg,
+						  msg->msgLength,
+						  &coredev->reload_start_done);
+		mem_address = *(u32 *) &payload[20];
+	}
+
+	while (size && rc >= 0) {
+		struct SmsDataDownload_ST *DataMsg =
+			(struct SmsDataDownload_ST *) msg;
+		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
+
+		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+			     (u16)(sizeof(struct SmsMsgHdr_ST) +
+				      sizeof(u32) + payload_size));
+
+		DataMsg->MemAddr = mem_address;
+		memcpy(DataMsg->Payload, payload, payload_size);
+
+		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
+		    (coredev->mode == DEVICE_MODE_NONE))
+			rc = coredev->sendrequest_handler(
+				coredev->context, DataMsg,
+				DataMsg->xMsgHeader.msgLength);
+		else
+			rc = smscore_sendrequest_and_wait(
+				coredev, DataMsg,
+				DataMsg->xMsgHeader.msgLength,
+				&coredev->data_download_done);
+
+		payload += payload_size;
+		size -= payload_size;
+		mem_address += payload_size;
+	}
+
+	if (rc >= 0) {
+		if (coredev->mode == DEVICE_MODE_NONE) {
+			struct SmsMsgData_ST *TriggerMsg =
+				(struct SmsMsgData_ST *) msg;
+
+			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+				     sizeof(struct SmsMsgHdr_ST) +
+				     sizeof(u32) * 5);
+
+			TriggerMsg->msgData[0] = firmware->StartAddress;
+						/* Entry point */
+			TriggerMsg->msgData[1] = 5; /* Priority */
+			TriggerMsg->msgData[2] = 0x200; /* Stack size */
+			TriggerMsg->msgData[3] = 0; /* Parameter */
+			TriggerMsg->msgData[4] = 4; /* Task ID */
+
+			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
+				rc = coredev->sendrequest_handler(
+					coredev->context, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength);
+				msleep(100);
+			} else
+				rc = smscore_sendrequest_and_wait(
+					coredev, TriggerMsg,
+					TriggerMsg->xMsgHeader.msgLength,
+					&coredev->trigger_done);
+		} else {
+			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+				     sizeof(struct SmsMsgHdr_ST));
+
+			rc = coredev->sendrequest_handler(coredev->context,
+							  msg, msg->msgLength);
+		}
+		msleep(500);
+	}
+
+	sms_debug("rc=%d, postload=%p ", rc,
+		  coredev->postload_handler);
+
+	kfree(msg);
+
+	return ((rc >= 0) && coredev->postload_handler) ?
+		coredev->postload_handler(coredev->context) :
+		rc;
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+					   char *filename,
+					   loadfirmware_t loadfirmware_handler)
+{
+	int rc = -ENOENT;
+	const struct firmware *fw;
+	u8 *fw_buffer;
+
+	if (loadfirmware_handler == NULL && !(coredev->device_flags &
+					      SMS_DEVICE_FAMILY2))
+		return -EINVAL;
+
+	rc = request_firmware(&fw, filename, coredev->device);
+	if (rc < 0) {
+		sms_info("failed to open \"%s\"", filename);
+		return rc;
+	}
+	sms_info("read FW %s, size=%zd", filename, fw->size);
+	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+			    GFP_KERNEL | GFP_DMA);
+	if (fw_buffer) {
+		memcpy(fw_buffer, fw->data, fw->size);
+
+		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+		      smscore_load_firmware_family2(coredev,
+						    fw_buffer,
+						    fw->size) :
+		      loadfirmware_handler(coredev->context,
+					   fw_buffer, fw->size);
+
+		kfree(fw_buffer);
+	} else {
+		sms_info("failed to allocate firmware buffer");
+		rc = -ENOMEM;
+	}
+
+	release_firmware(fw);
+
+	return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb;
+	int num_buffers = 0;
+	int retry = 0;
+
+	kmutex_lock(&g_smscore_deviceslock);
+
+	smscore_notify_clients(coredev);
+	smscore_notify_callbacks(coredev, NULL, 0);
+
+	/* at this point all buffers should be back
+	 * onresponse must no longer be called */
+
+	while (1) {
+		while ((cb = smscore_getbuffer(coredev))) {
+			kfree(cb);
+			num_buffers++;
+		}
+		if (num_buffers == coredev->num_buffers)
+			break;
+		if (++retry > 10) {
+			sms_info("exiting although "
+				 "not all buffers released.");
+			break;
+		}
+
+		sms_info("waiting for %d buffer(s)",
+			 coredev->num_buffers - num_buffers);
+		msleep(100);
+	}
+
+	sms_info("freed %d buffers", num_buffers);
+
+	if (coredev->common_buffer)
+		dma_free_coherent(NULL, coredev->common_buffer_size,
+				  coredev->common_buffer,
+				  coredev->common_buffer_phys);
+
+	list_del(&coredev->entry);
+	kfree(coredev);
+
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	sms_info("device %p destroyed", coredev);
+}
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+			       GFP_KERNEL | GFP_DMA);
+	struct SmsMsgHdr_ST *msg =
+		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+	int rc;
+
+	if (!buffer)
+		return -ENOMEM;
+
+	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+		     sizeof(struct SmsMsgHdr_ST));
+
+	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+					  &coredev->version_ex_done);
+	if (rc == -ETIME) {
+		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+		if (wait_for_completion_timeout(&coredev->resume_done,
+						msecs_to_jiffies(5000))) {
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->msgLength,
+				&coredev->version_ex_done);
+			if (rc < 0)
+				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
+					"second try, rc %d", rc);
+		} else
+			rc = -ETIME;
+	}
+
+	kfree(buffer);
+
+	return rc;
+}
+
+static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+	/*Stellar		NOVA A0		Nova B0		VEGA*/
+	/*DVBT*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*DVBH*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*TDMB*/
+	{"none", "tdmb_nova_12mhz.inp", "none", "none"},
+	/*DABIP*/
+	{"none", "none", "none", "none"},
+	/*BDA*/
+	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+	/*ISDBT*/
+	{"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+	/*ISDBTBDA*/
+	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+	/*CMMB*/
+	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
+};
+
+static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
+				    int mode, enum sms_device_type_st type)
+{
+	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
+	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+}
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+	void *buffer;
+	int rc = 0;
+	enum sms_device_type_st type;
+
+	sms_debug("set device mode to %d", mode);
+	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+			rc = smscore_detect_mode(coredev);
+			if (rc < 0) {
+				sms_err("mode detect failed %d", rc);
+				return rc;
+			}
+		}
+
+		if (coredev->mode == mode) {
+			sms_info("device mode %d already set", mode);
+			return 0;
+		}
+
+		if (!(coredev->modes_supported & (1 << mode))) {
+			char *fw_filename;
+
+			type = smscore_registry_gettype(coredev->devpath);
+			fw_filename = sms_get_fw_name(coredev, mode, type);
+
+			rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+			if (rc < 0) {
+				sms_warn("error %d loading firmware: %s, "
+					 "trying again with default firmware",
+					 rc, fw_filename);
+
+				/* try again with the default firmware */
+				fw_filename = smscore_fw_lkup[mode][type];
+				rc = smscore_load_firmware_from_file(coredev,
+							     fw_filename, NULL);
+
+				if (rc < 0) {
+					sms_warn("error %d loading "
+						 "firmware: %s", rc,
+						 fw_filename);
+					return rc;
+				}
+			}
+			sms_log("firmware download success: %s", fw_filename);
+		} else
+			sms_info("mode %d supported by running "
+				 "firmware", mode);
+
+		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
+				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+		if (buffer) {
+			struct SmsMsgData_ST *msg =
+				(struct SmsMsgData_ST *)
+					SMS_ALIGN_ADDRESS(buffer);
+
+			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+				     sizeof(struct SmsMsgData_ST));
+			msg->msgData[0] = mode;
+
+			rc = smscore_sendrequest_and_wait(
+				coredev, msg, msg->xMsgHeader.msgLength,
+				&coredev->init_device_done);
+
+			kfree(buffer);
+		} else {
+			sms_err("Could not allocate buffer for "
+				"init device message.");
+			rc = -ENOMEM;
+		}
+	} else {
+		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+			sms_err("invalid mode specified %d", mode);
+			return -EINVAL;
+		}
+
+		smscore_registry_setmode(coredev->devpath, mode);
+
+		if (coredev->detectmode_handler)
+			coredev->detectmode_handler(coredev->context,
+						    &coredev->mode);
+
+		if (coredev->mode != mode && coredev->setmode_handler)
+			rc = coredev->setmode_handler(coredev->context, mode);
+	}
+
+	if (rc >= 0) {
+		coredev->mode = mode;
+		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+	}
+
+	if (rc != 0)
+		sms_err("return error code %d.", rc);
+	return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+	return coredev->mode;
+}
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct
+smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
+				      int data_type, int id)
+{
+	struct smscore_client_t *client = NULL;
+	struct list_head *next, *first;
+	unsigned long flags;
+	struct list_head *firstid, *nextid;
+
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+	first = &coredev->clients;
+	for (next = first->next;
+	     (next != first) && !client;
+	     next = next->next) {
+		firstid = &((struct smscore_client_t *)next)->idlist;
+		for (nextid = firstid->next;
+		     nextid != firstid;
+		     nextid = nextid->next) {
+			if ((((struct smscore_idlist_t *)nextid)->id == id) &&
+			    (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
+			    (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
+				client = (struct smscore_client_t *) next;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+	return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+			struct smscore_buffer_t *cb)
+{
+	struct SmsMsgHdr_ST *phdr =
+		(struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
+	struct smscore_client_t *client =
+		smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+	int rc = -EBUSY;
+
+	static unsigned long last_sample_time; /* = 0; */
+	static int data_total; /* = 0; */
+	unsigned long time_now = jiffies_to_msecs(jiffies);
+
+	if (!last_sample_time)
+		last_sample_time = time_now;
+
+	if (time_now - last_sample_time > 10000) {
+		sms_debug("\ndata rate %d bytes/secs",
+			  (int)((data_total * 1000) /
+				(time_now - last_sample_time)));
+
+		last_sample_time = time_now;
+		data_total = 0;
+	}
+
+	data_total += cb->size;
+	/* If no client registered for type & id,
+	 * check for control client where type is not registered */
+	if (client)
+		rc = client->onresponse_handler(client->context, cb);
+
+	if (rc < 0) {
+		switch (phdr->msgType) {
+		case MSG_SMS_GET_VERSION_EX_RES:
+		{
+			struct SmsVersionRes_ST *ver =
+				(struct SmsVersionRes_ST *) phdr;
+			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+				  "id %d prots 0x%x ver %d.%d",
+				  ver->FirmwareId, ver->SupportedProtocols,
+				  ver->RomVersionMajor, ver->RomVersionMinor);
+
+			coredev->mode = ver->FirmwareId == 255 ?
+				DEVICE_MODE_NONE : ver->FirmwareId;
+			coredev->modes_supported = ver->SupportedProtocols;
+
+			complete(&coredev->version_ex_done);
+			break;
+		}
+		case MSG_SMS_INIT_DEVICE_RES:
+			sms_debug("MSG_SMS_INIT_DEVICE_RES");
+			complete(&coredev->init_device_done);
+			break;
+		case MSG_SW_RELOAD_START_RES:
+			sms_debug("MSG_SW_RELOAD_START_RES");
+			complete(&coredev->reload_start_done);
+			break;
+		case MSG_SMS_DATA_DOWNLOAD_RES:
+			complete(&coredev->data_download_done);
+			break;
+		case MSG_SW_RELOAD_EXEC_RES:
+			sms_debug("MSG_SW_RELOAD_EXEC_RES");
+			break;
+		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
+			complete(&coredev->trigger_done);
+			break;
+		case MSG_SMS_SLEEP_RESUME_COMP_IND:
+			complete(&coredev->resume_done);
+			break;
+		default:
+			break;
+		}
+		smscore_putbuffer(coredev, cb);
+	}
+}
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+	struct smscore_buffer_t *cb = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->bufferslock, flags);
+
+	if (!list_empty(&coredev->buffers)) {
+		cb = (struct smscore_buffer_t *) coredev->buffers.next;
+		list_del(&cb->entry);
+	}
+
+	spin_unlock_irqrestore(&coredev->bufferslock, flags);
+
+	return cb;
+}
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ *                smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+		       struct smscore_buffer_t *cb)
+{
+	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+				   struct smscore_client_t *client,
+				   int data_type, int id)
+{
+	struct smscore_idlist_t *listentry;
+	struct smscore_client_t *registered_client;
+
+	if (!client) {
+		sms_err("bad parameter.");
+		return -EFAULT;
+	}
+	registered_client = smscore_find_client(coredev, data_type, id);
+	if (registered_client == client)
+		return 0;
+
+	if (registered_client) {
+		sms_err("The msg ID already registered to another client.");
+		return -EEXIST;
+	}
+	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+	if (!listentry) {
+		sms_err("Can't allocate memory for client id.");
+		return -ENOMEM;
+	}
+	listentry->id = id;
+	listentry->data_type = data_type;
+	list_add_locked(&listentry->entry, &client->idlist,
+			&coredev->clientslock);
+	return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ *                           process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+			    struct smsclient_params_t *params,
+			    struct smscore_client_t **client)
+{
+	struct smscore_client_t *newclient;
+	/* check that no other channel with same parameters exists */
+	if (smscore_find_client(coredev, params->data_type,
+				params->initial_id)) {
+		sms_err("Client already exist.");
+		return -EEXIST;
+	}
+
+	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+	if (!newclient) {
+		sms_err("Failed to allocate memory for client.");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&newclient->idlist);
+	newclient->coredev = coredev;
+	newclient->onresponse_handler = params->onresponse_handler;
+	newclient->onremove_handler = params->onremove_handler;
+	newclient->context = params->context;
+	list_add_locked(&newclient->entry, &coredev->clients,
+			&coredev->clientslock);
+	smscore_validate_client(coredev, newclient, params->data_type,
+				params->initial_id);
+	*client = newclient;
+	sms_debug("%p %d %d", params->context, params->data_type,
+		  params->initial_id);
+
+	return 0;
+}
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+	struct smscore_device_t *coredev = client->coredev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&coredev->clientslock, flags);
+
+
+	while (!list_empty(&client->idlist)) {
+		struct smscore_idlist_t *identry =
+			(struct smscore_idlist_t *) client->idlist.next;
+		list_del(&identry->entry);
+		kfree(identry);
+	}
+
+	sms_info("%p", client->context);
+
+	list_del(&client->entry);
+	kfree(client);
+
+	spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ *               smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client,
+			  void *buffer, size_t size)
+{
+	struct smscore_device_t *coredev;
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+	int rc;
+
+	if (client == NULL) {
+		sms_err("Got NULL client");
+		return -EINVAL;
+	}
+
+	coredev = client->coredev;
+
+	/* check that no other channel with same id exists */
+	if (coredev == NULL) {
+		sms_err("Got NULL coredev");
+		return -EINVAL;
+	}
+
+	rc = smscore_validate_client(client->coredev, client, 0,
+				     phdr->msgSrcId);
+	if (rc < 0)
+		return rc;
+
+	return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+
+
+int smscore_module_init(void)
+{
+	int rc = 0;
+
+	INIT_LIST_HEAD(&g_smscore_notifyees);
+	INIT_LIST_HEAD(&g_smscore_devices);
+	kmutex_init(&g_smscore_deviceslock);
+
+	INIT_LIST_HEAD(&g_smscore_registry);
+	kmutex_init(&g_smscore_registrylock);
+
+	/* USB Register */
+	rc = smsusb_register();
+
+	/* DVB Register */
+	rc = smsdvb_register();
+
+	sms_debug("rc %d", rc);
+
+	return rc;
+}
+
+void smscore_module_exit(void)
+{
+
+	kmutex_lock(&g_smscore_deviceslock);
+	while (!list_empty(&g_smscore_notifyees)) {
+		struct smscore_device_notifyee_t *notifyee =
+			(struct smscore_device_notifyee_t *)
+				g_smscore_notifyees.next;
+
+		list_del(&notifyee->entry);
+		kfree(notifyee);
+	}
+	kmutex_unlock(&g_smscore_deviceslock);
+
+	kmutex_lock(&g_smscore_registrylock);
+	while (!list_empty(&g_smscore_registry)) {
+		struct smscore_registry_entry_t *entry =
+			(struct smscore_registry_entry_t *)
+				g_smscore_registry.next;
+
+		list_del(&entry->entry);
+		kfree(entry);
+	}
+	kmutex_unlock(&g_smscore_registrylock);
+
+	/* DVB UnRegister */
+	smsdvb_unregister();
+
+	/* Unregister USB */
+	smsusb_unregister();
+
+	sms_debug("");
+}
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
new file mode 100644
index 0000000..c1f8f1d
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -0,0 +1,434 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  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 __smscoreapi_h__
+#define __smscoreapi_h__
+
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <asm/page.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include <linux/mutex.h>
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define SMS_ALLOC_ALIGNMENT					128
+#define SMS_DMA_ALIGNMENT					16
+#define SMS_ALIGN_ADDRESS(addr) \
+	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY2					1
+#define SMS_ROM_NO_RESPONSE					2
+#define SMS_DEVICE_NOT_READY				0x8000000
+
+enum sms_device_type_st {
+	SMS_STELLAR = 0,
+	SMS_NOVA_A0,
+	SMS_NOVA_B0,
+	SMS_VEGA,
+	SMS_NUM_OF_DEVICE_TYPES
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t)(struct smscore_device_t *coredev,
+			 struct device *device, int arrival);
+
+typedef int (*setmode_t)(void *context, int mode);
+typedef void (*detectmode_t)(void *context, int *mode);
+typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
+typedef int (*preload_t)(void *context);
+typedef int (*postload_t)(void *context);
+
+typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t)(void *context);
+
+struct smscore_buffer_t {
+	/* public members, once passed to clients can be changed freely */
+	struct list_head entry;
+	int				size;
+	int				offset;
+
+	/* private members, read-only for clients */
+	void			*p;
+	dma_addr_t		phys;
+	unsigned long	offset_in_common;
+};
+
+struct smsdevice_params_t {
+	struct device	*device;
+
+	int				buffer_size;
+	int				num_buffers;
+
+	char			devpath[32];
+	unsigned long	flags;
+
+	setmode_t		setmode_handler;
+	detectmode_t	detectmode_handler;
+	sendrequest_t	sendrequest_handler;
+	preload_t		preload_handler;
+	postload_t		postload_handler;
+
+	void			*context;
+	enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+	int				initial_id;
+	int				data_type;
+	onresponse_t	onresponse_handler;
+	onremove_t		onremove_handler;
+
+	void			*context;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0					1
+#define SMS_ANTENNA_GPIO_1					0
+
+#define BW_8_MHZ							0
+#define BW_7_MHZ							1
+#define BW_6_MHZ							2
+#define BW_5_MHZ							3
+#define BW_ISDBT_1SEG						4
+#define BW_ISDBT_3SEG						5
+
+#define MSG_HDR_FLAG_SPLIT_MSG				4
+
+#define MAX_GPIO_PIN_NUMBER					31
+
+#define HIF_TASK							11
+#define SMS_HOST_LIB						150
+#define DVBT_BDA_CONTROL_MSG_ID				201
+
+#define SMS_MAX_PAYLOAD_SIZE				240
+#define SMS_TUNE_TIMEOUT					500
+
+#define MSG_SMS_GPIO_CONFIG_REQ				507
+#define MSG_SMS_GPIO_CONFIG_RES				508
+#define MSG_SMS_GPIO_SET_LEVEL_REQ			509
+#define MSG_SMS_GPIO_SET_LEVEL_RES			510
+#define MSG_SMS_GPIO_GET_LEVEL_REQ			511
+#define MSG_SMS_GPIO_GET_LEVEL_RES			512
+#define MSG_SMS_RF_TUNE_REQ					561
+#define MSG_SMS_RF_TUNE_RES					562
+#define MSG_SMS_INIT_DEVICE_REQ				578
+#define MSG_SMS_INIT_DEVICE_RES				579
+#define MSG_SMS_ADD_PID_FILTER_REQ			601
+#define MSG_SMS_ADD_PID_FILTER_RES			602
+#define MSG_SMS_REMOVE_PID_FILTER_REQ		603
+#define MSG_SMS_REMOVE_PID_FILTER_RES		604
+#define MSG_SMS_DAB_CHANNEL					607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ		608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES		609
+#define MSG_SMS_GET_STATISTICS_REQ			615
+#define MSG_SMS_GET_STATISTICS_RES			616
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ		651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES		652
+#define MSG_SMS_GET_STATISTICS_EX_REQ		653
+#define MSG_SMS_GET_STATISTICS_EX_RES		654
+#define MSG_SMS_SLEEP_RESUME_COMP_IND		655
+#define MSG_SMS_DATA_DOWNLOAD_REQ			660
+#define MSG_SMS_DATA_DOWNLOAD_RES			661
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES		665
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ		666
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES		667
+#define MSG_SMS_GET_VERSION_EX_REQ			668
+#define MSG_SMS_GET_VERSION_EX_RES			669
+#define MSG_SMS_SET_CLOCK_OUTPUT_REQ		670
+#define MSG_SMS_I2C_SET_FREQ_REQ			685
+#define MSG_SMS_GENERIC_I2C_REQ				687
+#define MSG_SMS_GENERIC_I2C_RES				688
+#define MSG_SMS_DVBT_BDA_DATA				693
+#define MSG_SW_RELOAD_REQ					697
+#define MSG_SMS_DATA_MSG					699
+#define MSG_SW_RELOAD_START_REQ				702
+#define MSG_SW_RELOAD_START_RES				703
+#define MSG_SW_RELOAD_EXEC_REQ				704
+#define MSG_SW_RELOAD_EXEC_RES				705
+#define MSG_SMS_SPI_INT_LINE_SET_REQ		710
+#define MSG_SMS_ISDBT_TUNE_REQ				776
+#define MSG_SMS_ISDBT_TUNE_RES				777
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
+	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+} while (0)
+#define SMS_INIT_MSG(ptr, type, len) \
+	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DEVICE_MODE {
+	DEVICE_MODE_NONE = -1,
+	DEVICE_MODE_DVBT = 0,
+	DEVICE_MODE_DVBH,
+	DEVICE_MODE_DAB_TDMB,
+	DEVICE_MODE_DAB_TDMB_DABIP,
+	DEVICE_MODE_DVBT_BDA,
+	DEVICE_MODE_ISDBT,
+	DEVICE_MODE_ISDBT_BDA,
+	DEVICE_MODE_CMMB,
+	DEVICE_MODE_RAW_TUNER,
+	DEVICE_MODE_MAX,
+};
+
+struct SmsMsgHdr_ST {
+	u16	msgType;
+	u8	msgSrcId;
+	u8	msgDstId;
+	u16	msgLength; /* Length of entire message, including header */
+	u16	msgFlags;
+};
+
+struct SmsMsgData_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+	u32			msgData[1];
+};
+
+struct SmsDataDownload_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+	u32			MemAddr;
+	u8			Payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct SmsVersionRes_ST {
+	struct SmsMsgHdr_ST	xMsgHeader;
+
+	u16		ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
+	u8		Step; /* 0 - Step A */
+	u8		MetalFix; /* 0 - Metal 0 */
+
+	u8		FirmwareId; /* 0xFF � ROM, otherwise the
+				     * value indicated by
+				     * SMSHOSTLIB_DEVICE_MODES_E */
+	u8		SupportedProtocols; /* Bitwise OR combination of
+					     * supported protocols */
+
+	u8		VersionMajor;
+	u8		VersionMinor;
+	u8		VersionPatch;
+	u8		VersionFieldPatch;
+
+	u8		RomVersionMajor;
+	u8		RomVersionMinor;
+	u8		RomVersionPatch;
+	u8		RomVersionFieldPatch;
+
+	u8		TextLabel[34];
+};
+
+struct SmsFirmware_ST {
+	u32			CheckSum;
+	u32			Length;
+	u32			StartAddress;
+	u8			Payload[1];
+};
+
+struct SMSHOSTLIB_STATISTICS_ST {
+	u32 Reserved; /* Reserved */
+
+	/* Common parameters */
+	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+	/* Reception quality */
+	s32  SNR; /* dB */
+	u32 BER; /* Post Viterbi BER [1E-5] */
+	u32 FIB_CRC;	/* CRC errors percentage, valid only for DAB */
+	u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
+		     * valid only for DVB-T/H */
+	u32 MFER; /* DVB-H frame error rate in percentage,
+		   * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32  RSSI; /* dBm */
+	s32  InBandPwr; /* In band power in dBM */
+	s32  CarrierOffset; /* Carrier Offset in bin/1024 */
+
+	/* Transmission parameters, valid only for DVB-T/H */
+	u32 Frequency; /* Frequency in Hz */
+	u32 Bandwidth; /* Bandwidth in MHz */
+	u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
+			       * for DVB-T/H FFT mode carriers in Kilos */
+	u32 ModemState; /* from SMS_DvbModemState_ET */
+	u32 GuardInterval; /* Guard Interval, 1 divided by value */
+	u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
+	u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
+	u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
+	u32 Constellation; /* Constellation from SMS_Constellation_ET */
+
+	/* Burst parameters, valid only for DVB-H */
+	u32 BurstSize; /* Current burst size in bytes */
+	u32 BurstDuration; /* Current burst duration in mSec */
+	u32 BurstCycleTime; /* Current burst cycle time in mSec */
+	u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
+				       * as calculated by demodulator */
+	u32 NumOfRows; /* Number of rows in MPE table */
+	u32 NumOfPaddCols; /* Number of padding columns in MPE table */
+	u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
+	/* Burst parameters */
+	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+	u32 TotalTSPackets; /* Total number of transport-stream packets */
+	u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
+				* errors after MPE RS decoding */
+	u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
+				  * after MPE RS decoding */
+	u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
+				    * by MPE RS decoding */
+
+	/* Common params */
+	u32 BERErrorCount; /* Number of errornous SYNC bits. */
+	u32 BERBitCount; /* Total number of SYNC bits. */
+
+	/* Interface information */
+	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+
+	/* DAB/T-DMB */
+	u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+
+	/* DVB-H TPS parameters */
+	u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+		     * if set to 0xFFFFFFFF cell_id not yet recovered */
+
+};
+
+struct SmsMsgStatisticsInfo_ST {
+	u32 RequestResult;
+
+	struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+	/* Split the calc of the SNR in DAB */
+	u32 Signal; /* dB */
+	u32 Noise; /* dB */
+
+};
+
+
+struct smsdvb_client_t {
+	struct list_head entry;
+
+	struct smscore_device_t	*coredev;
+	struct smscore_client_t	*smsclient;
+
+	struct dvb_adapter	adapter;
+	struct dvb_demux	demux;
+	struct dmxdev		dmxdev;
+	struct dvb_frontend	frontend;
+
+	fe_status_t		fe_status;
+	int			fe_ber, fe_snr, fe_signal_strength;
+
+	struct completion	tune_done, stat_done;
+
+	/* todo: save freq/band instead whole struct */
+	struct dvb_frontend_parameters fe_params;
+
+};
+
+extern void smscore_registry_setmode(char *devpath, int mode);
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+				   struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+				 char *filename,
+				 loadfirmware_t loadfirmware_handler);
+
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+				    struct smsclient_params_t *params,
+				    struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+				 void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+			       struct smscore_buffer_t *cb);
+
+
+extern
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+			      struct smscore_buffer_t *cb);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+/* smsdvb.c */
+int smsdvb_register(void);
+void smsdvb_unregister(void);
+
+/* smsusb.c */
+int smsusb_register(void);
+void smsusb_unregister(void);
+
+/* ------------------------------------------------------------------------ */
+
+extern int sms_debug;
+
+#define DBG_INFO 1
+#define DBG_ADV  2
+
+#define sms_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+	if (sms_debug & lvl) \
+		sms_printk(kern, fmt, ##arg); } while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+	sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...)  sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+	dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
+
+
+#endif /* __smscoreapi_h__ */
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
new file mode 100644
index 0000000..6f9c185
--- /dev/null
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -0,0 +1,449 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct list_head g_smsdvb_clients;
+struct mutex g_smsdvb_clientslock;
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+	struct SmsMsgHdr_ST *phdr =
+		(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+
+	switch (phdr->msgType) {
+	case MSG_SMS_DVBT_BDA_DATA:
+		dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
+				 cb->size - sizeof(struct SmsMsgHdr_ST));
+		break;
+
+	case MSG_SMS_RF_TUNE_RES:
+		complete(&client->tune_done);
+		break;
+
+	case MSG_SMS_GET_STATISTICS_RES:
+	{
+		struct SmsMsgStatisticsInfo_ST *p =
+			(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
+
+		if (p->Stat.IsDemodLocked) {
+			client->fe_status = FE_HAS_SIGNAL |
+					    FE_HAS_CARRIER |
+					    FE_HAS_VITERBI |
+					    FE_HAS_SYNC |
+					    FE_HAS_LOCK;
+
+			client->fe_snr = p->Stat.SNR;
+			client->fe_ber = p->Stat.BER;
+
+			if (p->Stat.InBandPwr < -95)
+				client->fe_signal_strength = 0;
+			else if (p->Stat.InBandPwr > -29)
+				client->fe_signal_strength = 100;
+			else
+				client->fe_signal_strength =
+					(p->Stat.InBandPwr + 95) * 3 / 2;
+		} else {
+			client->fe_status = 0;
+			client->fe_snr =
+			client->fe_ber =
+			client->fe_signal_strength = 0;
+		}
+
+		complete(&client->stat_done);
+		break;
+	} }
+
+	smscore_putbuffer(client->coredev, cb);
+
+	return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+	/* must be called under clientslock */
+
+	list_del(&client->entry);
+
+	smscore_unregister_client(client->smsclient);
+	dvb_unregister_frontend(&client->frontend);
+	dvb_dmxdev_release(&client->dmxdev);
+	dvb_dmx_release(&client->demux);
+	dvb_unregister_adapter(&client->adapter);
+	kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("add pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct smsdvb_client_t *client =
+		container_of(feed->demux, struct smsdvb_client_t, demux);
+	struct SmsMsgData_ST PidMsg;
+
+	sms_debug("remove pid %d(%x)",
+		  feed->pid, feed->pid);
+
+	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+	PidMsg.xMsgHeader.msgFlags = 0;
+	PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
+	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+	PidMsg.msgData[0] = feed->pid;
+
+	return smsclient_sendrequest(client->smsclient,
+				     &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+					void *buffer, size_t size,
+					struct completion *completion)
+{
+	int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+	if (rc < 0)
+		return rc;
+
+	return wait_for_completion_timeout(completion,
+					   msecs_to_jiffies(2000)) ?
+						0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+			     DVBT_BDA_CONTROL_MSG_ID,
+			     HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->stat_done);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*stat = client->fe_status;
+
+	return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*ber = client->fe_ber;
+
+	return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*strength = client->fe_signal_strength;
+
+	return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	int rc = smsdvb_send_statistics_request(client);
+
+	if (!rc)
+		*snr = client->fe_snr;
+
+	return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	sms_debug("");
+
+	tune->min_delay_ms = 400;
+	tune->step_size = 250000;
+	tune->max_drift = 0;
+	return 0;
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *fep)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	struct {
+		struct SmsMsgHdr_ST	Msg;
+		u32		Data[3];
+	} Msg;
+
+	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId  = HIF_TASK;
+	Msg.Msg.msgFlags  = 0;
+	Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+	Msg.Msg.msgLength = sizeof(Msg);
+	Msg.Data[0] = fep->frequency;
+	Msg.Data[2] = 12000000;
+
+	sms_debug("freq %d band %d",
+		  fep->frequency, fep->u.ofdm.bandwidth);
+
+	switch (fep->u.ofdm.bandwidth) {
+	case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
+	case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
+	case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
+	case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+	default: return -EINVAL;
+	}
+
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->tune_done);
+}
+
+static int smsdvb_get_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *fep)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	sms_debug("");
+
+	/* todo: */
+	memcpy(fep, &client->fe_params,
+	       sizeof(struct dvb_frontend_parameters));
+	return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+	/* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+	.info = {
+		.name			= "Siano Mobile Digital SMS1xxx",
+		.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 = smsdvb_release,
+
+	.set_frontend = smsdvb_set_frontend,
+	.get_frontend = smsdvb_get_frontend,
+	.get_tune_settings = smsdvb_get_tune_settings,
+
+	.read_status = smsdvb_read_status,
+	.read_ber = smsdvb_read_ber,
+	.read_signal_strength = smsdvb_read_signal_strength,
+	.read_snr = smsdvb_read_snr,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+			  struct device *device, int arrival)
+{
+	struct smsclient_params_t params;
+	struct smsdvb_client_t *client;
+	int rc;
+
+	/* device removal handled by onremove callback */
+	if (!arrival)
+		return 0;
+
+	if (smscore_get_device_mode(coredev) != 4) {
+		sms_err("SMS Device mode is not set for "
+			"DVB operation.");
+		return 0;
+	}
+
+	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
+	if (!client) {
+		sms_err("kmalloc() failed");
+		return -ENOMEM;
+	}
+
+	/* register dvb adapter */
+	rc = dvb_register_adapter(&client->adapter,
+				  sms_get_board(
+					smscore_get_board_id(coredev))->name,
+				  THIS_MODULE, device, adapter_nr);
+	if (rc < 0) {
+		sms_err("dvb_register_adapter() failed %d", rc);
+		goto adapter_error;
+	}
+
+	/* init dvb demux */
+	client->demux.dmx.capabilities = DMX_TS_FILTERING;
+	client->demux.filternum = 32; /* todo: nova ??? */
+	client->demux.feednum = 32;
+	client->demux.start_feed = smsdvb_start_feed;
+	client->demux.stop_feed = smsdvb_stop_feed;
+
+	rc = dvb_dmx_init(&client->demux);
+	if (rc < 0) {
+		sms_err("dvb_dmx_init failed %d", rc);
+		goto dvbdmx_error;
+	}
+
+	/* init dmxdev */
+	client->dmxdev.filternum = 32;
+	client->dmxdev.demux = &client->demux.dmx;
+	client->dmxdev.capabilities = 0;
+
+	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+	if (rc < 0) {
+		sms_err("dvb_dmxdev_init failed %d", rc);
+		goto dmxdev_error;
+	}
+
+	/* init and register frontend */
+	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	rc = dvb_register_frontend(&client->adapter, &client->frontend);
+	if (rc < 0) {
+		sms_err("frontend registration failed %d", rc);
+		goto frontend_error;
+	}
+
+	params.initial_id = 1;
+	params.data_type = MSG_SMS_DVBT_BDA_DATA;
+	params.onresponse_handler = smsdvb_onresponse;
+	params.onremove_handler = smsdvb_onremove;
+	params.context = client;
+
+	rc = smscore_register_client(coredev, &params, &client->smsclient);
+	if (rc < 0) {
+		sms_err("smscore_register_client() failed %d", rc);
+		goto client_error;
+	}
+
+	client->coredev = coredev;
+
+	init_completion(&client->tune_done);
+	init_completion(&client->stat_done);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	list_add(&client->entry, &g_smsdvb_clients);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+
+	sms_info("success");
+
+	return 0;
+
+client_error:
+	dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+	dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+	dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+	dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+	kfree(client);
+	return rc;
+}
+
+int smsdvb_register(void)
+{
+	int rc;
+
+	INIT_LIST_HEAD(&g_smsdvb_clients);
+	kmutex_init(&g_smsdvb_clientslock);
+
+	rc = smscore_register_hotplug(smsdvb_hotplug);
+
+	sms_debug("");
+
+	return rc;
+}
+
+void smsdvb_unregister(void)
+{
+	smscore_unregister_hotplug(smsdvb_hotplug);
+
+	kmutex_lock(&g_smsdvb_clientslock);
+
+	while (!list_empty(&g_smsdvb_clients))
+	       smsdvb_unregister_client(
+			(struct smsdvb_client_t *) g_smsdvb_clients.next);
+
+	kmutex_unlock(&g_smsdvb_clientslock);
+}
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
new file mode 100644
index 0000000..c10b184
--- /dev/null
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -0,0 +1,459 @@
+/*
+ *  Driver for the Siano SMS1xxx USB dongle
+ *
+ *  author: Anatoly Greenblat
+ *
+ *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ *  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+#define USB1_BUFFER_SIZE		0x1000
+#define USB2_BUFFER_SIZE		0x4000
+
+#define MAX_BUFFERS		50
+#define MAX_URBS		10
+
+struct smsusb_device_t;
+
+struct smsusb_urb_t {
+	struct smscore_buffer_t *cb;
+	struct smsusb_device_t	*dev;
+
+	struct urb urb;
+};
+
+struct smsusb_device_t {
+	struct usb_device *udev;
+	struct smscore_device_t *coredev;
+
+	struct smsusb_urb_t 	surbs[MAX_URBS];
+
+	int		response_alignment;
+	int		buffer_size;
+};
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+			     struct smsusb_urb_t *surb);
+
+static void smsusb_onresponse(struct urb *urb)
+{
+	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
+	struct smsusb_device_t *dev = surb->dev;
+
+	if (urb->status < 0) {
+		sms_err("error, urb status %d, %d bytes",
+			urb->status, urb->actual_length);
+		return;
+	}
+
+	if (urb->actual_length > 0) {
+		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+
+		if (urb->actual_length >= phdr->msgLength) {
+			surb->cb->size = phdr->msgLength;
+
+			if (dev->response_alignment &&
+			    (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
+
+				surb->cb->offset =
+					dev->response_alignment +
+					((phdr->msgFlags >> 8) & 3);
+
+				/* sanity check */
+				if (((int) phdr->msgLength +
+				     surb->cb->offset) > urb->actual_length) {
+					sms_err("invalid response "
+						"msglen %d offset %d "
+						"size %d",
+						phdr->msgLength,
+						surb->cb->offset,
+						urb->actual_length);
+					goto exit_and_resubmit;
+				}
+
+				/* move buffer pointer and
+				 * copy header to its new location */
+				memcpy((char *) phdr + surb->cb->offset,
+				       phdr, sizeof(struct SmsMsgHdr_ST));
+			} else
+				surb->cb->offset = 0;
+
+			smscore_onresponse(dev->coredev, surb->cb);
+			surb->cb = NULL;
+		} else {
+			sms_err("invalid response "
+				"msglen %d actual %d",
+				phdr->msgLength, urb->actual_length);
+		}
+	}
+
+exit_and_resubmit:
+	smsusb_submit_urb(dev, surb);
+}
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+			     struct smsusb_urb_t *surb)
+{
+	if (!surb->cb) {
+		surb->cb = smscore_getbuffer(dev->coredev);
+		if (!surb->cb) {
+			sms_err("smscore_getbuffer(...) returned NULL");
+			return -ENOMEM;
+		}
+	}
+
+	usb_fill_bulk_urb(
+		&surb->urb,
+		dev->udev,
+		usb_rcvbulkpipe(dev->udev, 0x81),
+		surb->cb->p,
+		dev->buffer_size,
+		smsusb_onresponse,
+		surb
+	);
+	surb->urb.transfer_dma = surb->cb->phys;
+	surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	return usb_submit_urb(&surb->urb, GFP_ATOMIC);
+}
+
+static void smsusb_stop_streaming(struct smsusb_device_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_URBS; i++) {
+		usb_kill_urb(&dev->surbs[i].urb);
+
+		if (dev->surbs[i].cb) {
+			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
+			dev->surbs[i].cb = NULL;
+		}
+	}
+}
+
+static int smsusb_start_streaming(struct smsusb_device_t *dev)
+{
+	int i, rc;
+
+	for (i = 0; i < MAX_URBS; i++) {
+		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
+		if (rc < 0) {
+			sms_err("smsusb_submit_urb(...) failed");
+			smsusb_stop_streaming(dev);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int smsusb_sendrequest(void *context, void *buffer, size_t size)
+{
+	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
+	int dummy;
+
+	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+			    buffer, size, &dummy, 1000);
+}
+
+static char *smsusb1_fw_lkup[] = {
+	"dvbt_stellar_usb.inp",
+	"dvbh_stellar_usb.inp",
+	"tdmb_stellar_usb.inp",
+	"none",
+	"dvbt_bda_stellar_usb.inp",
+};
+
+static inline char *sms_get_fw_name(int mode, int board_id)
+{
+	char **fw = sms_get_board(board_id)->fw;
+	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
+}
+
+static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
+{
+	const struct firmware *fw;
+	u8 *fw_buffer;
+	int rc, dummy;
+	char *fw_filename;
+
+	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
+		sms_err("invalid firmware id specified %d", id);
+		return -EINVAL;
+	}
+
+	fw_filename = sms_get_fw_name(id, board_id);
+
+	rc = request_firmware(&fw, fw_filename, &udev->dev);
+	if (rc < 0) {
+		sms_warn("failed to open \"%s\" mode %d, "
+			 "trying again with default firmware", fw_filename, id);
+
+		fw_filename = smsusb1_fw_lkup[id];
+		rc = request_firmware(&fw, fw_filename, &udev->dev);
+		if (rc < 0) {
+			sms_warn("failed to open \"%s\" mode %d",
+				 fw_filename, id);
+
+			return rc;
+		}
+	}
+
+	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
+	if (fw_buffer) {
+		memcpy(fw_buffer, fw->data, fw->size);
+
+		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
+				  fw_buffer, fw->size, &dummy, 1000);
+
+		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+
+		kfree(fw_buffer);
+	} else {
+		sms_err("failed to allocate firmware buffer");
+		rc = -ENOMEM;
+	}
+	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+
+	release_firmware(fw);
+
+	return rc;
+}
+
+static void smsusb1_detectmode(void *context, int *mode)
+{
+	char *product_string =
+		((struct smsusb_device_t *) context)->udev->product;
+
+	*mode = DEVICE_MODE_NONE;
+
+	if (!product_string) {
+		product_string = "none";
+		sms_err("product string not found");
+	} else if (strstr(product_string, "DVBH"))
+		*mode = 1;
+	else if (strstr(product_string, "BDA"))
+		*mode = 4;
+	else if (strstr(product_string, "DVBT"))
+		*mode = 0;
+	else if (strstr(product_string, "TDMB"))
+		*mode = 2;
+
+	sms_info("%d \"%s\"", *mode, product_string);
+}
+
+static int smsusb1_setmode(void *context, int mode)
+{
+	struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
+			     sizeof(struct SmsMsgHdr_ST), 0 };
+
+	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+		sms_err("invalid firmware id specified %d", mode);
+		return -EINVAL;
+	}
+
+	return smsusb_sendrequest(context, &Msg, sizeof(Msg));
+}
+
+static void smsusb_term_device(struct usb_interface *intf)
+{
+	struct smsusb_device_t *dev =
+		(struct smsusb_device_t *) usb_get_intfdata(intf);
+
+	if (dev) {
+		smsusb_stop_streaming(dev);
+
+		/* unregister from smscore */
+		if (dev->coredev)
+			smscore_unregister_device(dev->coredev);
+
+		kfree(dev);
+
+		sms_info("device %p destroyed", dev);
+	}
+
+	usb_set_intfdata(intf, NULL);
+}
+
+static int smsusb_init_device(struct usb_interface *intf, int board_id)
+{
+	struct smsdevice_params_t params;
+	struct smsusb_device_t *dev;
+	int i, rc;
+
+	/* create device object */
+	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
+	if (!dev) {
+		sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
+		return -ENOMEM;
+	}
+
+	memset(&params, 0, sizeof(params));
+	usb_set_intfdata(intf, dev);
+	dev->udev = interface_to_usbdev(intf);
+
+	params.device_type = sms_get_board(board_id)->type;
+
+	switch (params.device_type) {
+	case SMS_STELLAR:
+		dev->buffer_size = USB1_BUFFER_SIZE;
+
+		params.setmode_handler = smsusb1_setmode;
+		params.detectmode_handler = smsusb1_detectmode;
+		break;
+	default:
+		sms_err("Unspecified sms device type!");
+		/* fall-thru */
+	case SMS_NOVA_A0:
+	case SMS_NOVA_B0:
+	case SMS_VEGA:
+		dev->buffer_size = USB2_BUFFER_SIZE;
+		dev->response_alignment =
+			dev->udev->ep_in[1]->desc.wMaxPacketSize -
+			sizeof(struct SmsMsgHdr_ST);
+
+		params.flags |= SMS_DEVICE_FAMILY2;
+		break;
+	}
+
+	params.device = &dev->udev->dev;
+	params.buffer_size = dev->buffer_size;
+	params.num_buffers = MAX_BUFFERS;
+	params.sendrequest_handler = smsusb_sendrequest;
+	params.context = dev;
+	snprintf(params.devpath, sizeof(params.devpath),
+		 "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+
+	/* register in smscore */
+	rc = smscore_register_device(&params, &dev->coredev);
+	if (rc < 0) {
+		sms_err("smscore_register_device(...) failed, rc %d", rc);
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	smscore_set_board_id(dev->coredev, board_id);
+
+	/* initialize urbs */
+	for (i = 0; i < MAX_URBS; i++) {
+		dev->surbs[i].dev = dev;
+		usb_init_urb(&dev->surbs[i].urb);
+	}
+
+	sms_info("smsusb_start_streaming(...).");
+	rc = smsusb_start_streaming(dev);
+	if (rc < 0) {
+		sms_err("smsusb_start_streaming(...) failed");
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	rc = smscore_start_device(dev->coredev);
+	if (rc < 0) {
+		sms_err("smscore_start_device(...) failed");
+		smsusb_term_device(intf);
+		return rc;
+	}
+
+	sms_info("device %p created", dev);
+
+	return rc;
+}
+
+static int smsusb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	char devpath[32];
+	int i, rc;
+
+	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+	if (intf->num_altsetting > 0) {
+		rc = usb_set_interface(
+			udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
+		if (rc < 0) {
+			sms_err("usb_set_interface failed, rc %d", rc);
+			return rc;
+		}
+	}
+
+	sms_info("smsusb_probe %d",
+	       intf->cur_altsetting->desc.bInterfaceNumber);
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+		sms_info("endpoint %d %02x %02x %d", i,
+		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
+		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
+		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+
+	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
+	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
+		sms_err("rom interface 0 is not used");
+		return -ENODEV;
+	}
+
+	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
+			 udev->bus->busnum, udev->devpath);
+		sms_info("stellar device was found.");
+		return smsusb1_load_firmware(
+				udev, smscore_registry_getmode(devpath),
+				id->driver_info);
+	}
+
+	rc = smsusb_init_device(intf, id->driver_info);
+	sms_info("rc %d", rc);
+	return rc;
+}
+
+static void smsusb_disconnect(struct usb_interface *intf)
+{
+	smsusb_term_device(intf);
+}
+
+static struct usb_driver smsusb_driver = {
+	.name			= "sms1xxx",
+	.probe			= smsusb_probe,
+	.disconnect		= smsusb_disconnect,
+	.id_table		= smsusb_id_table,
+};
+
+int smsusb_register(void)
+{
+	int rc = usb_register(&smsusb_driver);
+	if (rc)
+		sms_err("usb_register failed. Error number %d", rc);
+
+	sms_debug("");
+
+	return rc;
+}
+
+void smsusb_unregister(void)
+{
+	sms_debug("");
+	/* Regular USB Cleanup */
+	usb_deregister(&smsusb_driver);
+}
+
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 07643e0..87c973a 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -106,6 +106,8 @@
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
 	select VIDEO_IR
 	help
 	  Support for simple SAA7146 based DVB cards
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index d7483f1..7145123 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -3,7 +3,11 @@
 # and the AV7110 DVB device driver
 #
 
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
+
+ifdef CONFIG_INPUT_EVDEV
+dvb-ttpci-objs += av7110_ir.o
+endif
 
 obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
@@ -14,6 +18,7 @@
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
 
 hostprogs-y	:= fdump
 
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index f05d43d..0777e8f 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -587,7 +587,7 @@
 		}
 		DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0);
+		dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
 
 		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
 		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
@@ -1198,7 +1198,6 @@
 	if (budget->feeding1)
 		return ++budget->feeding1;
 	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
-	budget->tsf = 0xff;
 	budget->ttbp = 0;
 	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
 	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
@@ -2403,18 +2402,18 @@
 		saa7146_write(dev, MC1, MASK_29);
 		/* RPS1 timeout disable */
 		saa7146_write(dev, RPS_TOV1, 0);
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+		WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 		/* issue RPS1 interrupt to increment counter */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
-		WRITE_RPS1(cpu_to_le32(CMD_STOP));
+		WRITE_RPS1(CMD_STOP);
 		/* Jump to begin of RPS program as safety measure               (p37) */
-		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
 
 #if RPS_IRQ
 		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
@@ -2472,11 +2471,7 @@
 	   get recognized before the main driver is fully loaded */
 	saa7146_write(dev, GPIO_CTRL, 0x500000);
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
 	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2527,28 +2522,28 @@
 		count = 0;
 
 		/* Wait Source Line Counter Threshold                           (p36) */
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+		WRITE_RPS1(CMD_PAUSE | EVT_HS);
 		/* Set GPIO3=1                                                  (p42) */
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
 #if RPS_IRQ
 		/* issue RPS1 interrupt */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
 		/* Wait reset Source Line Counter Threshold                     (p36) */
-		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+		WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
 		/* Set GPIO3=0                                                  (p42) */
-		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+		WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+		WRITE_RPS1(GPIO3_MSK);
+		WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 		/* issue RPS1 interrupt */
-		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+		WRITE_RPS1(CMD_INTERRUPT);
 #endif
 		/* Jump to begin of RPS program                                 (p37) */
-		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+		WRITE_RPS1(CMD_JUMP);
+		WRITE_RPS1(dev->d_rps1.dma_handle);
 
 		/* Fix VSYNC level */
 		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index e494e04..55f23dd 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -188,7 +188,6 @@
 	struct dvb_net		dvb_net1;
 	spinlock_t		feedlock1;
 	int			feeding1;
-	u8			tsf;
 	u32			ttbp;
 	unsigned char           *grabbing;
 	struct saa7146_pgtable  pt;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index ec55a968..184647a 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -269,7 +269,7 @@
 		return -1;
 	}
 
-	dvb_ringbuffer_read(buf, dest, (size_t) blen, 0);
+	dvb_ringbuffer_read(buf, dest, (size_t) blen);
 
 	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
 	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index c58e3fc..261135d 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -208,7 +208,7 @@
 		return -EINVAL;
 	DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-	return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
+	return dvb_ringbuffer_read_user(cibuf, buf, len);
 }
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 74d940f..ca99e5c 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -305,7 +305,6 @@
 #define IRQ_STATE	(DPRAM_BASE + 0x0F4)
 #define IRQ_STATE_EXT	(DPRAM_BASE + 0x0F6)
 #define MSGSTATE	(DPRAM_BASE + 0x0F8)
-#define FILT_STATE	(DPRAM_BASE + 0x0FA)
 #define COMMAND		(DPRAM_BASE + 0x0FC)
 #define COM_BUFF	(DPRAM_BASE + 0x100)
 #define COM_BUFF_SIZE	0x20
@@ -332,8 +331,6 @@
 
 /* firmware status area */
 #define STATUS_BASE	(DPRAM_BASE + 0x1FC0)
-#define STATUS_SCR	(STATUS_BASE + 0x00)
-#define STATUS_MODES	(STATUS_BASE + 0x04)
 #define STATUS_LOOPS	(STATUS_BASE + 0x08)
 
 #define STATUS_MPEG_WIDTH     (STATUS_BASE + 0x0C)
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index b30a528..b7d1f2f 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -667,6 +667,11 @@
 	.invert = 0,
 };
 
+static struct tda10023_config philips_cu1216_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
 static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
@@ -1019,9 +1024,10 @@
 	case SUBID_DVBC_KNC1_PLUS_MK3:
 		budget_av->reinitialise_demod = 1;
 		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
-		fe = dvb_attach(tda10023_attach, &philips_cu1216_config,
-				     &budget_av->budget.i2c_adap,
-				     read_pwm(budget_av));
+		fe = dvb_attach(tda10023_attach,
+			&philips_cu1216_tda10023_config,
+			&budget_av->budget.i2c_adap,
+			read_pwm(budget_av));
 		if (fe) {
 			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
 		}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 6530323..060e7c7 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -46,6 +46,8 @@
 #include "lnbp21.h"
 #include "bsbe1.h"
 #include "bsru6.h"
+#include "tda1002x.h"
+#include "tda827x.h"
 
 /*
  * Regarding DEBIADDR_IR:
@@ -225,6 +227,7 @@
 		break;
 	case 0x1010:
 	case 0x1017:
+	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_tt_1500);
@@ -1056,6 +1059,15 @@
 	.stop_during_read = 1,
 };
 
+static struct tda10023_config tda10023_config = {
+	.demod_address = 0xc,
+	.invert = 0,
+	.xtal = 16000000,
+	.pll_m = 11,
+	.pll_p = 3,
+	.pll_n = 1,
+	.deltaf = 0xa511,
+};
 
 
 
@@ -1126,7 +1138,17 @@
 				budget_ci->budget.dvb_frontend = NULL;
 			}
 		}
+		break;
 
+	case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
+		budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
+		if (budget_ci->budget.dvb_frontend) {
+			if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
+				printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
 		break;
 	}
 
@@ -1216,6 +1238,7 @@
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1224,6 +1247,7 @@
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
 	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
 	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
+	MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
 	{
 	 .vendor = 0,
 	 }
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 18cac4b..6f4ddb6 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -497,11 +497,7 @@
 	if (bi->type != BUDGET_FS_ACTIVY)
 		saa7146_write(dev, GPIO_CTRL, 0x500000);	/* GPIO 3 = 1 */
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
 
 	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 9a15539..39bd0a2 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -431,22 +431,22 @@
 	// in budget patch GPIO3 is connected to VSYNC_B
 	count = 0;
 #if 0
-	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
-	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
+	WRITE_RPS1(CMD_UPLOAD |
+	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
 #endif
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+	WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 	// issue RPS1 interrupt to increment counter
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 	// at least a NOP is neede between two interrupts
-	WRITE_RPS1(cpu_to_le32(CMD_NOP));
+	WRITE_RPS1(CMD_NOP);
 	// interrupt again
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
-	WRITE_RPS1(cpu_to_le32(CMD_STOP));
+	WRITE_RPS1(CMD_STOP);
 
 #if RPS_IRQ
 	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
@@ -558,28 +558,28 @@
 
 
 	// Wait Source Line Counter Threshold                           (p36)
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+	WRITE_RPS1(CMD_PAUSE | EVT_HS);
 	// Set GPIO3=1                                                  (p42)
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
 #if RPS_IRQ
 	// issue RPS1 interrupt
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
 	// Wait reset Source Line Counter Threshold                     (p36)
-	WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+	WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
 	// Set GPIO3=0                                                  (p42)
-	WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
-	WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
-	WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+	WRITE_RPS1(GPIO3_MSK);
+	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
 #if RPS_IRQ
 	// issue RPS1 interrupt
-	WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+	WRITE_RPS1(CMD_INTERRUPT);
 #endif
 	// Jump to begin of RPS program                                 (p37)
-	WRITE_RPS1(cpu_to_le32(CMD_JUMP));
-	WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+	WRITE_RPS1(CMD_JUMP);
+	WRITE_RPS1(dev->d_rps1.dma_handle);
 
 	// Fix VSYNC level
 	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index bc2043e..e6c9cd2 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
+#include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
@@ -990,22 +991,9 @@
 }
 
 static ssize_t stc_read(struct file *file, char *buf, size_t count,
-		 loff_t * offset)
+		 loff_t *offset)
 {
-	int tc = count;
-
-	if ((tc + *offset) > 8192)
-		tc = 8192 - *offset;
-
-	if (tc < 0)
-		return 0;
-
-	if (copy_to_user(buf, stc_firmware + *offset, tc))
-		return -EFAULT;
-
-	*offset += tc;
-
-	return tc;
+	return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
 }
 
 static int stc_release(struct inode *inode, struct file *file)
@@ -1693,11 +1681,7 @@
 
 	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
 
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	ttusb->i2c_adap.class		  = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
 	ttusb->i2c_adap.class		  = I2C_CLASS_TV_DIGITAL;
-#endif
 	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
 	ttusb->i2c_adap.algo_data         = NULL;
 	ttusb->i2c_adap.dev.parent	  = &udev->dev;
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 77354ca..dc93a88 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -24,6 +24,19 @@
 
 
 /*
+ * User Notes:
+ * - USB Audio is provided by the alsa snd_usb_audio module.
+ *   For listing you have to redirect the sound, for example using:
+ *   arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
+ * - regarding module parameters in /sys/module/radio_si470x/parameters:
+ *   the contents of read-only files (0444) are not updated, even if
+ *   space, band and de are changed using private video controls
+ * - increase tune_timeout, if you often get -EIO errors
+ * - hw_freq_seek returns -EAGAIN, when timed out or band limit is reached
+ */
+
+
+/*
  * History:
  * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
  *		Version 1.0.0
@@ -85,10 +98,14 @@
  *		Oliver Neukum <oliver@neukum.org>
  *		Version 1.0.7
  *		- usb autosuspend support
- *             - unplugging fixed
+ *		- unplugging fixed
+ * 2008-05-07	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.8
+ *		- hardware frequency seek support
+ *		- afc indication
+ *		- more safety checks, let si470x_get_freq return errno
  *
  * ToDo:
- * - add seeking support
  * - add firmware download/update support
  * - RDS support: interrupt mode, instead of polling
  * - add LED status output (check if that's not already done in firmware)
@@ -98,10 +115,10 @@
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
 #define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.7"
+#define DRIVER_VERSION "1.0.8"
 
 
 /* kernel includes */
@@ -175,6 +192,11 @@
 module_param(tune_timeout, uint, 0);
 MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
 
+/* Seek timeout */
+static unsigned int seek_timeout = 5000;
+module_param(seek_timeout, uint, 0);
+MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
+
 /* RDS buffer blocks */
 static unsigned int rds_buf = 100;
 module_param(rds_buf, uint, 0);
@@ -425,7 +447,8 @@
 
 	/* driver management */
 	unsigned int users;
-       unsigned char disconnected;
+	unsigned char disconnected;
+	struct mutex disconnect_lock;
 
 	/* Silabs internal registers (0..15) */
 	unsigned short registers[RADIO_REGISTER_NUM];
@@ -442,12 +465,6 @@
 
 
 /*
- * Lock to prevent kfree of data before all users have releases the device.
- */
-static DEFINE_MUTEX(open_close_lock);
-
-
-/*
  * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
  * 62.5 kHz otherwise.
  * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
@@ -476,11 +493,11 @@
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
 		report[0], 2,
 		buf, size, usb_timeout);
+
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 			": si470x_get_report: usb_control_msg returned %d\n",
 			retval);
-
 	return retval;
 }
 
@@ -499,11 +516,11 @@
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
 		report[0], 2,
 		buf, size, usb_timeout);
+
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 			": si470x_set_report: usb_control_msg returned %d\n",
 			retval);
-
 	return retval;
 }
 
@@ -521,8 +538,7 @@
 	retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
 
 	if (retval >= 0)
-		radio->registers[regnr] = be16_to_cpu(get_unaligned(
-			(unsigned short *) &buf[1]));
+		radio->registers[regnr] = get_unaligned_be16(&buf[1]);
 
 	return (retval < 0) ? -EINVAL : 0;
 }
@@ -537,8 +553,7 @@
 	int retval;
 
 	buf[0] = REGISTER_REPORT(regnr);
-	put_unaligned(cpu_to_be16(radio->registers[regnr]),
-		(unsigned short *) &buf[1]);
+	put_unaligned_be16(radio->registers[regnr], &buf[1]);
 
 	retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
 
@@ -561,9 +576,8 @@
 
 	if (retval >= 0)
 		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
-			radio->registers[regnr] = be16_to_cpu(get_unaligned(
-				(unsigned short *)
-				&buf[regnr * RADIO_REGISTER_SIZE + 1]));
+			radio->registers[regnr] = get_unaligned_be16(
+				&buf[regnr * RADIO_REGISTER_SIZE + 1]);
 
 	return (retval < 0) ? -EINVAL : 0;
 }
@@ -585,7 +599,7 @@
 		usb_rcvintpipe(radio->usbdev, 1),
 		(void *) &buf, sizeof(buf), &size, usb_timeout);
 	if (size != sizeof(buf))
-	       printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
 			"return size differs: %d != %zu\n", size, sizeof(buf));
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
@@ -594,8 +608,8 @@
 	if (retval >= 0)
 		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
 			radio->registers[STATUSRSSI + regnr] =
-				be16_to_cpu(get_unaligned((unsigned short *)
-				&buf[regnr * RADIO_REGISTER_SIZE + 1]));
+				get_unaligned_be16(
+				&buf[regnr * RADIO_REGISTER_SIZE + 1]);
 
 	return (retval < 0) ? -EINVAL : 0;
 }
@@ -615,33 +629,39 @@
 	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
 	retval = si470x_set_register(radio, CHANNEL);
 	if (retval < 0)
-		return retval;
+		goto done;
 
-	/* wait till seek operation has completed */
+	/* wait till tune operation has completed */
 	timeout = jiffies + msecs_to_jiffies(tune_timeout);
 	do {
 		retval = si470x_get_register(radio, STATUSRSSI);
 		if (retval < 0)
-			return retval;
+			goto stop;
 		timed_out = time_after(jiffies, timeout);
 	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
 		(!timed_out));
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+		printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n");
 	if (timed_out)
 		printk(KERN_WARNING DRIVER_NAME
-			": seek does not finish after %u ms\n", tune_timeout);
+			": tune timed out after %u ms\n", tune_timeout);
 
+stop:
 	/* stop tuning */
 	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
-	return si470x_set_register(radio, CHANNEL);
+	retval = si470x_set_register(radio, CHANNEL);
+
+done:
+	return retval;
 }
 
 
 /*
  * si470x_get_freq - get the frequency
  */
-static unsigned int si470x_get_freq(struct si470x_device *radio)
+static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
 {
-	unsigned int spacing, band_bottom, freq;
+	unsigned int spacing, band_bottom;
 	unsigned short chan;
 	int retval;
 
@@ -667,14 +687,12 @@
 
 	/* read channel */
 	retval = si470x_get_register(radio, READCHAN);
-	if (retval < 0)
-		return retval;
 	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
 
 	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
-	freq = chan * spacing + band_bottom;
+	*freq = chan * spacing + band_bottom;
 
-	return freq;
+	return retval;
 }
 
 
@@ -714,6 +732,62 @@
 
 
 /*
+ * si470x_set_seek - set seek
+ */
+static int si470x_set_seek(struct si470x_device *radio,
+		unsigned int wrap_around, unsigned int seek_upward)
+{
+	int retval = 0;
+	unsigned long timeout;
+	bool timed_out = 0;
+
+	/* start seeking */
+	radio->registers[POWERCFG] |= POWERCFG_SEEK;
+	if (wrap_around == 1)
+		radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
+	else
+		radio->registers[POWERCFG] |= POWERCFG_SKMODE;
+	if (seek_upward == 1)
+		radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
+	else
+		radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
+	retval = si470x_set_register(radio, POWERCFG);
+	if (retval < 0)
+		goto done;
+
+	/* wait till seek operation has completed */
+	timeout = jiffies + msecs_to_jiffies(seek_timeout);
+	do {
+		retval = si470x_get_register(radio, STATUSRSSI);
+		if (retval < 0)
+			goto stop;
+		timed_out = time_after(jiffies, timeout);
+	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
+		(!timed_out));
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+		printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n");
+	if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek failed / band limit reached\n");
+	if (timed_out)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek timed out after %u ms\n", seek_timeout);
+
+stop:
+	/* stop seeking */
+	radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
+	retval = si470x_set_register(radio, POWERCFG);
+
+done:
+	/* try again, if timed out */
+	if ((retval == 0) && timed_out)
+		retval = -EAGAIN;
+
+	return retval;
+}
+
+
+/*
  * si470x_start - switch on radio
  */
 static int si470x_start(struct si470x_device *radio)
@@ -725,27 +799,30 @@
 		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
 	retval = si470x_set_register(radio, POWERCFG);
 	if (retval < 0)
-		return retval;
+		goto done;
 
 	/* sysconfig 1 */
 	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	if (retval < 0)
-		return retval;
+		goto done;
 
 	/* sysconfig 2 */
 	radio->registers[SYSCONFIG2] =
-		(0x3f  << 8) |	/* SEEKTH */
-		(band  << 6) |	/* BAND */
-		(space << 4) |	/* SPACE */
-		15;		/* VOLUME (max) */
+		(0x3f  << 8) |				/* SEEKTH */
+		((band  << 6) & SYSCONFIG2_BAND)  |	/* BAND */
+		((space << 4) & SYSCONFIG2_SPACE) |	/* SPACE */
+		15;					/* VOLUME (max) */
 	retval = si470x_set_register(radio, SYSCONFIG2);
 	if (retval < 0)
-		return retval;
+		goto done;
 
 	/* reset last channel */
-	return si470x_set_chan(radio,
+	retval = si470x_set_chan(radio,
 		radio->registers[CHANNEL] & CHANNEL_CHAN);
+
+done:
+	return retval;
 }
 
 
@@ -760,13 +837,16 @@
 	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	if (retval < 0)
-		return retval;
+		goto done;
 
 	/* powercfg */
 	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 	/* POWERCFG_ENABLE has to automatically go low */
 	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
-	return si470x_set_register(radio, POWERCFG);
+	retval = si470x_set_register(radio, POWERCFG);
+
+done:
+	return retval;
 }
 
 
@@ -843,7 +923,7 @@
 		};
 
 		/* Fill the V4L2 RDS buffer */
-		put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf);
+		put_unaligned_le16(rds, &tmpbuf);
 		tmpbuf[2] = blocknum;		/* offset name */
 		tmpbuf[2] |= blocknum << 3;	/* received offset */
 		if (bler > max_rds_errors)
@@ -883,8 +963,9 @@
 	struct si470x_device *radio = container_of(work, struct si470x_device,
 		work.work);
 
-       if (radio->disconnected)
-	       return;
+	/* safety checks */
+	if (radio->disconnected)
+		return;
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		return;
 
@@ -917,11 +998,15 @@
 
 	/* block if no new data available */
 	while (radio->wr_index == radio->rd_index) {
-		if (file->f_flags & O_NONBLOCK)
-			return -EWOULDBLOCK;
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
 		if (wait_event_interruptible(radio->read_queue,
-			radio->wr_index != radio->rd_index) < 0)
-			return -EINTR;
+			radio->wr_index != radio->rd_index) < 0) {
+			retval = -EINTR;
+			goto done;
+		}
 	}
 
 	/* calculate block count from byte count */
@@ -950,6 +1035,7 @@
 	}
 	mutex_unlock(&radio->lock);
 
+done:
 	return retval;
 }
 
@@ -961,6 +1047,7 @@
 		struct poll_table_struct *pts)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
 	/* switch on rds reception */
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
@@ -972,9 +1059,9 @@
 	poll_wait(file, &radio->read_queue, pts);
 
 	if (radio->rd_index != radio->wr_index)
-		return POLLIN | POLLRDNORM;
+		retval = POLLIN | POLLRDNORM;
 
-	return 0;
+	return retval;
 }
 
 
@@ -991,17 +1078,18 @@
 	retval = usb_autopm_get_interface(radio->intf);
 	if (retval < 0) {
 		radio->users--;
-		return -EIO;
+		retval = -EIO;
+		goto done;
 	}
 
 	if (radio->users == 1) {
 		retval = si470x_start(radio);
 		if (retval < 0)
 			usb_autopm_put_interface(radio->intf);
-		return retval;
 	}
 
-	return 0;
+done:
+	return retval;
 }
 
 
@@ -1011,20 +1099,23 @@
 static int si470x_fops_release(struct inode *inode, struct file *file)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-       int retval = 0;
+	int retval = 0;
 
-	if (!radio)
-		return -ENODEV;
+	/* safety check */
+	if (!radio) {
+		retval = -ENODEV;
+		goto done;
+	}
 
-       mutex_lock(&open_close_lock);
+	mutex_lock(&radio->disconnect_lock);
 	radio->users--;
 	if (radio->users == 0) {
-	       if (radio->disconnected) {
-		       video_unregister_device(radio->videodev);
-		       kfree(radio->buffer);
-		       kfree(radio);
-		       goto done;
-	       }
+		if (radio->disconnected) {
+			video_unregister_device(radio->videodev);
+			kfree(radio->buffer);
+			kfree(radio);
+			goto unlock;
+		}
 
 		/* stop rds reception */
 		cancel_delayed_work_sync(&radio->work);
@@ -1036,9 +1127,11 @@
 		usb_autopm_put_interface(radio->intf);
 	}
 
+unlock:
+	mutex_unlock(&radio->disconnect_lock);
+
 done:
-       mutex_unlock(&open_close_lock);
-       return retval;
+	return retval;
 }
 
 
@@ -1116,7 +1209,8 @@
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	sprintf(capability->bus_info, "USB");
 	capability->version = DRIVER_KERNEL_VERSION;
-	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+		V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 
 	return 0;
 }
@@ -1125,7 +1219,7 @@
 /*
  * si470x_vidioc_g_input - get input
  */
-static int si470x_vidioc_g_input(struct file *filp, void *priv,
+static int si470x_vidioc_g_input(struct file *file, void *priv,
 		unsigned int *i)
 {
 	*i = 0;
@@ -1137,12 +1231,18 @@
 /*
  * si470x_vidioc_s_input - set input
  */
-static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-	if (i != 0)
-		return -EINVAL;
+	int retval = 0;
 
-	return 0;
+	/* safety checks */
+	if (i != 0)
+		retval = -EINVAL;
+
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set input failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1155,17 +1255,22 @@
 	unsigned char i;
 	int retval = -EINVAL;
 
+	/* safety checks */
+	if (!qc->id)
+		goto done;
+
 	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
-		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
+		if (qc->id == si470x_v4l2_queryctrl[i].id) {
 			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
 			retval = 0;
 			break;
 		}
 	}
+
+done:
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
-			": query control failed with %d\n", retval);
-
+			": query controls failed with %d\n", retval);
 	return retval;
 }
 
@@ -1177,9 +1282,13 @@
 		struct v4l2_control *ctrl)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
@@ -1190,9 +1299,15 @@
 		ctrl->value = ((radio->registers[POWERCFG] &
 				POWERCFG_DMUTE) == 0) ? 1 : 0;
 		break;
+	default:
+		retval = -EINVAL;
 	}
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get control failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1203,10 +1318,13 @@
 		struct v4l2_control *ctrl)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
@@ -1224,10 +1342,11 @@
 	default:
 		retval = -EINVAL;
 	}
+
+done:
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 			": set control failed with %d\n", retval);
-
 	return retval;
 }
 
@@ -1238,13 +1357,22 @@
 static int si470x_vidioc_g_audio(struct file *file, void *priv,
 		struct v4l2_audio *audio)
 {
-	if (audio->index > 1)
-		return -EINVAL;
+	int retval = 0;
+
+	/* safety checks */
+	if (audio->index != 0) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 	strcpy(audio->name, "Radio");
 	audio->capability = V4L2_AUDCAP_STEREO;
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get audio failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1254,10 +1382,19 @@
 static int si470x_vidioc_s_audio(struct file *file, void *priv,
 		struct v4l2_audio *audio)
 {
-	if (audio->index != 0)
-		return -EINVAL;
+	int retval = 0;
 
-	return 0;
+	/* safety checks */
+	if (audio->index != 0) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set audio failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1268,20 +1405,23 @@
 		struct v4l2_tuner *tuner)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (tuner->index > 0)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
-	/* read status rssi */
 	retval = si470x_get_register(radio, STATUSRSSI);
 	if (retval < 0)
-		return retval;
+		goto done;
 
 	strcpy(tuner->name, "FM");
-	tuner->type = V4L2_TUNER_RADIO;
 	switch (band) {
 	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
 	default:
@@ -1313,9 +1453,14 @@
 				* 0x0101;
 
 	/* automatic frequency control: -1: freq to low, 1 freq to high */
-	tuner->afc = 0;
+	/* AFCRL does only indicate that freq. differs, not if too low/high */
+	tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get tuner failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1326,12 +1471,17 @@
 		struct v4l2_tuner *tuner)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (tuner->index > 0)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
 		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
@@ -1339,10 +1489,11 @@
 		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
 
 	retval = si470x_set_register(radio, POWERCFG);
+
+done:
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 			": set tuner failed with %d\n", retval);
-
 	return retval;
 }
 
@@ -1354,14 +1505,25 @@
 		struct v4l2_frequency *freq)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
-	freq->type = V4L2_TUNER_RADIO;
-	freq->frequency = si470x_get_freq(radio);
+	retval = si470x_get_freq(radio, &freq->frequency);
 
-	return 0;
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": get frequency failed with %d\n", retval);
+	return retval;
 }
 
 
@@ -1372,19 +1534,55 @@
 		struct v4l2_frequency *freq)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+	int retval = 0;
 
-       if (radio->disconnected)
-	       return -EIO;
-	if (freq->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
 
 	retval = si470x_set_freq(radio, freq->frequency);
+
+done:
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME
 			": set frequency failed with %d\n", retval);
+	return retval;
+}
 
-	return 0;
+
+/*
+ * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
+ */
+static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+		struct v4l2_hw_freq_seek *seek)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+
+	/* safety checks */
+	if (radio->disconnected) {
+		retval = -EIO;
+		goto done;
+	}
+	if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
+
+done:
+	if (retval < 0)
+		printk(KERN_WARNING DRIVER_NAME
+			": set hardware frequency seek failed with %d\n",
+			retval);
+	return retval;
 }
 
 
@@ -1408,6 +1606,7 @@
 	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
 	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
 	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek	= si470x_vidioc_s_hw_freq_seek,
 	.owner			= THIS_MODULE,
 };
 
@@ -1424,31 +1623,36 @@
 		const struct usb_device_id *id)
 {
 	struct si470x_device *radio;
-	int retval = -ENOMEM;
+	int retval = 0;
 
-	/* private data allocation */
+	/* private data allocation and initialization */
 	radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
-	if (!radio)
+	if (!radio) {
+		retval = -ENOMEM;
 		goto err_initial;
-
-	/* video device allocation */
-	radio->videodev = video_device_alloc();
-	if (!radio->videodev)
-		goto err_radio;
-
-	/* initial configuration */
-	memcpy(radio->videodev, &si470x_viddev_template,
-			sizeof(si470x_viddev_template));
+	}
 	radio->users = 0;
+	radio->disconnected = 0;
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->intf = intf;
+	mutex_init(&radio->disconnect_lock);
 	mutex_init(&radio->lock);
+
+	/* video device allocation and initialization */
+	radio->videodev = video_device_alloc();
+	if (!radio->videodev) {
+		retval = -ENOMEM;
+		goto err_radio;
+	}
+	memcpy(radio->videodev, &si470x_viddev_template,
+			sizeof(si470x_viddev_template));
 	video_set_drvdata(radio->videodev, radio);
 
 	/* show some infos about the specific device */
-	retval = -EIO;
-	if (si470x_get_all_registers(radio) < 0)
+	if (si470x_get_all_registers(radio) < 0) {
+		retval = -EIO;
 		goto err_all;
+	}
 	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
 			radio->registers[DEVICEID], radio->registers[CHIPID]);
 
@@ -1474,8 +1678,10 @@
 	/* rds buffer allocation */
 	radio->buf_size = rds_buf * 3;
 	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
-	if (!radio->buffer)
+	if (!radio->buffer) {
+		retval = -EIO;
 		goto err_all;
+	}
 
 	/* rds buffer configuration */
 	radio->wr_index = 0;
@@ -1487,6 +1693,7 @@
 
 	/* register video device */
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		retval = -EIO;
 		printk(KERN_WARNING DRIVER_NAME
 				": Could not register video device\n");
 		goto err_all;
@@ -1546,16 +1753,16 @@
 {
 	struct si470x_device *radio = usb_get_intfdata(intf);
 
-       mutex_lock(&open_close_lock);
-       radio->disconnected = 1;
+	mutex_lock(&radio->disconnect_lock);
+	radio->disconnected = 1;
 	cancel_delayed_work_sync(&radio->work);
 	usb_set_intfdata(intf, NULL);
-       if (radio->users == 0) {
-	       video_unregister_device(radio->videodev);
-	       kfree(radio->buffer);
-	       kfree(radio);
-       }
-       mutex_unlock(&open_close_lock);
+	if (radio->users == 0) {
+		video_unregister_device(radio->videodev);
+		kfree(radio->buffer);
+		kfree(radio);
+	}
+	mutex_unlock(&radio->disconnect_lock);
 }
 
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 5ccb0ae..f606d29 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -24,21 +24,21 @@
 	select VIDEOBUF_GEN
 	tristate
 
+config VIDEOBUF_DMA_CONTIG
+	depends on HAS_DMA
+	select VIDEOBUF_GEN
+	tristate
+
 config VIDEOBUF_DVB
 	tristate
 	select VIDEOBUF_GEN
-	select VIDEOBUF_DMA_SG
 
 config VIDEO_BTCX
 	tristate
 
-config VIDEO_IR_I2C
-	tristate
-
 config VIDEO_IR
 	tristate
 	depends on INPUT
-	select VIDEO_IR_I2C if I2C
 
 config VIDEO_TVEEPROM
 	tristate
@@ -84,6 +84,19 @@
 
 	  In doubt, say Y.
 
+config VIDEO_IR_I2C
+	tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
+	depends on I2C && VIDEO_IR
+	default y
+	---help---
+	  Most boards have an IR chip directly connected via GPIO. However,
+	  some video boards have the IR connected via I2C bus.
+
+	  If your board doesn't have an I2C IR chip, you may disable this
+	  option.
+
+	  In doubt, say Y.
+
 #
 # Encoder / Decoder module configuration
 #
@@ -600,9 +613,6 @@
 	  driver for PCI.  There is a product page at
 	  <http://www.stradis.com/>.
 
-config VIDEO_ZORAN_ZR36060
-	tristate
-
 config VIDEO_ZORAN
 	tristate "Zoran ZR36057/36067 Video For Linux"
 	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
@@ -616,25 +626,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr36067.
 
-config VIDEO_ZORAN_BUZ
-	tristate "Iomega Buz support"
-	depends on VIDEO_ZORAN
-	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
-	help
-	  Support for the Iomega Buz MJPEG capture/playback card.
-
-config VIDEO_ZORAN_DC10
-	tristate "Pinnacle/Miro DC10(+) support"
-	depends on VIDEO_ZORAN
-	select VIDEO_SAA7110
-	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
-	help
-	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
-	  card.
-
 config VIDEO_ZORAN_DC30
 	tristate "Pinnacle/Miro DC30(+) support"
 	depends on VIDEO_ZORAN
@@ -645,32 +636,54 @@
 	  card. This also supports really old DC10 cards based on the
 	  zr36050 MJPEG codec and zr36016 VFE.
 
+config VIDEO_ZORAN_ZR36060
+	tristate "Zoran ZR36060"
+	depends on VIDEO_ZORAN
+	help
+	  Say Y to support Zoran boards based on 36060 chips.
+	  This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33
+	  and 33 R10 and AverMedia 6 boards.
+
+config VIDEO_ZORAN_BUZ
+	tristate "Iomega Buz support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Iomega Buz MJPEG capture/playback card.
+
+config VIDEO_ZORAN_DC10
+	tristate "Pinnacle/Miro DC10(+) support"
+	depends on VIDEO_ZORAN_ZR36060
+	select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	help
+	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
+	  card.
+
 config VIDEO_ZORAN_LML33
 	tristate "Linux Media Labs LML33 support"
-	depends on VIDEO_ZORAN
+	depends on VIDEO_ZORAN_ZR36060
 	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the Linux Media Labs LML33 MJPEG capture/playback
 	  card.
 
 config VIDEO_ZORAN_LML33R10
 	tristate "Linux Media Labs LML33R10 support"
-	depends on VIDEO_ZORAN
+	depends on VIDEO_ZORAN_ZR36060
 	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
 	  card.
 
 config VIDEO_ZORAN_AVS6EYES
 	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
-	depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+	depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
 	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
-	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the AverMedia 6 Eyes video surveillance card.
 
@@ -801,6 +814,8 @@
 
 	  For more information see: <http://linux-uvc.berlios.de/>
 
+source "drivers/media/video/gspca/Kconfig"
+
 source "drivers/media/video/pvrusb2/Kconfig"
 
 source "drivers/media/video/em28xx/Kconfig"
@@ -905,12 +920,21 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called stkwebcam.
 
+config USB_S2255
+	tristate "USB Sensoray 2255 video capture device"
+	depends on VIDEO_V4L2
+	select VIDEOBUF_VMALLOC
+	default n
+	help
+	  Say Y here if you want support for the Sensoray 2255 USB device.
+	  This driver can be compiled as a module, called s2255drv.
+
 endif # V4L_USB_DRIVERS
 
 config SOC_CAMERA
 	tristate "SoC camera support"
 	depends on VIDEO_V4L2 && HAS_DMA
-	select VIDEOBUF_DMA_SG
+	select VIDEOBUF_GEN
 	help
 	  SoC Camera is a common API to several cameras, not connecting
 	  over a bus like PCI or USB. For example some i2c camera connected
@@ -945,11 +969,26 @@
 	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
 	  extender to switch between 8 and 10 bit datawidth modes
 
+config SOC_CAMERA_PLATFORM
+	tristate "platform camera support"
+	depends on SOC_CAMERA
+	help
+	  This is a generic SoC camera platform driver, useful for testing
+
 config VIDEO_PXA27x
 	tristate "PXA27x Quick Capture Interface driver"
 	depends on VIDEO_DEV && PXA27x
 	select SOC_CAMERA
+	select VIDEOBUF_DMA_SG
 	---help---
 	  This is a v4l2 driver for the PXA27x Quick Capture Interface
 
+config VIDEO_SH_MOBILE_CEU
+	tristate "SuperH Mobile CEU Interface driver"
+	depends on VIDEO_DEV
+	select SOC_CAMERA
+	select VIDEOBUF_DMA_CONTIG
+	---help---
+	  This is a v4l2 driver for the SuperH Mobile CEU Interface
+
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ecbbfaa..45d5db5 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -88,6 +88,7 @@
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
@@ -117,11 +118,13 @@
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_ZC0301)        += zc0301/
+obj-$(CONFIG_USB_GSPCA)         += gspca/
 
 obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
+obj-$(CONFIG_USB_S2255)		+= s2255drv.o
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
@@ -130,9 +133,11 @@
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 8bfd5c7..ddd2a79 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -516,7 +516,7 @@
 
 	dprintk(1,
 		KERN_INFO
-		"saa7111.c: detecting bt819 client on address 0x%x\n",
+		"bt819: detecting bt819 client on address 0x%x\n",
 		address << 1);
 
 	/* Check if the adapter supports the needed features */
diff --git a/drivers/media/video/bt8xx/bt832.c b/drivers/media/video/bt8xx/bt832.c
index f92f06d..216fc96 100644
--- a/drivers/media/video/bt8xx/bt832.c
+++ b/drivers/media/video/bt8xx/bt832.c
@@ -179,7 +179,6 @@
 
 	v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
 
-
 	if(! bt832_init(&t->client)) {
 		bt832_detach(&t->client);
 		return -1;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 0165aac..0ea559a 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2448,7 +2448,7 @@
 	}
 }
 
-static int bttv_g_fmt_cap(struct file *file, void *priv,
+static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct bttv_fh *fh  = priv;
@@ -2461,7 +2461,7 @@
 	return 0;
 }
 
-static int bttv_g_fmt_overlay(struct file *file, void *priv,
+static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct bttv_fh *fh  = priv;
@@ -2472,7 +2472,7 @@
 	return 0;
 }
 
-static int bttv_try_fmt_cap(struct file *file, void *priv,
+static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
 	const struct bttv_format *fmt;
@@ -2532,7 +2532,7 @@
 	return 0;
 }
 
-static int bttv_try_fmt_overlay(struct file *file, void *priv,
+static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
 	struct bttv_fh *fh = priv;
@@ -2542,7 +2542,7 @@
 			/* adjust_crop */ 0);
 }
 
-static int bttv_s_fmt_cap(struct file *file, void *priv,
+static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	int retval;
@@ -2556,7 +2556,7 @@
 	if (0 != retval)
 		return retval;
 
-	retval = bttv_try_fmt_cap(file, priv, f);
+	retval = bttv_try_fmt_vid_cap(file, priv, f);
 	if (0 != retval)
 		return retval;
 
@@ -2591,7 +2591,7 @@
 	return 0;
 }
 
-static int bttv_s_fmt_overlay(struct file *file, void *priv,
+static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct bttv_fh *fh = priv;
@@ -2661,7 +2661,7 @@
 	return 0;
 }
 
-static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
+static int bttv_enum_fmt_vbi_cap(struct file *file, void  *priv,
 				struct v4l2_fmtdesc *f)
 {
 	if (0 != f->index)
@@ -2692,7 +2692,7 @@
 	return i;
 }
 
-static int bttv_enum_fmt_cap(struct file *file, void  *priv,
+static int bttv_enum_fmt_vid_cap(struct file *file, void  *priv,
 				struct v4l2_fmtdesc *f)
 {
 	int rc = bttv_enum_fmt_cap_ovr(f);
@@ -2703,7 +2703,7 @@
 	return 0;
 }
 
-static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
+static int bttv_enum_fmt_vid_overlay(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	int rc;
@@ -3362,18 +3362,18 @@
 	.fops     = &bttv_fops,
 	.minor    = -1,
 	.vidioc_querycap                = bttv_querycap,
-	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
-	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
-	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
-	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
-	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
-	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
-	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
-	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
-	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
-	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
-	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
-	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
+	.vidioc_enum_fmt_vid_cap        = bttv_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap           = bttv_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap         = bttv_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap           = bttv_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay    = bttv_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay       = bttv_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay     = bttv_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay       = bttv_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vbi_cap        = bttv_enum_fmt_vbi_cap,
+	.vidioc_g_fmt_vbi_cap           = bttv_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap         = bttv_try_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap           = bttv_s_fmt_vbi_cap,
 	.vidioc_g_audio                 = bttv_g_audio,
 	.vidioc_s_audio                 = bttv_s_audio,
 	.vidioc_cropcap                 = bttv_cropcap,
@@ -3705,7 +3705,7 @@
 	for (i = 0; i < (risc->size >> 2); i += n) {
 		printk("%s:   0x%lx: ", btv->c.name,
 		       (unsigned long)(risc->dma + (i<<2)));
-		n = bttv_risc_decode(risc->cpu[i]);
+		n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
 		for (j = 1; j < n; j++)
 			printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
 			       btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
@@ -3774,8 +3774,8 @@
 	printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
 	       btv->c.nr,
 	       (unsigned long)btv->main.dma,
-	       (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
-	       (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
+	       (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
+	       (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
 	       (unsigned long)rc);
 
 	if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
@@ -4188,6 +4188,7 @@
 	vfd->dev     = &btv->c.pci->dev;
 	vfd->release = video_device_release;
 	vfd->type    = type;
+	vfd->debug   = bttv_debug;
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
 		 type_name, bttv_tvcards[btv->c.type].name);
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 4d5b803..bcd2cd2 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -36,11 +36,6 @@
 #include <linux/jiffies.h>
 #include <asm/io.h>
 
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
-static struct i2c_adapter bttv_i2c_adap_sw_template;
-static struct i2c_adapter bttv_i2c_adap_hw_template;
-static struct i2c_client bttv_i2c_client_template;
-
 static int attach_inform(struct i2c_client *client);
 
 static int i2c_debug;
@@ -104,7 +99,7 @@
 	return state;
 }
 
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
+static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
 	.setsda  = bttv_bit_setsda,
 	.setscl  = bttv_bit_setscl,
 	.getsda  = bttv_bit_getsda,
@@ -113,14 +108,6 @@
 	.timeout = 200,
 };
 
-static struct i2c_adapter bttv_i2c_adap_sw_template = {
-	.owner             = THIS_MODULE,
-	.class             = I2C_CLASS_TV_ANALOG,
-	.name              = "bttv",
-	.id                = I2C_HW_B_BT848,
-	.client_register   = attach_inform,
-};
-
 /* ----------------------------------------------------------------------- */
 /* I2C functions - hardware i2c                                            */
 
@@ -270,20 +257,11 @@
 	return retval;
 }
 
-static struct i2c_algorithm bttv_algo = {
+static const struct i2c_algorithm bttv_algo = {
 	.master_xfer   = bttv_i2c_xfer,
 	.functionality = functionality,
 };
 
-static struct i2c_adapter bttv_i2c_adap_hw_template = {
-	.owner             = THIS_MODULE,
-	.class         = I2C_CLASS_TV_ANALOG,
-	.name          = "bt878",
-	.id            = I2C_HW_B_BT848 /* FIXME */,
-	.algo          = &bttv_algo,
-	.client_register = attach_inform,
-};
-
 /* ----------------------------------------------------------------------- */
 /* I2C functions - common stuff                                            */
 
@@ -332,10 +310,6 @@
 	i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
 }
 
-static struct i2c_client bttv_i2c_client_template = {
-	.name	= "bttv internal",
-};
-
 
 /* read I2C */
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
@@ -417,29 +391,34 @@
 /* init + register i2c algo-bit adapter */
 int __devinit init_bttv_i2c(struct bttv *btv)
 {
-	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
-	       sizeof(bttv_i2c_client_template));
+	strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
 
 	if (i2c_hw)
 		btv->use_i2c_hw = 1;
 	if (btv->use_i2c_hw) {
 		/* bt878 */
-		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
-		       sizeof(bttv_i2c_adap_hw_template));
+		strlcpy(btv->c.i2c_adap.name, "bt878",
+			sizeof(btv->c.i2c_adap.name));
+		btv->c.i2c_adap.id = I2C_HW_B_BT848;	/* FIXME */
+		btv->c.i2c_adap.algo = &bttv_algo;
 	} else {
 		/* bt848 */
 	/* Prevents usage of invalid delay values */
 		if (i2c_udelay<5)
 			i2c_udelay=5;
-		bttv_i2c_algo_bit_template.udelay=i2c_udelay;
 
-		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
-		       sizeof(bttv_i2c_adap_sw_template));
+		strlcpy(btv->c.i2c_adap.name, "bttv",
+			sizeof(btv->c.i2c_adap.name));
+		btv->c.i2c_adap.id = I2C_HW_B_BT848;
 		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
 		       sizeof(bttv_i2c_algo_bit_template));
+		btv->i2c_algo.udelay = i2c_udelay;
 		btv->i2c_algo.data = btv;
 		btv->c.i2c_adap.algo_data = &btv->i2c_algo;
 	}
+	btv->c.i2c_adap.owner = THIS_MODULE;
+	btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
+	btv->c.i2c_adap.client_register = attach_inform;
 
 	btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
 	snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index bfdbc46..68f28e5 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -303,7 +303,7 @@
 	return 0;
 }
 
-int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
@@ -321,7 +321,7 @@
 }
 
 
-int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
@@ -369,7 +369,7 @@
 }
 
 
-int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
 {
 	struct bttv_fh *fh = f;
 	const struct bttv_tvnorm *tvnorm;
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f239320..6d93d16c 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -299,7 +299,6 @@
 /* ---------------------------------------------------------- */
 /* sysfs/driver-moded based gpio access interface             */
 
-
 struct bttv_sub_device {
 	struct device    dev;
 	struct bttv_core *core;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 27da7b4..08ef54a 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -39,7 +39,6 @@
 #include <linux/scatterlist.h>
 #include <asm/io.h>
 #include <media/v4l2-common.h>
-
 #include <linux/device.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/tveeprom.h>
@@ -254,21 +253,19 @@
 /* ---------------------------------------------------------- */
 /* bttv-vbi.c                                                 */
 
-int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
 /* ---------------------------------------------------------- */
 /* bttv-gpio.c */
 
-
 extern struct bus_type bttv_sub_bus_type;
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 
-
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
 
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 5195b1f..d99453f 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -1593,7 +1593,7 @@
 	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
 };
 
-static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_fmtdesc *fmt)
 {
 	struct cafe_camera *cam = priv;
@@ -1608,7 +1608,7 @@
 }
 
 
-static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *fmt)
 {
 	struct cafe_camera *cam = priv;
@@ -1620,7 +1620,7 @@
 	return ret;
 }
 
-static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *fmt)
 {
 	struct cafe_camera *cam = priv;
@@ -1635,7 +1635,7 @@
 	/*
 	 * See if the formatting works in principle.
 	 */
-	ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+	ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
 	if (ret)
 		return ret;
 	/*
@@ -1670,7 +1670,7 @@
  * The V4l2 spec wants us to be smarter, and actually get this from
  * the camera (and not mess with it at open time).  Someday.
  */
-static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
 		struct v4l2_format *f)
 {
 	struct cafe_camera *cam = priv;
@@ -1780,10 +1780,10 @@
 	.release = cafe_v4l_dev_release,
 
 	.vidioc_querycap 	= cafe_vidioc_querycap,
-	.vidioc_enum_fmt_cap	= cafe_vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap	= cafe_vidioc_try_fmt_cap,
-	.vidioc_s_fmt_cap	= cafe_vidioc_s_fmt_cap,
-	.vidioc_g_fmt_cap	= cafe_vidioc_g_fmt_cap,
+	.vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= cafe_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= cafe_vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= cafe_vidioc_g_fmt_vid_cap,
 	.vidioc_enum_input	= cafe_vidioc_enum_input,
 	.vidioc_g_input		= cafe_vidioc_g_input,
 	.vidioc_s_input		= cafe_vidioc_s_input,
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index cefd138..54de0cd 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -884,6 +884,7 @@
 	case VIDIOC_G_INPUT32:
 	case VIDIOC_S_INPUT32:
 	case VIDIOC_TRY_FMT32:
+	case VIDIOC_S_HW_FREQ_SEEK:
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index 0341150..1c3fa3a 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -173,4 +173,3 @@
 	.probe = cs5345_probe,
 	.id_table = cs5345_id,
 };
-
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index d965af8..645b339 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -43,7 +43,6 @@
 
 static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
 
-
 I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
@@ -189,4 +188,3 @@
 	.probe = cs53l32a_probe,
 	.id_table = cs53l32a_id,
 };
-
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
index 1adc404..6d5b94f 100644
--- a/drivers/media/video/cx18/cx18-audio.c
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -26,13 +26,17 @@
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 
+#define CX18_AUDIO_ENABLE 0xc72014
+
 /* Selects the audio input and output according to the current
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 {
 	struct v4l2_routing route;
 	u32 audio_input;
+	u32 val;
 	int mux_input;
+	int err;
 
 	/* Determine which input to use */
 	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
@@ -51,8 +55,17 @@
 	cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 
 	route.input = audio_input;
-	return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+	err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
 			VIDIOC_INT_S_AUDIO_ROUTING, &route);
+	if (err)
+		return err;
+
+	val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+	val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+					(audio_input << 4);
+	write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+	cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+	return 0;
 }
 
 void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
index 2dc3a5d..c40a286 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -34,7 +34,7 @@
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
 	cx18_av_write(cx, 0x127, 0x50);
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		switch (freq) {
 		case 32000:
 			/* VID_PLL and AUX_PLL */
@@ -148,7 +148,7 @@
 	/* Mute everything to prevent the PFFT! */
 	cx18_av_write(cx, 0x8d3, 0x1f);
 
-	if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
 		/* Set Path1 to Serial Audio Input */
 		cx18_av_write4(cx, 0x8d0, 0x01011012);
 
@@ -165,7 +165,7 @@
 	/* deassert soft reset */
 	cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		/* When the microcontroller detects the
 		 * audio format, it will unmute the lines */
 		cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
@@ -271,7 +271,7 @@
 {
 	struct cx18_av_state *state = &cx->av_state;
 
-	if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 		/* Must turn off microcontroller in order to mute sound.
 		 * Not sure if this is the best method, but it does work.
 		 * If the microcontroller is running, then it will undo any
@@ -298,14 +298,14 @@
 
 	switch (cmd) {
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+		if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
 			cx18_av_and_or(cx, 0x803, ~0x10, 0);
 			cx18_av_write(cx, 0x8d3, 0x1f);
 		}
 		cx18_av_and_or(cx, 0x810, ~0x1, 1);
 		retval = set_audclk_freq(cx, *(u32 *)arg);
 		cx18_av_and_or(cx, 0x810, ~0x1, 0);
-		if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+		if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
 			cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
 		return retval;
 
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index faca43e..3b0a2c4 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -69,58 +69,6 @@
 			     or_value);
 }
 
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
-{
-	int retval;
-	u32 saved_reg[8] = {0};
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
-		saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
-		saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
-		saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
-		saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
-		saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
-		saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
-		saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
-		saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
-	}
-
-	retval = cx18_av_write(cx, addr, value);
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
-		cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
-		cx18_av_write4(cx, CXADEC_AFE_CTRL,  saved_reg[1]);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
-		cx18_av_write4(cx, CXADEC_PLL_CTRL1,    saved_reg[2]);
-		cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
-	}
-
-	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
-		cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL,    saved_reg[4]);
-		cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL,     saved_reg[5]);
-		cx18_av_write4(cx, CXADEC_SRC_COMB_CFG,      saved_reg[6]);
-		cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
-	}
-
-	return retval;
-}
-
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
-			   u8 or_value, int no_acfg_mask)
-{
-	return cx18_av_write_no_acfg(cx, addr,
-				     (cx18_av_read(cx, addr) & and_mask) |
-				     or_value, no_acfg_mask);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
@@ -132,6 +80,7 @@
 
 static void cx18_av_initialize(struct cx18 *cx)
 {
+	struct cx18_av_state *state = &cx->av_state;
 	u32 v;
 
 	cx18_av_loadfw(cx);
@@ -211,6 +160,149 @@
 /*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
 /*    } */
 	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+	state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
+	state->default_volume = ((state->default_volume / 2) + 23) << 9;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void cx18_av_std_setup(struct cx18 *cx)
+{
+	struct cx18_av_state *state = &cx->av_state;
+	v4l2_std_id std = state->std;
+	int hblank, hactive, burst, vblank, vactive, sc;
+	int vblank656, src_decimation;
+	int luma_lpf, uv_lpf, comb;
+	u32 pll_int, pll_frac, pll_post;
+
+	/* datasheet startup, step 8d */
+	if (std & ~V4L2_STD_NTSC)
+		cx18_av_write(cx, 0x49f, 0x11);
+	else
+		cx18_av_write(cx, 0x49f, 0x14);
+
+	if (std & V4L2_STD_625_50) {
+		hblank = 132;
+		hactive = 720;
+		burst = 93;
+		vblank = 36;
+		vactive = 580;
+		vblank656 = 40;
+		src_decimation = 0x21f;
+
+		luma_lpf = 2;
+		if (std & V4L2_STD_PAL) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 556453;
+		} else { /* SECAM */
+			uv_lpf = 0;
+			comb = 0;
+			sc = 672351;
+		}
+	} else {
+		hactive = 720;
+		hblank = 122;
+		vactive = 487;
+		luma_lpf = 1;
+		uv_lpf = 1;
+		vblank = 26;
+		vblank656 = 26;
+
+		src_decimation = 0x21f;
+		if (std == V4L2_STD_PAL_60) {
+			burst = 0x5b;
+			luma_lpf = 2;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_M) {
+			burst = 0x61;
+			comb = 0x20;
+			sc = 555452;
+		} else {
+			burst = 0x5b;
+			comb = 0x66;
+			sc = 556063;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	pll_int = cx18_av_read(cx, 0x108);
+	pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+	pll_post = cx18_av_read(cx, 0x109);
+	CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+			pll_int, pll_frac, pll_post);
+
+	if (pll_post) {
+		int fin, fsc;
+		int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+		pll >>= 25;
+		pll /= pll_post;
+		CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+					pll / 1000000, pll % 1000000);
+		CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+					pll / 8000000, (pll / 8) % 1000000);
+
+		fin = ((u64)src_decimation * pll) >> 12;
+		CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+					fin / 1000000, fin % 1000000);
+
+		fsc = (((u64)sc) * pll) >> 24L;
+		CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+					fsc / 1000000, fsc % 1000000);
+
+		CX18_DEBUG_INFO("hblank %i, hactive %i, "
+			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+			" sc 0x%06x\n",
+			hblank, hactive, vblank, vactive, vblank656,
+			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx18_av_write(cx, 0x470, hblank);
+	cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+						(hactive << 4)));
+	cx18_av_write(cx, 0x472, hactive >> 4);
+
+	/* Sets burst gate delay */
+	cx18_av_write(cx, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx18_av_write(cx, 0x474, vblank);
+	cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+						(vactive << 4)));
+	cx18_av_write(cx, 0x476, vactive >> 4);
+	cx18_av_write(cx, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx18_av_write(cx, 0x478, 0xff & src_decimation);
+	cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+	/* Enables comb filters */
+	cx18_av_write(cx, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx18_av_write(cx, 0x47c, sc);
+	cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+	cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+	/* Sets VBI parameters */
+	if (std & V4L2_STD_625_50) {
+		cx18_av_write(cx, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
+	} else {
+		cx18_av_write(cx, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
+	}
 }
 
 /* ----------------------------------------------------------------------- */
@@ -221,16 +313,9 @@
 	v4l2_std_id std = state->std;
 
 	/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
-	if (std & V4L2_STD_SECAM)
-		cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
-	else {
-		cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
-		cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
-	}
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+	cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0);
+	cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
 
 	if (std & V4L2_STD_525_60) {
 		if (std == V4L2_STD_NTSC_M_JP) {
@@ -300,7 +385,8 @@
 	}
 
 	switch (aud_input) {
-	case CX18_AV_AUDIO_SERIAL:
+	case CX18_AV_AUDIO_SERIAL1:
+	case CX18_AV_AUDIO_SERIAL2:
 		/* do nothing, use serial audio input */
 		break;
 	case CX18_AV_AUDIO4: reg &= ~0x30; break;
@@ -316,8 +402,7 @@
 
 	cx18_av_write(cx, 0x103, reg);
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
-				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+	cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
@@ -373,13 +458,13 @@
 	   This happens for example with the Yuan MPC622. */
 	if (fmt >= 4 && fmt < 8) {
 		/* Set format to NTSC-M */
-		cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
+		cx18_av_and_or(cx, 0x400, ~0xf, 1);
 		/* Turn off LCOMB */
 		cx18_av_and_or(cx, 0x47b, ~6, 0);
 	}
-	cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
-	cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
-	cx18_av_vbi_setup(cx);
+	cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
+	cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+	cx18_av_std_setup(cx);
 	input_change(cx);
 	return 0;
 }
@@ -618,6 +703,8 @@
 
 		switch (qc->id) {
 		case V4L2_CID_AUDIO_VOLUME:
+			return v4l2_ctrl_query_fill(qc, 0, 65535,
+				65535 / 100, state->default_volume);
 		case V4L2_CID_AUDIO_MUTE:
 		case V4L2_CID_AUDIO_BALANCE:
 		case V4L2_CID_AUDIO_BASS:
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index c172823..eb61fa1 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -62,7 +62,8 @@
 
 enum cx18_av_audio_input {
 	/* Audio inputs: serial or In4-In8 */
-	CX18_AV_AUDIO_SERIAL,
+	CX18_AV_AUDIO_SERIAL1,
+	CX18_AV_AUDIO_SERIAL2,
 	CX18_AV_AUDIO4 = 4,
 	CX18_AV_AUDIO5,
 	CX18_AV_AUDIO6,
@@ -78,6 +79,7 @@
 	u32 audclk_freq;
 	int audmode;
 	int vbi_line_offset;
+	int default_volume;
 	u32 id;
 	u32 rev;
 	int is_initialized;
@@ -295,25 +297,16 @@
 #define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
 #define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
 
-/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
-#define CXADEC_NO_ACFG_AFE	0x01 /* Preserve 0x100-0x107 */
-#define CXADEC_NO_ACFG_PLL	0x02 /* Preserve 0x108-0x10f */
-#define CXADEC_NO_ACFG_VID	0x04 /* Preserve 0x470-0x47f */
-#define CXADEC_NO_ACFG_ALL	0x07
-
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c 							   */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
-int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
-				int no_acfg_mask);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
-int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
-				int no_acfg_mask);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_std_setup(struct cx18 *cx);
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-firmware.c                                                      */
@@ -326,7 +319,6 @@
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-vbi.c                                                           */
-void cx18_av_vbi_setup(struct cx18 *cx);
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
 
 #endif
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index a1a6af6..834b924 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -22,6 +22,7 @@
 #include "cx18-driver.h"
 #include <linux/firmware.h>
 
+#define CX18_AUDIO_ENABLE 0xc72014
 #define FWFILE "v4l-cx23418-dig.fw"
 
 int cx18_av_loadfw(struct cx18 *cx)
@@ -31,40 +32,58 @@
 	u32 v;
 	const u8 *ptr;
 	int i;
+	int retries = 0;
 
 	if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
 		CX18_ERR("unable to open firmware %s\n", FWFILE);
 		return -EINVAL;
 	}
 
-	cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
-	cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
+	/* The firmware load often has byte errors, so allow for several
+	   retries, both at byte level and at the firmware load level. */
+	while (retries < 5) {
+		cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+		cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
 
-	/* Reset the Mako core (Register is undocumented.) */
-	cx18_av_write4(cx, 0x8100, 0x00010000);
+		/* Reset the Mako core (Register is undocumented.) */
+		cx18_av_write4(cx, 0x8100, 0x00010000);
 
-	/* Put the 8051 in reset and enable firmware upload */
-	cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+		/* Put the 8051 in reset and enable firmware upload */
+		cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
 
-	ptr = fw->data;
-	size = fw->size;
+		ptr = fw->data;
+		size = fw->size;
 
-	for (i = 0; i < size; i++) {
-		u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
-		u32 value = 0;
-		int retries;
+		for (i = 0; i < size; i++) {
+			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+			u32 value = 0;
+			int retries;
 
-		for (retries = 0; retries < 5; retries++) {
-			cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
-			value = cx18_av_read4(cx, CXADEC_DL_CTL);
-			if ((value & 0x3F00) == (dl_control & 0x3F00))
+			for (retries = 0; retries < 5; retries++) {
+				cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+				udelay(10);
+				value = cx18_av_read4(cx, CXADEC_DL_CTL);
+				if (value == dl_control)
+					break;
+				/* Check if we can correct the byte by changing
+				   the address.  We can only write the lower
+				   address byte of the address. */
+				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+					retries = 5;
+					break;
+				}
+			}
+			if (retries >= 5)
 				break;
 		}
-		if (retries >= 5) {
-			CX18_ERR("unable to load firmware %s\n", FWFILE);
-			release_firmware(fw);
-			return -EIO;
-		}
+		if (i == size)
+			break;
+		retries++;
+	}
+	if (retries >= 5) {
+		CX18_ERR("unable to load firmware %s\n", FWFILE);
+		release_firmware(fw);
+		return -EIO;
 	}
 
 	cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
@@ -100,7 +119,6 @@
 	   have a name in the spec. */
 	cx18_av_write4(cx, 0x09CC, 1);
 
-#define CX18_AUDIO_ENABLE            	0xc72014
 	v = read_reg(CX18_AUDIO_ENABLE);
 	/* If bit 11 is 1 */
 	if (v & 0x800)
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
index d09f1da..02fdf57 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -83,150 +83,6 @@
 	return err & 0xf0;
 }
 
-void cx18_av_vbi_setup(struct cx18 *cx)
-{
-	struct cx18_av_state *state = &cx->av_state;
-	v4l2_std_id std = state->std;
-	int hblank, hactive, burst, vblank, vactive, sc;
-	int vblank656, src_decimation;
-	int luma_lpf, uv_lpf, comb;
-	u32 pll_int, pll_frac, pll_post;
-
-	/* datasheet startup, step 8d */
-	if (std & ~V4L2_STD_NTSC)
-		cx18_av_write(cx, 0x49f, 0x11);
-	else
-		cx18_av_write(cx, 0x49f, 0x14);
-
-	if (std & V4L2_STD_625_50) {
-		hblank = 0x084;
-		hactive = 0x2d0;
-		burst = 0x5d;
-		vblank = 0x024;
-		vactive = 0x244;
-		vblank656 = 0x28;
-		src_decimation = 0x21f;
-
-		luma_lpf = 2;
-		if (std & V4L2_STD_SECAM) {
-			uv_lpf = 0;
-			comb = 0;
-			sc = 0x0a425f;
-		} else if (std == V4L2_STD_PAL_Nc) {
-			uv_lpf = 1;
-			comb = 0x20;
-			sc = 556453;
-		} else {
-			uv_lpf = 1;
-			comb = 0x20;
-			sc = 0x0a8263;
-		}
-	} else {
-		hactive = 720;
-		hblank = 122;
-		vactive = 487;
-		luma_lpf = 1;
-		uv_lpf = 1;
-
-		src_decimation = 0x21f;
-		if (std == V4L2_STD_PAL_60) {
-			vblank = 26;
-			vblank656 = 26;
-			burst = 0x5b;
-			luma_lpf = 2;
-			comb = 0x20;
-			sc = 0x0a8263;
-		} else if (std == V4L2_STD_PAL_M) {
-			vblank = 20;
-			vblank656 = 24;
-			burst = 0x61;
-			comb = 0x20;
-
-			sc = 555452;
-		} else {
-			vblank = 26;
-			vblank656 = 26;
-			burst = 0x5b;
-			comb = 0x66;
-			sc = 556063;
-		}
-	}
-
-	/* DEBUG: Displays configured PLL frequency */
-	pll_int = cx18_av_read(cx, 0x108);
-	pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
-	pll_post = cx18_av_read(cx, 0x109);
-	CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
-			pll_int, pll_frac, pll_post);
-
-	if (pll_post) {
-		int fin, fsc;
-		int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
-
-		pll >>= 25;
-		pll /= pll_post;
-		CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
-					pll / 1000000, pll % 1000000);
-		CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
-					pll / 8000000, (pll / 8) % 1000000);
-
-		fin = ((u64)src_decimation * pll) >> 12;
-		CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
-					fin / 1000000, fin % 1000000);
-
-		fsc = (((u64)sc) * pll) >> 24L;
-		CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
-					fsc / 1000000, fsc % 1000000);
-
-		CX18_DEBUG_INFO("hblank %i, hactive %i, "
-			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
-			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
-			" sc 0x%06x\n",
-			hblank, hactive, vblank, vactive, vblank656,
-			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
-	}
-
-	/* Sets horizontal blanking delay and active lines */
-	cx18_av_write(cx, 0x470, hblank);
-	cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
-						(hactive << 4)));
-	cx18_av_write(cx, 0x472, hactive >> 4);
-
-	/* Sets burst gate delay */
-	cx18_av_write(cx, 0x473, burst);
-
-	/* Sets vertical blanking delay and active duration */
-	cx18_av_write(cx, 0x474, vblank);
-	cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
-						(vactive << 4)));
-	cx18_av_write(cx, 0x476, vactive >> 4);
-	cx18_av_write(cx, 0x477, vblank656);
-
-	/* Sets src decimation rate */
-	cx18_av_write(cx, 0x478, 0xff & src_decimation);
-	cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
-
-	/* Sets Luma and UV Low pass filters */
-	cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
-
-	/* Enables comb filters */
-	cx18_av_write(cx, 0x47b, comb);
-
-	/* Sets SC Step*/
-	cx18_av_write(cx, 0x47c, sc);
-	cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
-	cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
-
-	/* Sets VBI parameters */
-	if (std & V4L2_STD_625_50) {
-		cx18_av_write(cx, 0x47f, 0x01);
-		state->vbi_line_offset = 5;
-	} else {
-		cx18_av_write(cx, 0x47f, 0x00);
-		state->vbi_line_offset = 8;
-	}
-}
-
 int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
 {
 	struct cx18_av_state *state = &cx->av_state;
@@ -292,8 +148,8 @@
 			/* raw VBI */
 			memset(svbi, 0, sizeof(*svbi));
 
-			/* Setup VBI */
-			cx18_av_vbi_setup(cx);
+			/* Setup standard */
+			cx18_av_std_setup(cx);
 
 			/* VBI Offset */
 			cx18_av_write(cx, 0x47f, vbi_offset);
@@ -304,8 +160,8 @@
 		for (x = 0; x <= 23; x++)
 			lcr[x] = 0x00;
 
-		/* Setup VBI */
-		cx18_av_vbi_setup(cx);
+		/* Setup standard */
+		cx18_av_std_setup(cx);
 
 		/* Sliced VBI */
 		cx18_av_write(cx, 0x404, 0x32);	/* Ancillary data */
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index c26e0ef..8fe5f38 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -27,6 +27,8 @@
 #include "cx18-i2c.h"
 #include <media/cs5345.h>
 
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
 /********************** card configuration *******************************/
 
 /* usual i2c tuner addresses to probe */
@@ -65,12 +67,12 @@
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
 	.ddr = {
 		/* ESMT M13S128324A-5B memory */
 		.chip_config = 0x003,
@@ -86,6 +88,7 @@
 		.active_lo_mask = 0x3001,
 		.msecs_asserted = 10,
 		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
 	},
 	.i2c = &cx18_i2c_std,
 };
@@ -110,12 +113,12 @@
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
+		  CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
+			 CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
 	.ddr = {
 		/* Samsung K4D263238G-VC33 memory */
 		.chip_config = 0x003,
@@ -131,6 +134,7 @@
 		.active_lo_mask = 0x3001,
 		.msecs_asserted = 10,
 		.msecs_recovery = 40,
+		.ir_reset_mask  = 0x0001,
 	},
 	.i2c = &cx18_i2c_std,
 };
@@ -161,10 +165,10 @@
 		{ CX18_CARD_INPUT_AUD_TUNER,
 		  CX18_AV_AUDIO8, 0 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX18_AV_AUDIO_SERIAL, 0 },
+		  CX18_AV_AUDIO_SERIAL1, 0 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX18_AV_AUDIO_SERIAL, 0 },
+			 CX18_AV_AUDIO_SERIAL1, 0 },
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
@@ -194,7 +198,7 @@
 static const struct cx18_card cx18_card_mpc718 = {
 	.type = CX18_CARD_YUAN_MPC718,
 	.name = "Yuan MPC718",
-	.comment = "Some Composite and S-Video inputs are currently working.\n",
+	.comment = "Analog video capture works; some audio line in may not.\n",
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_all = CX18_HW_TUNER,
@@ -209,11 +213,11 @@
 		{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
 	},
 	.audio_inputs = {
-		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,       0 },
-		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL, 0 },
-		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL, 0 },
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 0 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL1, 0 },
 	},
-	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
 	.tuners = {
 		/* XC3028 tuner */
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -227,16 +231,73 @@
 		.tune_lane = 0,
 		.initial_emrs = 2,
 	},
-	.xceive_pin = 15,
+	.xceive_pin = 0,
 	.pci_list = cx18_pci_mpc718,
 	.i2c = &cx18_i2c_std,
 };
 
+/* ------------------------------------------------------------------------- */
+
+/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+	.type = CX18_CARD_CNXT_RAPTOR_PAL,
+	.name = "Conexant Raptor PAL/SECAM",
+	.comment = "VBI is not yet supported\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_CX23418,
+	.hw_muxer = CX18_HW_GPIO,
+	.hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+			CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL2, 1 },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
+	.ddr = {
+		/* MT 46V16M16 memory */
+		.chip_config = 0x50306,
+		.refresh = 0x753,
+		.timing1 = 0x33220953,
+		.timing2 = 0x09,
+		.tune_lane = 0,
+		.initial_emrs = 0,
+	},
+	.gpio_init.initial_value = 0x1002,
+	.gpio_init.direction = 0xf002,
+	.gpio_audio_input = { .mask   = 0xf002,
+			      .tuner  = 0x1002,   /* LED D1  Tuner AF  */
+			      .linein = 0x2000,   /* LED D2  Line In 1 */
+			      .radio  = 0x4002 }, /* LED D3  Tuner AF  */
+	.pci_list = cx18_pci_cnxt_raptor_pal,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_samsung,
 	&cx18_card_h900,
 	&cx18_card_mpc718,
+	&cx18_card_cnxt_raptor_pal,
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index dc2dd94..32155f6 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -83,6 +83,14 @@
 	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
 	int msecs_asserted; /* time period reset must remain asserted */
 	int msecs_recovery; /* time after deassert for chips to be ready */
+	u32 ir_reset_mask;  /* GPIO to reset the Zilog Z8F0811 IR contoller */
+};
+
+struct cx18_gpio_audio_input { 	/* select tuner/line in input */
+	u32 mask; 		/* leave to 0 if not supported */
+	u32 tuner;
+	u32 linein;
+	u32 radio;
 };
 
 struct cx18_card_tuner {
@@ -123,6 +131,7 @@
 	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
 	struct cx18_gpio_init 		 gpio_init;
 	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
+	struct cx18_gpio_audio_input    gpio_audio_input;
 
 	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
 	struct cx18_card_tuner_i2c *i2c;
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 87cf410..f46c7e5 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -51,12 +51,11 @@
 	NULL
 };
 
-static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	const char *name;
 
-	CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
-
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	if (qctrl->id == 0)
 		return -EINVAL;
@@ -91,21 +90,35 @@
 	return 0;
 }
 
-static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	struct v4l2_queryctrl qctrl;
 
 	qctrl.id = qmenu->id;
-	cx18_queryctrl(cx, &qctrl);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+	cx18_queryctrl(file, fh, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+			cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
+}
+
+static int cx18_try_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_control *vctrl)
+{
+	struct v4l2_queryctrl qctrl;
+	const char **menu_items = NULL;
+	int err;
+
+	qctrl.id = vctrl->id;
+	err = cx18_queryctrl(file, fh, &qctrl);
+	if (err)
+		return err;
+	if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+		menu_items = v4l2_ctrl_get_menu(qctrl.id);
+	return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
 }
 
 static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 {
-	s32 v = vctrl->value;
-
-	CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
-
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
@@ -123,7 +136,7 @@
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
 
 	default:
-		CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -131,8 +144,6 @@
 
 static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
 {
-	CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
@@ -149,7 +160,7 @@
 	case V4L2_CID_AUDIO_LOUDNESS:
 		return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
 	default:
-		CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -194,113 +205,110 @@
 	return 0;
 }
 
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 {
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 	struct v4l2_control ctrl;
 
-	switch (cmd) {
-	case VIDIOC_QUERYMENU:
-		CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
-		return cx18_querymenu(cx, arg);
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
 
-	case VIDIOC_QUERYCTRL:
-		return cx18_queryctrl(cx, arg);
-
-	case VIDIOC_S_CTRL:
-		return cx18_s_ctrl(cx, arg);
-
-	case VIDIOC_G_CTRL:
-		return cx18_g_ctrl(cx, arg);
-
-	case VIDIOC_S_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
-
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = cx18_s_ctrl(cx, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = cx18_g_ctrl(cx, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
-			return err;
 		}
-		CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-			struct cx2341x_mpeg_params p = cx->params;
-			int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
+		return err;
+	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
+	return -EINVAL;
+}
 
-			if (err)
-				return err;
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+	struct v4l2_control ctrl;
 
-			if (p.video_encoding != cx->params.video_encoding) {
-				int is_mpeg1 = p.video_encoding ==
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
+
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = cx18_s_ctrl(cx, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
+			}
+		}
+		return err;
+	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		struct cx2341x_mpeg_params p = cx->params;
+		int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
+						c, VIDIOC_S_EXT_CTRLS);
+
+		if (err)
+			return err;
+
+		if (p.video_encoding != cx->params.video_encoding) {
+			int is_mpeg1 = p.video_encoding ==
 						V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
-				struct v4l2_format fmt;
+			struct v4l2_format fmt;
 
-				/* fix videodecoder resolution */
-				fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-				fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
-				fmt.fmt.pix.height = cx->params.height;
-				cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
-			}
-			err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
-			if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
-				err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
-			cx->params = p;
-			cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-			cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
-			return err;
+			/* fix videodecoder resolution */
+			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			fmt.fmt.pix.width = cx->params.width
+						/ (is_mpeg1 ? 2 : 1);
+			fmt.fmt.pix.height = cx->params.height;
+			cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
 		}
-		return -EINVAL;
+		err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+		if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+			err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+		cx->params = p;
+		cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+		cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+		return err;
 	}
+	return -EINVAL;
+}
 
-	case VIDIOC_G_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
+int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
 
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = cx18_g_ctrl(cx, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
+		for (i = 0; i < c->count; i++) {
+			err = cx18_try_ctrl(file, fh, &c->controls[i]);
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
-			return err;
 		}
-		CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
-		return -EINVAL;
+		return err;
 	}
-
-	case VIDIOC_TRY_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&cx->params,
-					atomic_read(&cx->ana_capturing), arg, cmd);
-		return -EINVAL;
-	}
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&cx->params,
+						atomic_read(&cx->ana_capturing),
+						c, VIDIOC_TRY_EXT_CTRLS);
+	return -EINVAL;
 }
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h
index 6e985cf..e463237 100644
--- a/drivers/media/video/cx18/cx18-controls.h
+++ b/drivers/media/video/cx18/cx18-controls.h
@@ -21,4 +21,9 @@
  *  02111-1307  USA
  */
 
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_try_ext_ctrls(struct file *file, void *fh,
+			struct v4l2_ext_controls *a);
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 2b810bb..22434aa 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -120,6 +120,7 @@
 		 "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
 		 "\t\t\t 3 = Compro VideoMate H900\n"
 		 "\t\t\t 4 = Yuan MPC718\n"
+		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -420,6 +421,7 @@
 	mutex_init(&cx->serialize_lock);
 	mutex_init(&cx->i2c_bus_lock[0]);
 	mutex_init(&cx->i2c_bus_lock[1]);
+	mutex_init(&cx->gpio_lock);
 
 	spin_lock_init(&cx->lock);
 	spin_lock_init(&cx->dma_reg_lock);
@@ -435,7 +437,7 @@
 		(cx->params.video_temporal_filter_mode << 1) |
 		(cx->params.video_median_filter_type << 2);
 	cx->params.port = CX2341X_PORT_MEMORY;
-	cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+	cx->params.capabilities = CX2341X_CAP_HAS_TS;
 	init_waitqueue_head(&cx->cap_w);
 	init_waitqueue_head(&cx->mb_apu_waitq);
 	init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -614,7 +616,7 @@
 	cx18_cards[cx18_cards_active] = cx;
 	cx->dev = dev;
 	cx->num = cx18_cards_active++;
-	snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
+	snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
 	CX18_INFO("Initializing card #%d\n", cx->num);
 
 	spin_unlock(&cx18_cards_lock);
@@ -721,6 +723,12 @@
 	/* if no tuner was found, then pick the first tuner in the card list */
 	if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
 		cx->std = cx->card->tuners[0].std;
+		if (cx->std & V4L2_STD_PAL)
+			cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		else if (cx->std & V4L2_STD_NTSC)
+			cx->std = V4L2_STD_NTSC_M;
+		else if (cx->std & V4L2_STD_SECAM)
+			cx->std = V4L2_STD_SECAM_L;
 		cx->options.tuner = cx->card->tuners[0].tuner;
 	}
 	if (cx->options.radio == -1)
@@ -818,6 +826,9 @@
 	int video_input;
 	int fw_retry_count = 3;
 	struct v4l2_frequency vf;
+	struct cx18_open_id fh;
+
+	fh.cx = cx;
 
 	if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
 		return -ENXIO;
@@ -869,13 +880,13 @@
 
 	video_input = cx->active_input;
 	cx->active_input++;	/* Force update of input */
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+	cx18_s_input(NULL, &fh, video_input);
 
 	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
 	   in one place. */
 	cx->std++;		/* Force full standard initialization */
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
-	cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+	cx18_s_std(NULL, &fh, &cx->tuner_std);
+	cx18_s_frequency(NULL, &fh, &vf);
 	return 0;
 }
 
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index de14ab5..45e31b0 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -75,7 +75,8 @@
 #define CX18_CARD_HVR_1600_SAMSUNG    1	/* Hauppauge HVR 1600 (Samsung memory) */
 #define CX18_CARD_COMPRO_H900 	      2	/* Compro VideoMate H900 */
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
-#define CX18_CARD_LAST 		      3
+#define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
+#define CX18_CARD_LAST 		      4
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -94,6 +95,7 @@
 #define CX18_PCI_ID_HAUPPAUGE 		0x0070
 #define CX18_PCI_ID_COMPRO 		0x185b
 #define CX18_PCI_ID_YUAN 		0x12ab
+#define CX18_PCI_ID_CONEXANT		0x14f1
 
 /* ======================================================================== */
 /* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -228,9 +230,7 @@
 	struct dvb_net dvbnet;
 	int enabled;
 	int feeding;
-
 	struct mutex feedlock;
-
 };
 
 struct cx18;	 /* forward reference */
@@ -427,6 +427,7 @@
 	/* gpio */
 	u32 gpio_dir;
 	u32 gpio_val;
+	struct mutex gpio_lock;
 
 	/* v4l2 and User settings */
 
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 2694ce3..2d630d9 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -41,9 +41,6 @@
 
 #define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
 
-#define CX18_AUDIO_ENABLE            	0xc72014
-#define CX18_REG_BUS_TIMEOUT_EN      	0xc72024
-
 #define CX18_FAST_CLOCK_PLL_INT      	0xc78000
 #define CX18_FAST_CLOCK_PLL_FRAC     	0xc78004
 #define CX18_FAST_CLOCK_PLL_POST     	0xc78008
@@ -90,7 +87,7 @@
 #define CX18_DSP0_INTERRUPT_MASK     	0xd0004C
 
 /* Encoder/decoder firmware sizes */
-#define CX18_FW_CPU_SIZE 		(174716)
+#define CX18_FW_CPU_SIZE 		(158332)
 #define CX18_FW_APU_SIZE 		(141200)
 
 #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
@@ -345,6 +342,11 @@
 		int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
 			       cx->enc_mem, cx, CX18_FW_APU_SIZE);
 
+		write_enc(0xE51FF004, 0);
+		write_enc(0xa00000, 4);  /* todo: not hardcoded */
+		write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+		cx18_msleep_timeout(500, 0);
+
 		sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
 					cx->enc_mem, cx, CX18_FW_CPU_SIZE);
 
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index b302833..3d495db 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -69,6 +69,7 @@
 	/* Assuming that the masks are a subset of the bits in gpio_dir */
 
 	/* Assert */
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val =
 		(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
 	gpio_write(cx);
@@ -79,10 +80,53 @@
 		(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
 	gpio_write(cx);
 	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+	mutex_unlock(&cx->gpio_lock);
 }
 
+void cx18_reset_ir_gpio(void *data)
+{
+	struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+	const struct cx18_gpio_i2c_slave_reset *p;
+
+	p = &cx->card->gpio_i2c_slave_reset;
+
+	if (p->ir_reset_mask == 0)
+		return;
+
+	CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+	/*
+	   Assert timing for the Z8F0811 on HVR-1600 boards:
+	   1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
+	   2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
+		(6,601,085 nanoseconds ~= 7 milliseconds)
+	   3. DBG pin must be high before chip exits reset for normal operation.
+		DBG is open drain and hopefully pulled high since we don't
+		normally drive it (GPIO 1?) for the HVR-1600
+	   4. Z8F0811 won't exit reset until RESET is deasserted
+	*/
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+	/*
+	   Zilog comes out of reset, loads reset vector address and executes
+	   from there. Required recovery delay unknown.
+	*/
+	mutex_lock(&cx->gpio_lock);
+	cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
+	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by an infrared module for the IR-blaster */
+
 void cx18_gpio_init(struct cx18 *cx)
 {
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_dir = cx->card->gpio_init.direction;
 	cx->gpio_val = cx->card->gpio_init.initial_value;
 
@@ -91,14 +135,17 @@
 		cx->gpio_val |= 1 << cx->card->xceive_pin;
 	}
 
-	if (cx->gpio_dir == 0)
+	if (cx->gpio_dir == 0) {
+		mutex_unlock(&cx->gpio_lock);
 		return;
+	}
 
 	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
 		   read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
 		   read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
 
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 }
 
 /* Xceive tuner reset function */
@@ -112,13 +159,52 @@
 		return 0;
 	CX18_DEBUG_INFO("Resetting tuner\n");
 
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val &= ~(1 << cx->card->xceive_pin);
-
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 
+	mutex_lock(&cx->gpio_lock);
 	cx->gpio_val |= 1 << cx->card->xceive_pin;
 	gpio_write(cx);
+	mutex_unlock(&cx->gpio_lock);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	return 0;
 }
+
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+{
+	struct v4l2_routing *route = arg;
+	u32 mask, data;
+
+	switch (command) {
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+		if (route->input > 2)
+			return -EINVAL;
+		mask = cx->card->gpio_audio_input.mask;
+		switch (route->input) {
+		case 0:
+			data = cx->card->gpio_audio_input.tuner;
+			break;
+		case 1:
+			data = cx->card->gpio_audio_input.linein;
+			break;
+		case 2:
+		default:
+			data = cx->card->gpio_audio_input.radio;
+			break;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	if (mask) {
+		mutex_lock(&cx->gpio_lock);
+		cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+		gpio_write(cx);
+		mutex_unlock(&cx->gpio_lock);
+	}
+	return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 525c328..22cd7dd 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -22,4 +22,6 @@
 
 void cx18_gpio_init(struct cx18 *cx);
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
+void cx18_reset_ir_gpio(void *data);
 int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 680bc4e..6023ba3 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -39,10 +39,6 @@
 #define GETSCL_BIT      0x0004
 #define GETSDL_BIT      0x0008
 
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif
-
 #define CX18_CS5345_I2C_ADDR		0x4c
 
 /* This array should match the CX18_HW_ defines */
@@ -311,8 +307,12 @@
 {
 	int addr;
 
-	if (hw == CX18_HW_GPIO || hw == 0)
+	if (hw == 0)
 		return 0;
+
+	if (hw == CX18_HW_GPIO)
+		return cx18_gpio(cx, cmd, arg);
+
 	if (hw == CX18_HW_CX23418)
 		return cx18_av_cmd(cx, cmd, arg);
 
@@ -350,6 +350,8 @@
 	cx18_av_cmd(cx, cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
 	i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+	if (cx->hw_flags & CX18_HW_GPIO)
+		cx18_gpio(cx, cmd, arg);
 }
 
 /* init + register i2c algo-bit adapter */
@@ -358,6 +360,18 @@
 	int i;
 	CX18_DEBUG_I2C("i2c init\n");
 
+	/* Sanity checks for the I2C hardware arrays. They must be the
+	 * same size and GPIO/CX23418 must be the last entries.
+	 */
+	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+	    CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+	    CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+		CX18_ERR("Mismatched I2C hardware arrays\n");
+		return -ENODEV;
+	}
+
 	for (i = 0; i < 2; i++) {
 		memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
 			sizeof(struct i2c_adapter));
@@ -391,6 +405,7 @@
 	write_reg_sync(0x00c000c0, 0xc7001c);
 	mdelay(10);
 	write_reg_sync(0x00c00000, 0xc7001c);
+	mdelay(10);
 
 	write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
 	write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 4151f1e..0d74e59 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -100,19 +100,6 @@
 	}
 }
 
-static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
-{
-	int f, l;
-	u16 set = 0;
-
-	for (f = 0; f < 2; f++) {
-		for (l = 0; l < 24; l++) {
-			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
-			set |= fmt->service_lines[f][l];
-		}
-	}
-	return set != 0;
-}
 
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 {
@@ -126,35 +113,167 @@
 	return set;
 }
 
-static const struct {
-	v4l2_std_id  std;
-	char        *name;
-} enum_stds[] = {
-	{ V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
-	{ V4L2_STD_PAL_DK,    "PAL-DK"    },
-	{ V4L2_STD_PAL_I,     "PAL-I"     },
-	{ V4L2_STD_PAL_M,     "PAL-M"     },
-	{ V4L2_STD_PAL_N,     "PAL-N"     },
-	{ V4L2_STD_PAL_Nc,    "PAL-Nc"    },
-	{ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
-	{ V4L2_STD_SECAM_DK,  "SECAM-DK"  },
-	{ V4L2_STD_SECAM_L,   "SECAM-L"   },
-	{ V4L2_STD_SECAM_LC,  "SECAM-L'"  },
-	{ V4L2_STD_NTSC_M,    "NTSC-M"    },
-	{ V4L2_STD_NTSC_M_JP, "NTSC-J"    },
-	{ V4L2_STD_NTSC_M_KR, "NTSC-K"    },
-};
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
-static const struct v4l2_standard cx18_std_60hz = {
-	.frameperiod = {.numerator = 1001, .denominator = 30000},
-	.framelines = 525,
-};
+	pixfmt->width = cx->params.width;
+	pixfmt->height = cx->params.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+		pixfmt->sizeimage =
+			pixfmt->height * pixfmt->width +
+			pixfmt->height * (pixfmt->width / 2);
+		pixfmt->bytesperline = 720;
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
 
-static const struct v4l2_standard cx18_std_50hz = {
-	.frameperiod = { .numerator = 1, .denominator = 25 },
-	.framelines = 625,
-};
+static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
 
+	vbifmt->sampling_rate = 27000000;
+	vbifmt->offset = 248;
+	vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+	vbifmt->start[0] = cx->vbi.start[0];
+	vbifmt->start[1] = cx->vbi.start[1];
+	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
+	vbifmt->flags = 0;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	return 0;
+}
+
+static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
+
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	w = min(w, 720);
+	w = max(w, 1);
+	h = min(h, cx->is_50hz ? 576 : 480);
+	h = max(h, 2);
+	cx18_g_fmt_vid_cap(file, fh, fmt);
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return 0;
+}
+
+static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+	if (ret)
+		return ret;
+
+	if (cx->params.width == w && cx->params.height == h)
+		return 0;
+
+	if (atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	cx->params.width = w;
+	cx->params.height = h;
+	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+	return cx18_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+			cx->vbi.sliced_in->service_set &&
+			atomic_read(&cx->ana_capturing) > 0)
+		return -EBUSY;
+
+	cx->vbi.sliced_in->service_set = 0;
+	cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+	return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_format *fmt)
+{
+	return -EINVAL;
+}
+
+static int cx18_g_chip_ident(struct file *file, void *fh,
+				struct v4l2_chip_ident *chip)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+			chip->ident = V4L2_IDENT_CX23418;
+		return 0;
+	}
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
+					chip);
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+		return cx18_call_i2c_client(cx, chip->match_chip,
+						VIDIOC_G_CHIP_IDENT, chip);
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 {
 	struct v4l2_register *regs = arg;
@@ -174,570 +293,473 @@
 	return 0;
 }
 
-static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
+static int cx18_g_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
 {
-	switch (fmt->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		fmt->fmt.pix.width = cx->params.width;
-		fmt->fmt.pix.height = cx->params.height;
-		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-		if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-			fmt->fmt.pix.sizeimage =
-				fmt->fmt.pix.height * fmt->fmt.pix.width +
-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-		} else {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-			fmt->fmt.pix.sizeimage = 128 * 1024;
-		}
-		break;
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		fmt->fmt.vbi.sampling_rate = 27000000;
-		fmt->fmt.vbi.offset = 248;
-		fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
-		fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-		fmt->fmt.vbi.start[0] = cx->vbi.start[0];
-		fmt->fmt.vbi.start[1] = cx->vbi.start[1];
-		fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
-		break;
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+					reg);
+	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+					reg);
+}
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-	{
-		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int cx18_s_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
-		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+					reg);
+	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+					reg);
+}
+#endif
 
-		cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
-		vbifmt->service_set = cx18_get_service_set(vbifmt);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
+static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	*p = v4l2_prio_max(&cx->prio);
 	return 0;
 }
 
-static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
-		struct v4l2_format *fmt, int set_fmt)
+static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
 {
-	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-	u16 set;
-
-	/* set window size */
-	if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		int w = fmt->fmt.pix.width;
-		int h = fmt->fmt.pix.height;
-
-		if (w > 720)
-			w = 720;
-		else if (w < 1)
-			w = 1;
-		if (h > (cx->is_50hz ? 576 : 480))
-			h = (cx->is_50hz ? 576 : 480);
-		else if (h < 2)
-			h = 2;
-		cx18_get_fmt(cx, streamtype, fmt);
-		fmt->fmt.pix.width = w;
-		fmt->fmt.pix.height = h;
-
-		if (!set_fmt || (cx->params.width == w && cx->params.height == h))
-			return 0;
-		if (atomic_read(&cx->ana_capturing) > 0)
-			return -EBUSY;
-
-		cx->params.width = w;
-		cx->params.height = h;
-		if (w != 720 || h != (cx->is_50hz ? 576 : 480))
-			cx->params.video_temporal_filter = 0;
-		else
-			cx->params.video_temporal_filter = 8;
-		cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
-		return cx18_get_fmt(cx, streamtype, fmt);
-	}
-
-	/* set raw VBI format */
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
-		    cx->vbi.sliced_in->service_set &&
-		    atomic_read(&cx->ana_capturing) > 0)
-			return -EBUSY;
-		if (set_fmt) {
-			cx->vbi.sliced_in->service_set = 0;
-			cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
-		}
-		return cx18_get_fmt(cx, streamtype, fmt);
-	}
-
-	/* any else but sliced VBI capture is an error */
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-
-	/* TODO: implement sliced VBI, for now silently return 0 */
-	return 0;
-
-	/* set sliced VBI capture format */
-	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-	memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-
-	if (vbifmt->service_set)
-		cx18_expand_service_set(vbifmt, cx->is_50hz);
-	set = check_service_set(vbifmt, cx->is_50hz);
-	vbifmt->service_set = cx18_get_service_set(vbifmt);
-
-	if (!set_fmt)
-		return 0;
-	if (set == 0)
-		return -EINVAL;
-	if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
-		return -EBUSY;
-	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
-	memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
-	return 0;
-}
-
-static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
-{
-	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+	struct cx18_open_id *id = fh;
 	struct cx18 *cx = id->cx;
-	struct v4l2_register *reg = arg;
+
+	return v4l2_prio_change(&cx->prio, &id->prio, prio);
+}
+
+static int cx18_querycap(struct file *file, void *fh,
+				struct v4l2_capability *vcap)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+	strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+	vcap->version = CX18_DRIVER_VERSION; 	    /* version */
+	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
+	return 0;
+}
+
+static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
+
+static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	vin->index = cx->audio_input;
+	return cx18_get_audio_input(cx, vin->index, vin);
+}
+
+static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (vout->index >= cx->nof_audio_inputs)
+		return -EINVAL;
+	cx->audio_input = vout->index;
+	cx18_audio_set_io(cx);
+	return 0;
+}
+
+static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	/* set it to defaults from our table */
+	return cx18_get_input(cx, vin->index, vin);
+}
+
+static int cx18_cropcap(struct file *file, void *fh,
+			struct v4l2_cropcap *cropcap)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+	cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+	cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+}
+
+static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+}
+
+static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+					struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+		  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
+		},
+		{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
+		}
+	};
+
+	if (fmt->index > 1)
+		return -EINVAL;
+	*fmt = formats[fmt->index];
+	return 0;
+}
+
+static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	*i = cx->active_input;
+	return 0;
+}
+
+int cx18_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (inp < 0 || inp >= cx->nof_inputs)
+		return -EINVAL;
+
+	if (inp == cx->active_input) {
+		CX18_DEBUG_INFO("Input unchanged\n");
+		return 0;
+	}
+
+	CX18_DEBUG_INFO("Changing input from %d to %d\n",
+			cx->active_input, inp);
+
+	cx->active_input = inp;
+	/* Set the audio input to whatever is appropriate for the input type. */
+	cx->audio_input = cx->card->video_inputs[inp].audio_index;
+
+	/* prevent others from messing with the streams until
+	   we're finished changing inputs. */
+	cx18_mute(cx);
+	cx18_video_set_io(cx);
+	cx18_audio_set_io(cx);
+	cx18_unmute(cx);
+	return 0;
+}
+
+static int cx18_g_frequency(struct file *file, void *fh,
+				struct v4l2_frequency *vf)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+	return 0;
+}
+
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	cx18_mute(cx);
+	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+	cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+	cx18_unmute(cx);
+	return 0;
+}
+
+static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	*std = cx->std;
+	return 0;
+}
+
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if ((*std & V4L2_STD_ALL) == 0)
+		return -EINVAL;
+
+	if (*std == cx->std)
+		return 0;
+
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+	    atomic_read(&cx->ana_capturing) > 0) {
+		/* Switching standard would turn off the radio or mess
+		   with already running streams, prevent that by
+		   returning EBUSY. */
+		return -EBUSY;
+	}
+
+	cx->std = *std;
+	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+	cx->params.width = 720;
+	cx->params.height = cx->is_50hz ? 576 : 480;
+	cx->vbi.count = cx->is_50hz ? 18 : 12;
+	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+	cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+	CX18_DEBUG_INFO("Switching standard to %llx.\n",
+			(unsigned long long) cx->std);
+
+	/* Tuner */
+	cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+	return 0;
+}
+
+static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+	int ret;
+
+	ret = v4l2_prio_check(&cx->prio, &id->prio);
+	if (ret)
+		return ret;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	/* Setting tuner can only set audio mode */
+	cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+
+	return 0;
+}
+
+static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+		strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_RADIO;
+	} else {
+		strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_ANALOG_TV;
+	}
+
+	return 0;
+}
+
+static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+					struct v4l2_sliced_vbi_cap *cap)
+{
+	return -EINVAL;
+}
+
+static int cx18_g_enc_index(struct file *file, void *fh,
+				struct v4l2_enc_idx *idx)
+{
+	return -EINVAL;
+}
+
+static int cx18_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18_open_id *id = fh;
+	struct cx18 *cx = id->cx;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return cx18_start_capture(id);
+
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		cx18_stop_capture(id,
+				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+		break;
+
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		cx18_mute(cx);
+		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		if (!atomic_read(&cx->ana_capturing))
+			return -EPERM;
+		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+			return 0;
+		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+		cx18_unmute(cx);
+		break;
+
+	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx18_try_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		break;
+
+	case V4L2_ENC_CMD_STOP:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		break;
+
+	case V4L2_ENC_CMD_PAUSE:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		break;
+
+	default:
+		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx18_log_status(struct file *file, void *fh)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+	struct v4l2_input vidin;
+	struct v4l2_audio audin;
+	int i;
+
+	CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
+	if (cx->hw_flags & CX18_HW_TVEEPROM) {
+		struct tveeprom tv;
+
+		cx18_read_eeprom(cx, &tv);
+	}
+	cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+	cx18_get_input(cx, cx->active_input, &vidin);
+	cx18_get_audio_input(cx, cx->audio_input, &audin);
+	CX18_INFO("Video Input: %s\n", vidin.name);
+	CX18_INFO("Audio Input: %s\n", audin.name);
+	mutex_lock(&cx->gpio_lock);
+	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",
+		cx->gpio_dir, cx->gpio_val);
+	mutex_unlock(&cx->gpio_lock);
+	CX18_INFO("Tuner: %s\n",
+		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
+	cx2341x_log_status(&cx->params, cx->name);
+	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+	for (i = 0; i < CX18_MAX_STREAMS; i++) {
+		struct cx18_stream *s = &cx->streams[i];
+
+		if (s->v4l2dev == NULL || s->buffers == 0)
+			continue;
+		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+			  s->name, s->s_flags,
+			  (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+			  (s->buffers * s->buf_size) / 1024, s->buffers);
+	}
+	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+			(long long)cx->mpg_data_received,
+			(long long)cx->vbi_data_inserted);
+	CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+	return 0;
+}
+
+static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
+{
+	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
 
 	switch (cmd) {
-	/* ioctls to allow direct access to the encoder registers for testing */
-	case VIDIOC_DBG_G_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return cx18_cxc(cx, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
-	case VIDIOC_DBG_S_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return cx18_cxc(cx, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
-	case VIDIOC_G_CHIP_IDENT: {
-		struct v4l2_chip_ident *chip = arg;
-
-		chip->ident = V4L2_IDENT_NONE;
-		chip->revision = 0;
-		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
-				struct v4l2_chip_ident *chip = arg;
-
-				chip->ident = V4L2_IDENT_CX23418;
-			}
-			return 0;
-		}
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-			return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-		return -EINVAL;
-	}
-
 	case VIDIOC_INT_S_AUDIO_ROUTING: {
 		struct v4l2_routing *route = arg;
 
+		CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
+			route->input, route->output);
 		cx18_audio_set_route(cx, route);
 		break;
 	}
 
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
 
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
-{
-	struct cx18_open_id *id = NULL;
-
-	if (filp)
-		id = (struct cx18_open_id *)filp->private_data;
-
-	switch (cmd) {
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
-
-		*p = v4l2_prio_max(&cx->prio);
-		break;
-	}
-
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
-
-		return v4l2_prio_change(&cx->prio, &id->prio, *prio);
-	}
-
-	case VIDIOC_QUERYCAP:{
-		struct v4l2_capability *vcap = arg;
-
-		memset(vcap, 0, sizeof(*vcap));
-		strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
-		strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
-		strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
-		vcap->version = CX18_DRIVER_VERSION; 	    /* version */
-		vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */
-
-		/* reserved.. must set to 0! */
-		vcap->reserved[0] = vcap->reserved[1] =
-			vcap->reserved[2] = vcap->reserved[3] = 0;
-		break;
-	}
-
-	case VIDIOC_ENUMAUDIO:{
-		struct v4l2_audio *vin = arg;
-
-		return cx18_get_audio_input(cx, vin->index, vin);
-	}
-
-	case VIDIOC_G_AUDIO:{
-		struct v4l2_audio *vin = arg;
-
-		vin->index = cx->audio_input;
-		return cx18_get_audio_input(cx, vin->index, vin);
-	}
-
-	case VIDIOC_S_AUDIO:{
-		struct v4l2_audio *vout = arg;
-
-		if (vout->index >= cx->nof_audio_inputs)
-			return -EINVAL;
-		cx->audio_input = vout->index;
-		cx18_audio_set_io(cx);
-		break;
-	}
-
-	case VIDIOC_ENUMINPUT:{
-		struct v4l2_input *vin = arg;
-
-		/* set it to defaults from our table */
-		return cx18_get_input(cx, vin->index, vin);
-	}
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT: {
-		struct v4l2_format *fmt = arg;
-
-		return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
-	}
-
-	case VIDIOC_G_FMT: {
-		struct v4l2_format *fmt = arg;
-		int type = fmt->type;
-
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->type = type;
-		return cx18_get_fmt(cx, id->type, fmt);
-	}
-
-	case VIDIOC_CROPCAP: {
-		struct v4l2_cropcap *cropcap = arg;
-
-		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		cropcap->bounds.top = cropcap->bounds.left = 0;
-		cropcap->bounds.width = 720;
-		cropcap->bounds.height = cx->is_50hz ? 576 : 480;
-		cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
-		cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
-		cropcap->defrect = cropcap->bounds;
-		return 0;
-	}
-
-	case VIDIOC_S_CROP: {
-		struct v4l2_crop *crop = arg;
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
-	}
-
-	case VIDIOC_G_CROP: {
-		struct v4l2_crop *crop = arg;
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
-	}
-
-	case VIDIOC_ENUM_FMT: {
-		static struct v4l2_fmtdesc formats[] = {
-			{ 0, 0, 0,
-			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
-			  { 0, 0, 0, 0 }
-			},
-			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
-			  "MPEG", V4L2_PIX_FMT_MPEG,
-			  { 0, 0, 0, 0 }
-			}
-		};
-		struct v4l2_fmtdesc *fmt = arg;
-		enum v4l2_buf_type type = fmt->type;
-
-		switch (type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			break;
-		default:
-			return -EINVAL;
-		}
-		if (fmt->index > 1)
-			return -EINVAL;
-		*fmt = formats[fmt->index];
-		fmt->type = type;
-		return 0;
-	}
-
-	case VIDIOC_G_INPUT:{
-		*(int *)arg = cx->active_input;
-		break;
-	}
-
-	case VIDIOC_S_INPUT:{
-		int inp = *(int *)arg;
-
-		if (inp < 0 || inp >= cx->nof_inputs)
-			return -EINVAL;
-
-		if (inp == cx->active_input) {
-			CX18_DEBUG_INFO("Input unchanged\n");
-			break;
-		}
-		CX18_DEBUG_INFO("Changing input from %d to %d\n",
-				cx->active_input, inp);
-
-		cx->active_input = inp;
-		/* Set the audio input to whatever is appropriate for the
-		   input type. */
-		cx->audio_input = cx->card->video_inputs[inp].audio_index;
-
-		/* prevent others from messing with the streams until
-		   we're finished changing inputs. */
-		cx18_mute(cx);
-		cx18_video_set_io(cx);
-		cx18_audio_set_io(cx);
-		cx18_unmute(cx);
-		break;
-	}
-
-	case VIDIOC_G_FREQUENCY:{
-		struct v4l2_frequency *vf = arg;
-
-		if (vf->tuner != 0)
-			return -EINVAL;
-		cx18_call_i2c_clients(cx, cmd, arg);
-		break;
-	}
-
-	case VIDIOC_S_FREQUENCY:{
-		struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
-
-		if (vf.tuner != 0)
-			return -EINVAL;
-
-		cx18_mute(cx);
-		CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
-		cx18_call_i2c_clients(cx, cmd, &vf);
-		cx18_unmute(cx);
-		break;
-	}
-
-	case VIDIOC_ENUMSTD:{
-		struct v4l2_standard *vs = arg;
-		int idx = vs->index;
-
-		if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
-			return -EINVAL;
-
-		*vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
-				cx18_std_60hz : cx18_std_50hz;
-		vs->index = idx;
-		vs->id = enum_stds[idx].std;
-		strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
-		break;
-	}
-
-	case VIDIOC_G_STD:{
-		*(v4l2_std_id *) arg = cx->std;
-		break;
-	}
-
-	case VIDIOC_S_STD: {
-		v4l2_std_id std = *(v4l2_std_id *) arg;
-
-		if ((std & V4L2_STD_ALL) == 0)
-			return -EINVAL;
-
-		if (std == cx->std)
-			break;
-
-		if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
-		    atomic_read(&cx->ana_capturing) > 0) {
-			/* Switching standard would turn off the radio or mess
-			   with already running streams, prevent that by
-			   returning EBUSY. */
-			return -EBUSY;
-		}
-
-		cx->std = std;
-		cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
-		cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
-		cx->params.width = 720;
-		cx->params.height = cx->is_50hz ? 576 : 480;
-		cx->vbi.count = cx->is_50hz ? 18 : 12;
-		cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
-		cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
-		cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
-		CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
-
-		/* Tuner */
-		cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
-		break;
-	}
-
-	case VIDIOC_S_TUNER: {	/* Setting tuner can only set audio mode */
-		struct v4l2_tuner *vt = arg;
-
-		if (vt->index != 0)
-			return -EINVAL;
-
-		cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
-		break;
-	}
-
-	case VIDIOC_G_TUNER: {
-		struct v4l2_tuner *vt = arg;
-
-		if (vt->index != 0)
-			return -EINVAL;
-
-		memset(vt, 0, sizeof(*vt));
-		cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
-
-		if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
-			strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_RADIO;
-		} else {
-			strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_ANALOG_TV;
-		}
-		break;
-	}
-
-	case VIDIOC_G_SLICED_VBI_CAP: {
-		struct v4l2_sliced_vbi_cap *cap = arg;
-		int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
-		int f, l;
-		enum v4l2_buf_type type = cap->type;
-
-		memset(cap, 0, sizeof(*cap));
-		cap->type = type;
-		if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-			for (f = 0; f < 2; f++) {
-				for (l = 0; l < 24; l++) {
-					if (valid_service_line(f, l, cx->is_50hz))
-						cap->service_lines[f][l] = set;
-				}
-			}
-			return 0;
-		}
-		return -EINVAL;
-	}
-
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD: {
-		struct v4l2_encoder_cmd *enc = arg;
-		int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
-		memset(&enc->raw, 0, sizeof(enc->raw));
-		switch (enc->cmd) {
-		case V4L2_ENC_CMD_START:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			return cx18_start_capture(id);
-
-		case V4L2_ENC_CMD_STOP:
-			enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
-			if (try)
-				return 0;
-			cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
-			return 0;
-
-		case V4L2_ENC_CMD_PAUSE:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&cx->ana_capturing))
-				return -EPERM;
-			if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
-				return 0;
-			cx18_mute(cx);
-			cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
-			break;
-
-		case V4L2_ENC_CMD_RESUME:
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&cx->ana_capturing))
-				return -EPERM;
-			if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
-				return 0;
-			cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
-			cx18_unmute(cx);
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	}
-
-	case VIDIOC_LOG_STATUS:
-	{
-		struct v4l2_input vidin;
-		struct v4l2_audio audin;
-		int i;
-
-		CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);
-		if (cx->hw_flags & CX18_HW_TVEEPROM) {
-			struct tveeprom tv;
-
-			cx18_read_eeprom(cx, &tv);
-		}
-		cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
-		cx18_get_input(cx, cx->active_input, &vidin);
-		cx18_get_audio_input(cx, cx->audio_input, &audin);
-		CX18_INFO("Video Input: %s\n", vidin.name);
-		CX18_INFO("Audio Input: %s\n", audin.name);
-		CX18_INFO("Tuner: %s\n",
-			test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
-			"Radio" : "TV");
-		cx2341x_log_status(&cx->params, cx->name);
-		CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
-		for (i = 0; i < CX18_MAX_STREAMS; i++) {
-			struct cx18_stream *s = &cx->streams[i];
-
-			if (s->v4l2dev == NULL || s->buffers == 0)
-				continue;
-			CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
-				s->name, s->s_flags,
-				(s->buffers - s->q_free.buffers) * 100 / s->buffers,
-				(s->buffers * s->buf_size) / 1024, s->buffers);
-		}
-		CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
-				(long long)cx->mpg_data_received,
-				(long long)cx->vbi_data_inserted);
-		CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
+		if ((val == 0) || (val & 0x01))
+			cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);
 		break;
 	}
 
@@ -747,105 +769,68 @@
 	return 0;
 }
 
-static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
-			      unsigned int cmd, void *arg)
-{
-	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
-	struct cx18 *cx = id->cx;
-	int ret;
-
-	/* check priority */
-	switch (cmd) {
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_S_FMT:
-	case VIDIOC_S_CROP:
-	case VIDIOC_S_EXT_CTRLS:
-		ret = v4l2_prio_check(&cx->prio, &id->prio);
-		if (ret)
-			return ret;
-	}
-
-	switch (cmd) {
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-	case VIDIOC_G_CHIP_IDENT:
-	case VIDIOC_INT_S_AUDIO_ROUTING:
-	case VIDIOC_INT_RESET:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_debug_ioctls(filp, cmd, arg);
-
-	case VIDIOC_G_PRIORITY:
-	case VIDIOC_S_PRIORITY:
-	case VIDIOC_QUERYCAP:
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_ENUM_FMT:
-	case VIDIOC_CROPCAP:
-	case VIDIOC_G_CROP:
-	case VIDIOC_S_CROP:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_G_TUNER:
-	case VIDIOC_ENUMAUDIO:
-	case VIDIOC_S_AUDIO:
-	case VIDIOC_G_AUDIO:
-	case VIDIOC_G_SLICED_VBI_CAP:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_G_ENC_INDEX:
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_v4l2_ioctls(cx, filp, cmd, arg);
-
-	case VIDIOC_QUERYMENU:
-	case VIDIOC_QUERYCTRL:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_G_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
-		if (cx18_debug & CX18_DBGFLG_IOCTL) {
-			printk(KERN_INFO "cx18%d ioctl: ", cx->num);
-			v4l_printk_ioctl(cmd);
-		}
-		return cx18_control_ioctls(cx, cmd, arg);
-
-	case 0x00005401:	/* Handle isatty() calls */
-		return -EINVAL;
-	default:
-		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
-						   cx18_v4l2_do_ioctl);
-	}
-	return 0;
-}
-
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long arg)
 {
+	struct video_device *vfd = video_devdata(filp);
 	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
 	struct cx18 *cx = id->cx;
 	int res;
 
 	mutex_lock(&cx->serialize_lock);
-	res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+
+	if (cx18_debug & CX18_DBGFLG_IOCTL)
+		vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+	res = video_ioctl2(inode, filp, cmd, arg);
+	vfd->debug = 0;
 	mutex_unlock(&cx->serialize_lock);
 	return res;
 }
+
+void cx18_set_funcs(struct video_device *vdev)
+{
+	vdev->vidioc_querycap                = cx18_querycap;
+	vdev->vidioc_g_priority              = cx18_g_priority;
+	vdev->vidioc_s_priority              = cx18_s_priority;
+	vdev->vidioc_s_audio                 = cx18_s_audio;
+	vdev->vidioc_g_audio                 = cx18_g_audio;
+	vdev->vidioc_enumaudio               = cx18_enumaudio;
+	vdev->vidioc_enum_input              = cx18_enum_input;
+	vdev->vidioc_cropcap                 = cx18_cropcap;
+	vdev->vidioc_s_crop                  = cx18_s_crop;
+	vdev->vidioc_g_crop                  = cx18_g_crop;
+	vdev->vidioc_g_input                 = cx18_g_input;
+	vdev->vidioc_s_input                 = cx18_s_input;
+	vdev->vidioc_g_frequency             = cx18_g_frequency;
+	vdev->vidioc_s_frequency             = cx18_s_frequency;
+	vdev->vidioc_s_tuner                 = cx18_s_tuner;
+	vdev->vidioc_g_tuner                 = cx18_g_tuner;
+	vdev->vidioc_g_enc_index             = cx18_g_enc_index;
+	vdev->vidioc_g_std                   = cx18_g_std;
+	vdev->vidioc_s_std                   = cx18_s_std;
+	vdev->vidioc_log_status              = cx18_log_status;
+	vdev->vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap;
+	vdev->vidioc_encoder_cmd             = cx18_encoder_cmd;
+	vdev->vidioc_try_encoder_cmd         = cx18_try_encoder_cmd;
+	vdev->vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap;
+	vdev->vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap;
+	vdev->vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap;
+	vdev->vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap;
+	vdev->vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap;
+	vdev->vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap;
+	vdev->vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap;
+	vdev->vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap;
+	vdev->vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap;
+	vdev->vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap;
+	vdev->vidioc_g_chip_ident            = cx18_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	vdev->vidioc_g_register              = cx18_g_register;
+	vdev->vidioc_s_register              = cx18_s_register;
+#endif
+	vdev->vidioc_default                 = cx18_default;
+	vdev->vidioc_queryctrl               = cx18_queryctrl;
+	vdev->vidioc_querymenu               = cx18_querymenu;
+	vdev->vidioc_g_ext_ctrls             = cx18_g_ext_ctrls;
+	vdev->vidioc_s_ext_ctrls             = cx18_s_ext_ctrls;
+	vdev->vidioc_try_ext_ctrls           = cx18_try_ext_ctrls;
+}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
index 9f4c7eb..2222f67 100644
--- a/drivers/media/video/cx18/cx18-ioctl.h
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -24,7 +24,9 @@
 u16 cx18_service2vbi(int type);
 void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
 u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void cx18_set_funcs(struct video_device *vdev);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_input(struct file *file, void *fh, unsigned int inp);
 int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		    unsigned long arg);
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
-		     void *arg);
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 2a5ccef..9317751 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@
 	API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,			0),
 	API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,			API_FAST),
+	API_ENTRY(CPU, CX18_APU_RESETAI,			API_FAST),
 	API_ENTRY(0, 0,						0),
 };
 
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 1b921a3..1728b1d 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -39,6 +39,7 @@
 	.owner = THIS_MODULE,
 	.read = cx18_v4l2_read,
 	.open = cx18_v4l2_open,
+	/* FIXME change to video_ioctl2 if serialization lock can be removed */
 	.ioctl = cx18_v4l2_ioctl,
 	.compat_ioctl = v4l_compat_ioctl32,
 	.release = cx18_v4l2_close,
@@ -189,14 +190,15 @@
 	s->v4l2dev->type =
 		VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
 		VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
-	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
-			cx->num, s->name);
+	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
+			cx->num);
 
 	s->v4l2dev->minor = minor;
 	s->v4l2dev->dev = &cx->dev->dev;
 	s->v4l2dev->fops = cx18_stream_info[type].fops;
 	s->v4l2dev->release = video_device_release;
-
+	s->v4l2dev->tvnorms = V4L2_STD_ALL;
+	cx18_set_funcs(s->v4l2dev);
 	return 0;
 }
 
@@ -309,8 +311,10 @@
 
 	/* Teardown all streams */
 	for (type = 0; type < CX18_MAX_STREAMS; type++) {
-		if (cx->streams[type].dvb.enabled)
+		if (cx->streams[type].dvb.enabled) {
 			cx18_dvb_unregister(&cx->streams[type]);
+			cx->streams[type].dvb.enabled = false;
+		}
 
 		vdev = cx->streams[type].v4l2dev;
 
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 33f78da..e7ed053 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -52,6 +52,11 @@
 #define EPU_CMD_MASK_DEBUG       		(EPU_CMD_MASK | 0x000000)
 #define EPU_CMD_MASK_DE                     	(EPU_CMD_MASK | 0x040000)
 
+#define APU_CMD_MASK 				0x10000000
+#define APU_CMD_MASK_ACK 			(APU_CMD_MASK | 0x80000000)
+
+#define CX18_APU_RESETAI 			(APU_CMD_MASK | 0x05)
+
 /* Description: This command indicates that a Memory Descriptor List has been
    filled with the requested channel type
    IN[0] - Task handle. Handle of the task
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index c592899..22847a0 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -77,10 +77,65 @@
 };
 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
 
+static const struct cx2341x_mpeg_params default_params = {
+	/* misc */
+	.capabilities = 0,
+	.port = CX2341X_PORT_MEMORY,
+	.width = 720,
+	.height = 480,
+	.is_50hz = 0,
+
+	/* stream */
+	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+	.stream_insert_nav_packets = 0,
+
+	/* audio */
+	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+	.audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+	.audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+	.audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+	.audio_mute = 0,
+
+	/* video */
+	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+	.video_b_frames = 2,
+	.video_gop_size = 12,
+	.video_gop_closure = 1,
+	.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+	.video_bitrate = 6000000,
+	.video_bitrate_peak = 8000000,
+	.video_temporal_decimation = 0,
+	.video_mute = 0,
+	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
+
+	/* encoding filters */
+	.video_spatial_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+	.video_spatial_filter = 0,
+	.video_luma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_chroma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_temporal_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+	.video_temporal_filter = 8,
+	.video_median_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+	.video_luma_median_filter_top = 255,
+	.video_luma_median_filter_bottom = 0,
+	.video_chroma_median_filter_top = 255,
+	.video_chroma_median_filter_bottom = 0,
+};
+
 
 /* Map the control ID to the correct field in the cx2341x_mpeg_params
    struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
 		struct v4l2_ext_control *ctrl)
 {
 	switch (ctrl->id) {
@@ -420,7 +475,7 @@
 	return 0;
 }
 
-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
 		       struct v4l2_queryctrl *qctrl)
 {
 	int err;
@@ -430,13 +485,13 @@
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
-				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+				default_params.audio_encoding);
 
 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_AUDIO_L2_BITRATE_192K,
 				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
-				V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+				default_params.audio_l2_bitrate);
 
 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
 	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
@@ -479,17 +534,22 @@
 		return cx2341x_ctrl_query_fill(qctrl,
 				V4L2_MPEG_STREAM_VBI_FMT_NONE,
 				V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
-				V4L2_MPEG_STREAM_VBI_FMT_NONE);
+				default_params.stream_vbi_fmt);
+
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+				params->is_50hz ? 12 : 15);
 
 	/* CX23415/6 specific */
 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
 		return cx2341x_ctrl_query_fill(qctrl,
 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
-			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+			default_params.video_spatial_filter_mode);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
-		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1,
+				default_params.video_spatial_filter);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_spatial_filter_mode ==
 			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
@@ -501,7 +561,7 @@
 			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
 			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
 			1,
-			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+			default_params.video_luma_spatial_filter_type);
 		if (params->video_spatial_filter_mode ==
 			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
@@ -512,7 +572,7 @@
 		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
 		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
 		    1,
-		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+		    default_params.video_chroma_spatial_filter_type);
 		if (params->video_spatial_filter_mode ==
 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
@@ -522,10 +582,11 @@
 		return cx2341x_ctrl_query_fill(qctrl,
 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
-			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+			default_params.video_temporal_filter_mode);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
-		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1,
+				default_params.video_temporal_filter);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_temporal_filter_mode ==
 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
@@ -536,10 +597,11 @@
 		return cx2341x_ctrl_query_fill(qctrl,
 			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
 			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
-			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+			default_params.video_median_filter_type);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
-		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_luma_median_filter_top);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_median_filter_type ==
 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
@@ -547,7 +609,8 @@
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
-		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_luma_median_filter_bottom);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_median_filter_type ==
 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
@@ -555,7 +618,8 @@
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
-		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+				default_params.video_chroma_median_filter_top);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_median_filter_type ==
 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
@@ -563,7 +627,8 @@
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
-		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+			default_params.video_chroma_median_filter_bottom);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
 		if (params->video_median_filter_type ==
 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
@@ -571,7 +636,8 @@
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
-		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1,
+				default_params.stream_insert_nav_packets);
 
 	default:
 		return v4l2_ctrl_query_fill_std(qctrl);
@@ -580,9 +646,9 @@
 }
 EXPORT_SYMBOL(cx2341x_ctrl_query);
 
-const char **cx2341x_ctrl_get_menu(u32 id)
+const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
 {
-	static const char *mpeg_stream_type[] = {
+	static const char *mpeg_stream_type_without_ts[] = {
 		"MPEG-2 Program Stream",
 		"",
 		"MPEG-1 System Stream",
@@ -592,6 +658,16 @@
 		NULL
 	};
 
+	static const char *mpeg_stream_type_with_ts[] = {
+		"MPEG-2 Program Stream",
+		"MPEG-2 Transport Stream",
+		"MPEG-1 System Stream",
+		"MPEG-2 DVD-compatible Stream",
+		"MPEG-1 VCD-compatible Stream",
+		"MPEG-2 SVCD-compatible Stream",
+		NULL
+	};
+
 	static const char *cx2341x_video_spatial_filter_mode_menu[] = {
 		"Manual",
 		"Auto",
@@ -630,7 +706,8 @@
 
 	switch (id) {
 	case V4L2_CID_MPEG_STREAM_TYPE:
-		return mpeg_stream_type;
+		return (p->capabilities & CX2341X_CAP_HAS_TS) ?
+			mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
 	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
 		return NULL;
@@ -690,7 +767,7 @@
 		if (err)
 			break;
 		if (qctrl.type == V4L2_CTRL_TYPE_MENU)
-			menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+			menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
 		err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
 		if (err)
 			break;
@@ -714,61 +791,6 @@
 
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
 {
-	static struct cx2341x_mpeg_params default_params = {
-	/* misc */
-	.capabilities = 0,
-	.port = CX2341X_PORT_MEMORY,
-	.width = 720,
-	.height = 480,
-	.is_50hz = 0,
-
-	/* stream */
-	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
-	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
-	.stream_insert_nav_packets = 0,
-
-	/* audio */
-	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
-	.audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-	.audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
-	.audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
-	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
-	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
-	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
-	.audio_mute = 0,
-
-	/* video */
-	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
-	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
-	.video_b_frames = 2,
-	.video_gop_size = 12,
-	.video_gop_closure = 1,
-	.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-	.video_bitrate = 6000000,
-	.video_bitrate_peak = 8000000,
-	.video_temporal_decimation = 0,
-	.video_mute = 0,
-	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
-
-	/* encoding filters */
-	.video_spatial_filter_mode =
-		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
-	.video_spatial_filter = 0,
-	.video_luma_spatial_filter_type =
-		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
-	.video_chroma_spatial_filter_type =
-		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-	.video_temporal_filter_mode =
-		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-	.video_temporal_filter = 8,
-	.video_median_filter_type =
-		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
-	.video_luma_median_filter_top = 255,
-	.video_luma_median_filter_bottom = 0,
-	.video_chroma_median_filter_top = 255,
-	.video_chroma_median_filter_bottom = 0,
-	};
-
 	*p = default_params;
 	cx2341x_calc_audio_properties(p);
 }
@@ -933,9 +955,9 @@
 }
 EXPORT_SYMBOL(cx2341x_update);
 
-static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
 {
-	const char **menu = cx2341x_ctrl_get_menu(id);
+	const char **menu = cx2341x_ctrl_get_menu(p, id);
 	struct v4l2_ext_control ctrl;
 
 	if (menu == NULL)
@@ -952,7 +974,7 @@
 	return "<invalid>";
 }
 
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
 {
 	int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
 	int temporal = p->video_temporal_filter;
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 7bf14c9..5cfb46b 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -9,11 +9,13 @@
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
 	select VIDEOBUF_DVB
+	select VIDEOBUF_DMA_SG
 	select VIDEO_CX25840
 	select VIDEO_CX2341X
 	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index acdd3b6..e7ef093 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -1173,379 +1173,404 @@
 	qctrl.id = qmenu->id;
 	cx23885_queryctrl(dev, &qctrl);
 	return v4l2_ctrl_query_menu(qmenu, &qctrl,
-		cx2341x_ctrl_get_menu(qmenu->id));
+		cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
 }
 
-int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio,
-	struct cx23885_dev *dev, unsigned int cmd, void *arg,
-	v4l2_kioctl driver_ioctl)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-	int err;
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+	unsigned int i;
 
-	switch (cmd) {
-	/* ---------- tv norms ---------- */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+		if (*id & cx23885_tvnorms[i].id)
+			break;
+	if (i == ARRAY_SIZE(cx23885_tvnorms))
+		return -EINVAL;
+	dev->encodernorm = cx23885_tvnorms[i];
+	return 0;
+}
 
-		i = e->index;
-		if (i >= ARRAY_SIZE(cx23885_tvnorms))
-			return -EINVAL;
-		err = v4l2_video_std_construct(e,
-			cx23885_tvnorms[e->index].id,
-			cx23885_tvnorms[e->index].name);
-		e->index = i;
-		if (err < 0)
-			return err;
-		return 0;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_input *input;
+	unsigned int n;
 
-		*id = dev->encodernorm.id;
-		return 0;
-	}
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-		unsigned int i;
+	n = i->index;
 
-		for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
-			if (*id & cx23885_tvnorms[i].id)
-				break;
-		if (i == ARRAY_SIZE(cx23885_tvnorms))
-			return -EINVAL;
-		dev->encodernorm = cx23885_tvnorms[i];
+	if (n >= 4)
+		return -EINVAL;
 
-		return 0;
-	}
+	input = &cx23885_boards[dev->board].input[n];
 
-	/* ------ input switching ---------- */
-	case VIDIOC_ENUMINPUT:
-	{
-		struct cx23885_input *input;
-		struct v4l2_input *i = arg;
-		unsigned int n;
+	if (input->type == 0)
+		return -EINVAL;
 
-		n = i->index;
-		if (n >= 4)
-			return -EINVAL;
-		input = &cx23885_boards[dev->board].input[n];
-		if (input->type == 0)
-			return -EINVAL;
-		memset(i, 0, sizeof(*i));
-		i->index = n;
-		/* FIXME
-		 * strcpy(i->name, input->name); */
-		strcpy(i->name, "unset");
-		if (input->type == CX23885_VMUX_TELEVISION ||
-		    input->type == CX23885_VMUX_CABLE)
-			i->type = V4L2_INPUT_TYPE_TUNER;
-		else
-			i->type  = V4L2_INPUT_TYPE_CAMERA;
+	memset(i, 0, sizeof(*i));
+	i->index = n;
 
-		for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
-			i->std |= cx23885_tvnorms[n].id;
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		unsigned int *i = arg;
+	/* FIXME
+	 * strcpy(i->name, input->name); */
+	strcpy(i->name, "unset");
 
-		*i = dev->input;
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		unsigned int *i = arg;
+	if (input->type == CX23885_VMUX_TELEVISION ||
+	    input->type == CX23885_VMUX_CABLE)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	else
+		i->type  = V4L2_INPUT_TYPE_CAMERA;
 
-		if (*i >= 4)
-			return -EINVAL;
+	for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
+		i->std |= cx23885_tvnorms[n].id;
+	return 0;
+}
 
-		return 0;
-	}
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
 
-	/* --- tuner ioctls ------------------------------------------ */
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+	*i = dev->input;
+	return 0;
+}
 
-		if (UNSET == dev->tuner_type)
-			return -EINVAL;
-		if (0 != t->index)
-			return -EINVAL;
-		memset(t, 0, sizeof(*t));
-		strcpy(t->name, "Television");
-		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
-		cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
-
-		dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
-
-		return 0;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
-
-		if (UNSET == dev->tuner_type)
-			return -EINVAL;
-
-		/* Update the A/V core */
-		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
-
-		return 0;
-	}
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		memset(f, 0, sizeof(*f));
-		if (UNSET == dev->tuner_type)
-			return -EINVAL;
-		f->type = V4L2_TUNER_ANALOG_TV;
-		f->frequency = dev->freq;
-
-		/* Assumption that tuner is always on bus 1 */
-		cx23885_call_i2c_clients(&dev->i2c_bus[1],
-			VIDIOC_G_FREQUENCY, f);
-
-		return 0;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
-			dev->tuner_type);
-		dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
-			f->tuner, f->type);
-		if (UNSET == dev->tuner_type)
-			return -EINVAL;
-		if (f->tuner != 0)
-			return -EINVAL;
-		if (f->type != V4L2_TUNER_ANALOG_TV)
-			return -EINVAL;
-		dev->freq = f->frequency;
-
-		/* Assumption that tuner is always on bus 1 */
-		cx23885_call_i2c_clients(&dev->i2c_bus[1],
-			VIDIOC_S_FREQUENCY, f);
-		return 0;
-	}
-	case VIDIOC_S_CTRL:
-	{
-		/* Update the A/V core */
-		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg);
-		return 0;
-	}
-	default:
-		/* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl
-		 * (driver_ioctl) */
-		return v4l_compat_translate_ioctl(inode, file, cmd, arg,
-						  driver_ioctl);
-	}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i >= 4)
+		return -EINVAL;
 
 	return 0;
 }
 
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, void *arg)
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	memset(t, 0, sizeof(*t));
+	strcpy(t->name, "Television");
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+
+	dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+
+	/* Update the A/V core */
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	memset(f, 0, sizeof(*f));
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->freq;
+
+	/* Assumption that tuner is always on bus 1 */
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+		CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+		CX23885_RAW_BITS_NONE);
+
+	dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
+		dev->tuner_type);
+	dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
+		f->tuner, f->type);
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (f->tuner != 0)
+		return -EINVAL;
+	if (f->type != V4L2_TUNER_ANALOG_TV)
+		return -EINVAL;
+	dev->freq = f->frequency;
+
+	/* Assumption that tuner is always on bus 1 */
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+
+	cx23885_initialize_codec(dev);
+
+	return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	/* Update the A/V core */
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
 {
 	struct cx23885_fh  *fh  = file->private_data;
 	struct cx23885_dev *dev = fh->dev;
 	struct cx23885_tsport  *tsport = &dev->ts1;
 
-	if (v4l_debug > 1)
-		v4l_print_ioctl(dev->name, cmd);
+	memset(cap, 0, sizeof(*cap));
+	strcpy(cap->driver, dev->name);
+	strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->version = CX23885_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		V4L2_CAP_STREAMING     |
+		0;
+	if (UNSET != dev->tuner_type)
+		cap->capabilities |= V4L2_CAP_TUNER;
 
-	switch (cmd) {
-
-	/* --- capabilities ------------------------------------------ */
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
-
-		memset(cap, 0, sizeof(*cap));
-		strcpy(cap->driver, dev->name);
-		strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
-			sizeof(cap->card));
-		sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-		cap->version = CX23885_VERSION_CODE;
-		cap->capabilities =
-			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_READWRITE     |
-			V4L2_CAP_STREAMING     |
-			0;
-		if (UNSET != dev->tuner_type)
-			cap->capabilities |= V4L2_CAP_TUNER;
-
-		return 0;
-	}
-
-	/* --- capture ioctls ---------------------------------------- */
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		int index;
-
-		index = f->index;
-		if (index != 0)
-			return -EINVAL;
-
-		memset(f, 0, sizeof(*f));
-		f->index = index;
-		strlcpy(f->description, "MPEG", sizeof(f->description));
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->pixelformat = V4L2_PIX_FMT_MPEG;
-		return 0;
-	}
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = arg;
-
-		memset(f, 0, sizeof(*f));
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.bytesperline = 0;
-		f->fmt.pix.sizeimage    =
-			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
-		f->fmt.pix.colorspace   = 0;
-		f->fmt.pix.width        = dev->ts1.width;
-		f->fmt.pix.height       = dev->ts1.height;
-		f->fmt.pix.field        = fh->mpegq.field;
-		dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
-			dev->ts1.width, dev->ts1.height, fh->mpegq.field);
-		return 0;
-	}
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *f = arg;
-
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.bytesperline = 0;
-		f->fmt.pix.sizeimage    =
-			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
-		f->fmt.pix.sizeimage    =
-		f->fmt.pix.colorspace   = 0;
-		dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
-			dev->ts1.width, dev->ts1.height, fh->mpegq.field);
-		return 0;
-	}
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
-
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.bytesperline = 0;
-		f->fmt.pix.sizeimage    =
-			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
-		f->fmt.pix.colorspace   = 0;
-		dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
-			f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
-		return 0;
-	}
-
-	/* --- streaming capture ------------------------------------- */
-	case VIDIOC_REQBUFS:
-		return videobuf_reqbufs(&fh->mpegq, arg);
-
-	case VIDIOC_QUERYBUF:
-		return videobuf_querybuf(&fh->mpegq, arg);
-
-	case VIDIOC_QBUF:
-		return videobuf_qbuf(&fh->mpegq, arg);
-
-	case VIDIOC_DQBUF:
-		return videobuf_dqbuf(&fh->mpegq, arg,
-				      file->f_flags & O_NONBLOCK);
-
-	case VIDIOC_STREAMON:
-		return videobuf_streamon(&fh->mpegq);
-
-	case VIDIOC_STREAMOFF:
-		return videobuf_streamoff(&fh->mpegq);
-
-	case VIDIOC_G_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *f = arg;
-
-		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-			return -EINVAL;
-		return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd);
-	}
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *f = arg;
-		struct cx2341x_mpeg_params p;
-		int err;
-
-		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-			return -EINVAL;
-		p = dev->mpeg_params;
-		err = cx2341x_ext_ctrls(&p, 0, f, cmd);
-		if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
-			err = cx2341x_update(dev, cx23885_mbox_func,
-				&dev->mpeg_params, &p);
-			dev->mpeg_params = p;
-		}
-		return err;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-			CX23885_END_NOW, CX23885_MPEG_CAPTURE,
-			CX23885_RAW_BITS_NONE);
-		cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
-			mpeg_do_ioctl);
-		cx23885_initialize_codec(dev);
-
-		return 0;
-	}
-	case VIDIOC_LOG_STATUS:
-	{
-		char name[32 + 2];
-
-		snprintf(name, sizeof(name), "%s/2", dev->name);
-		printk(KERN_INFO
-			"%s/2: ============  START LOG STATUS  ============\n",
-		       dev->name);
-		cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
-			NULL);
-		cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
-			NULL);
-		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
-			NULL);
-		cx2341x_log_status(&dev->mpeg_params, name);
-		printk(KERN_INFO
-			"%s/2: =============  END LOG STATUS  =============\n",
-		       dev->name);
-		return 0;
-	}
-	case VIDIOC_QUERYMENU:
-		return cx23885_querymenu(dev, arg);
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *c = arg;
-
-		return cx23885_queryctrl(dev, c);
-	}
-
-	default:
-		return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
-				mpeg_do_ioctl);
-	}
 	return 0;
 }
 
-static int mpeg_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
 {
-	return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+	int index;
+
+	index = f->index;
+	if (index != 0)
+		return -EINVAL;
+
+	memset(f, 0, sizeof(*f));
+	f->index = index;
+	strlcpy(f->description, "MPEG", sizeof(f->description));
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	memset(f, 0, sizeof(*f));
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.width        = dev->ts1.width;
+	f->fmt.pix.height       = dev->ts1.height;
+	f->fmt.pix.field        = fh->mpegq.field;
+	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.sizeimage    =
+	f->fmt.pix.colorspace   = 0;
+	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage    =
+		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+	f->fmt.pix.colorspace   = 0;
+	dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_reqbufs(&fh->mpegq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_querybuf(&fh->mpegq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+				struct v4l2_buffer *p)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_qbuf(&fh->mpegq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct cx23885_fh  *fh  = priv;
+
+	return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_streamon(&fh->mpegq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+
+	return videobuf_streamoff(&fh->mpegq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
+
+	if (err == 0) {
+		err = cx2341x_update(dev, cx23885_mbox_func,
+			&dev->mpeg_params, &p);
+		dev->mpeg_params = p;
+	}
+	return err;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+				struct v4l2_ext_controls *f)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx2341x_mpeg_params p;
+	int err;
+
+	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	p = dev->mpeg_params;
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+	return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+	char name[32 + 2];
+
+	snprintf(name, sizeof(name), "%s/2", dev->name);
+	printk(KERN_INFO
+		"%s/2: ============  START LOG STATUS  ============\n",
+	       dev->name);
+	cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+		NULL);
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+		NULL);
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+		NULL);
+	cx2341x_log_status(&dev->mpeg_params, name);
+	printk(KERN_INFO
+		"%s/2: =============  END LOG STATUS  =============\n",
+	       dev->name);
+	return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+				struct v4l2_querymenu *a)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	return cx23885_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *c)
+{
+	struct cx23885_fh  *fh  = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	return cx23885_queryctrl(dev, c);
 }
 
 static int mpeg_open(struct inode *inode, struct file *file)
@@ -1670,7 +1695,7 @@
 	.read	       = mpeg_read,
 	.poll          = mpeg_poll,
 	.mmap	       = mpeg_mmap,
-	.ioctl	       = mpeg_ioctl,
+	.ioctl	       = video_ioctl2,
 	.llseek        = no_llseek,
 };
 
@@ -1682,6 +1707,32 @@
 				VID_TYPE_MPEG_ENCODER,
 	.fops          = &mpeg_fops,
 	.minor         = -1,
+	.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_g_tuner		 = vidioc_g_tuner,
+	.vidioc_s_tuner		 = vidioc_s_tuner,
+	.vidioc_g_frequency	 = vidioc_g_frequency,
+	.vidioc_s_frequency	 = vidioc_s_frequency,
+	.vidioc_s_ctrl		 = vidioc_s_ctrl,
+	.vidioc_querycap	 = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
+	.vidioc_reqbufs		 = vidioc_reqbufs,
+	.vidioc_querybuf	 = vidioc_querybuf,
+	.vidioc_qbuf		 = vidioc_qbuf,
+	.vidioc_dqbuf		 = vidioc_dqbuf,
+	.vidioc_streamon	 = vidioc_streamon,
+	.vidioc_streamoff	 = vidioc_streamoff,
+	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
+	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_log_status	 = vidioc_log_status,
+	.vidioc_querymenu	 = vidioc_querymenu,
+	.vidioc_queryctrl	 = vidioc_queryctrl,
 };
 
 void cx23885_417_unregister(struct cx23885_dev *dev)
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 20e05f2..fd7112c 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -143,6 +143,10 @@
 		.name		= "Hauppauge WinTV-HVR1400",
 		.portc		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = {
+		.name		= "DViCO FusionHDTV7 Dual Express",
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -210,6 +214,10 @@
 		.subvendor = 0x0070,
 		.subdevice = 0x8010,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1400,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd618,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -477,6 +485,11 @@
 	}
 
 	switch (dev->board) {
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		/* break omitted intentionally */
 	case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
 		ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index c4cc2f3..d17343e 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -291,9 +291,9 @@
 		lines = 6;
 	BUG_ON(lines < 2);
 
-	cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
-	cx_write(8 + 4, cpu_to_le32(8) );
-	cx_write(8 + 8, cpu_to_le32(0) );
+	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	cx_write(8 + 4, 8);
+	cx_write(8 + 8, 0);
 
 	/* write CDT */
 	for (i = 0; i < lines; i++) {
@@ -408,11 +408,11 @@
 	       dev->name, risc->cpu, (unsigned long)risc->dma);
 	for (i = 0; i < (risc->size >> 2); i += n) {
 		printk("%s:   %04d: ", dev->name, i);
-		n = cx23885_risc_decode(risc->cpu[i]);
+		n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
 		for (j = 1; j < n; j++)
 			printk("%s:   %04d: 0x%08x [ arg #%d ]\n",
 			       dev->name, i + j, risc->cpu[i + j], j);
-		if (risc->cpu[i] == RISC_JUMP)
+		if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
 			break;
 	}
 }
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 022aa39..0a2e655 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -31,6 +31,7 @@
 #include <media/v4l2-common.h>
 
 #include "s5h1409.h"
+#include "s5h1411.h"
 #include "mt2131.h"
 #include "tda8290.h"
 #include "tda18271.h"
@@ -164,12 +165,38 @@
 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
+static struct s5h1409_config dvico_s5h1409_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1411_config dvico_s5h1411_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_ON,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
 static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
 	.i2c_address      = 0x61,
 	.if_khz           = 5380,
 	.tuner_callback   = cx23885_tuner_callback
 };
 
+static struct xc5000_config dvico_xc5000_tunerconfig = {
+	.i2c_address      = 0x64,
+	.if_khz           = 5380,
+	.tuner_callback   = cx23885_tuner_callback
+};
+
 static struct tda829x_config tda829x_no_probe = {
 	.probe_tuner = TDA829X_DONT_PROBE,
 };
@@ -453,6 +480,21 @@
 				fe->ops.tuner_ops.set_config(fe, &ctl);
 		}
 		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+		i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+		port->dvb.frontend = dvb_attach(s5h1409_attach,
+						&dvico_s5h1409_config,
+						&i2c_bus->i2c_adap);
+		if (port->dvb.frontend == NULL)
+			port->dvb.frontend = dvb_attach(s5h1411_attach,
+							&dvico_s5h1411_config,
+							&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL)
+			dvb_attach(xc5000_attach, port->dvb.frontend,
+				&i2c_bus->i2c_adap,
+				&dvico_xc5000_tunerconfig, i2c_bus);
+		break;
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->name);
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 8465221..043fc4e 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -915,7 +915,7 @@
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
 
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
 	struct cx23885_fh *fh   = priv;
@@ -932,7 +932,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
 	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -983,7 +983,7 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
 	struct cx23885_fh *fh = priv;
@@ -991,7 +991,7 @@
 	int err;
 
 	dprintk(2, "%s()\n", __func__);
-	err = vidioc_try_fmt_cap(file, priv, f);
+	err = vidioc_try_fmt_vid_cap(file, priv, f);
 
 	if (0 != err)
 		return err;
@@ -1025,7 +1025,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 	struct v4l2_fmtdesc *f)
 {
 	if (unlikely(f->index >= ARRAY_SIZE(formats)))
@@ -1440,13 +1440,13 @@
 	.fops                 = &video_fops,
 	.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_g_fmt_vbi     = cx23885_vbi_fmt,
-	.vidioc_try_fmt_vbi   = cx23885_vbi_fmt,
-	.vidioc_s_fmt_vbi     = cx23885_vbi_fmt,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap     = cx23885_vbi_fmt,
+	.vidioc_try_fmt_vbi_cap   = cx23885_vbi_fmt,
+	.vidioc_s_fmt_vbi_cap     = cx23885_vbi_fmt,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 32af87f..00dfdc8 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -63,6 +63,7 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1200        7
 #define CX23885_BOARD_HAUPPAUGE_HVR1700        8
 #define CX23885_BOARD_HAUPPAUGE_HVR1400        9
+#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 1da6f13..e7bf4f4 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -50,7 +50,6 @@
 
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
-
 int cx25840_debug;
 
 module_param_named(debug,cx25840_debug, int, 0644);
@@ -238,7 +237,7 @@
 	cx25840_write(client, 0x8d3, 0x1f);
 	cx25840_write(client, 0x8e3, 0x03);
 
-	cx25840_vbi_setup(client);
+	cx25840_std_setup(client);
 
 	/* trial and error says these are needed to get audio */
 	cx25840_write(client, 0x914, 0xa0);
@@ -338,7 +337,7 @@
 	finish_wait(&state->fw_wait, &wait);
 	destroy_workqueue(q);
 
-	cx25840_vbi_setup(client);
+	cx25840_std_setup(client);
 
 	/* (re)set input */
 	set_input(client, state->vid_input, state->aud_input);
@@ -349,6 +348,153 @@
 
 /* ----------------------------------------------------------------------- */
 
+void cx25840_std_setup(struct i2c_client *client)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	v4l2_std_id std = state->std;
+	int hblank, hactive, burst, vblank, vactive, sc;
+	int vblank656, src_decimation;
+	int luma_lpf, uv_lpf, comb;
+	u32 pll_int, pll_frac, pll_post;
+
+	/* datasheet startup, step 8d */
+	if (std & ~V4L2_STD_NTSC)
+		cx25840_write(client, 0x49f, 0x11);
+	else
+		cx25840_write(client, 0x49f, 0x14);
+
+	if (std & V4L2_STD_625_50) {
+		hblank = 132;
+		hactive = 720;
+		burst = 93;
+		vblank = 36;
+		vactive = 580;
+		vblank656 = 40;
+		src_decimation = 0x21f;
+		luma_lpf = 2;
+
+		if (std & V4L2_STD_SECAM) {
+			uv_lpf = 0;
+			comb = 0;
+			sc = 0x0a425f;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 556453;
+		} else {
+			uv_lpf = 1;
+			comb = 0x20;
+			sc = 688739;
+		}
+	} else {
+		hactive = 720;
+		hblank = 122;
+		vactive = 487;
+		luma_lpf = 1;
+		uv_lpf = 1;
+
+		src_decimation = 0x21f;
+		if (std == V4L2_STD_PAL_60) {
+			vblank = 26;
+			vblank656 = 26;
+			burst = 0x5b;
+			luma_lpf = 2;
+			comb = 0x20;
+			sc = 688739;
+		} else if (std == V4L2_STD_PAL_M) {
+			vblank = 20;
+			vblank656 = 24;
+			burst = 0x61;
+			comb = 0x20;
+			sc = 555452;
+		} else {
+			vblank = 26;
+			vblank656 = 26;
+			burst = 0x5b;
+			comb = 0x66;
+			sc = 556063;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	pll_int = cx25840_read(client, 0x108);
+	pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
+	pll_post = cx25840_read(client, 0x109);
+	v4l_dbg(1, cx25840_debug, client,
+				"PLL regs = int: %u, frac: %u, post: %u\n",
+				pll_int, pll_frac, pll_post);
+
+	if (pll_post) {
+		int fin, fsc;
+		int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
+
+		pll /= pll_post;
+		v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+				pll / 1000000, pll % 1000000);
+		v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+				pll / 8000000, (pll / 8) % 1000000);
+
+		fin = ((u64)src_decimation * pll) >> 12;
+		v4l_dbg(1, cx25840_debug, client,
+				"ADC Sampling freq = %d.%06d MHz\n",
+				fin / 1000000, fin % 1000000);
+
+		fsc = (((u64)sc) * pll) >> 24L;
+		v4l_dbg(1, cx25840_debug, client,
+				"Chroma sub-carrier freq = %d.%06d MHz\n",
+				fsc / 1000000, fsc % 1000000);
+
+		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
+			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
+			"sc 0x%06x\n",
+			hblank, hactive, vblank, vactive, vblank656,
+			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx25840_write(client, 0x470, hblank);
+	cx25840_write(client, 0x471,
+			0xff & (((hblank >> 8) & 0x3) | (hactive << 4)));
+	cx25840_write(client, 0x472, hactive >> 4);
+
+	/* Sets burst gate delay */
+	cx25840_write(client, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx25840_write(client, 0x474, vblank);
+	cx25840_write(client, 0x475,
+			0xff & (((vblank >> 8) & 0x3) | (vactive << 4)));
+	cx25840_write(client, 0x476, vactive >> 4);
+	cx25840_write(client, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx25840_write(client, 0x478, 0xff & src_decimation);
+	cx25840_write(client, 0x479, 0xff & (src_decimation >> 8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+	/* Enables comb filters */
+	cx25840_write(client, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx25840_write(client, 0x47c, sc);
+	cx25840_write(client, 0x47d, 0xff & sc >> 8);
+	cx25840_write(client, 0x47e, 0xff & sc >> 16);
+
+	/* Sets VBI parameters */
+	if (std & V4L2_STD_625_50) {
+		cx25840_write(client, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
+	} else {
+		cx25840_write(client, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
 static void input_change(struct i2c_client *client)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
@@ -566,7 +712,7 @@
 	}
 	cx25840_and_or(client, 0x400, ~0xf, fmt);
 	cx25840_and_or(client, 0x403, ~0x3, pal_m);
-	cx25840_vbi_setup(client);
+	cx25840_std_setup(client);
 	if (!state->is_cx25836)
 		input_change(client);
 	return 0;
@@ -1058,6 +1204,8 @@
 
 		switch (qc->id) {
 			case V4L2_CID_AUDIO_VOLUME:
+				return v4l2_ctrl_query_fill(qc, 0, 65535,
+					65535 / 100, state->default_volume);
 			case V4L2_CID_AUDIO_MUTE:
 			case V4L2_CID_AUDIO_BALANCE:
 			case V4L2_CID_AUDIO_BASS:
@@ -1265,6 +1413,8 @@
 	state->pvr150_workaround = 0;
 	state->audmode = V4L2_TUNER_MODE_LANG1;
 	state->unmute_volume = -1;
+	state->default_volume = 228 - cx25840_read(client, 0x8d4);
+	state->default_volume = ((state->default_volume / 2) + 23) << 9;
 	state->vbi_line_offset = 8;
 	state->id = id;
 	state->rev = device_id;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 8bf797f..72916ba 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -44,6 +44,7 @@
 	u32 audclk_freq;
 	int audmode;
 	int unmute_volume; /* -1 if not muted */
+	int default_volume;
 	int vbi_line_offset;
 	u32 id;
 	u32 rev;
@@ -61,6 +62,7 @@
 u8 cx25840_read(struct i2c_client *client, u16 addr);
 u32 cx25840_read4(struct i2c_client *client, u16 addr);
 int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
+void cx25840_std_setup(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-firmware.c                                                      */
@@ -73,7 +75,6 @@
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-vbi.c                                                           */
-void cx25840_vbi_setup(struct i2c_client *client);
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
 
 #endif
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index c754b9d..69f2bbd 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -82,150 +82,6 @@
 	return err & 0xf0;
 }
 
-void cx25840_vbi_setup(struct i2c_client *client)
-{
-	struct cx25840_state *state = i2c_get_clientdata(client);
-	v4l2_std_id std = state->std;
-	int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
-	int luma_lpf,uv_lpf, comb;
-	u32 pll_int,pll_frac,pll_post;
-
-	/* datasheet startup, step 8d */
-	if (std & ~V4L2_STD_NTSC) {
-		cx25840_write(client, 0x49f, 0x11);
-	} else {
-		cx25840_write(client, 0x49f, 0x14);
-	}
-
-	if (std & V4L2_STD_625_50) {
-		hblank=0x084;
-		hactive=0x2d0;
-		burst=0x5d;
-		vblank=0x024;
-		vactive=0x244;
-		vblank656=0x28;
-		src_decimation=0x21f;
-
-		luma_lpf=2;
-		if (std & V4L2_STD_SECAM) {
-			uv_lpf=0;
-			comb=0;
-			sc=0x0a425f;
-		} else if (std == V4L2_STD_PAL_Nc) {
-			uv_lpf=1;
-			comb=0x20;
-			sc=556453;
-		} else {
-			uv_lpf=1;
-			comb=0x20;
-			sc=0x0a8263;
-		}
-	} else {
-		hactive=720;
-		hblank=122;
-		vactive=487;
-		luma_lpf=1;
-		uv_lpf=1;
-
-		src_decimation=0x21f;
-		if (std == V4L2_STD_PAL_60) {
-			vblank=26;
-			vblank656=26;
-			burst=0x5b;
-			luma_lpf=2;
-			comb=0x20;
-			sc=0x0a8263;
-		} else if (std == V4L2_STD_PAL_M) {
-			vblank=20;
-			vblank656=24;
-			burst=0x61;
-			comb=0x20;
-
-			sc=555452;
-		} else {
-			vblank=26;
-			vblank656=26;
-			burst=0x5b;
-			comb=0x66;
-			sc=556063;
-		}
-	}
-
-	/* DEBUG: Displays configured PLL frequency */
-	pll_int=cx25840_read(client, 0x108);
-	pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
-	pll_post=cx25840_read(client, 0x109);
-	v4l_dbg(1, cx25840_debug, client,
-				"PLL regs = int: %u, frac: %u, post: %u\n",
-				pll_int,pll_frac,pll_post);
-
-	if (pll_post) {
-		int fin, fsc;
-		int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
-
-		pll/=pll_post;
-		v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
-						pll/1000000, pll%1000000);
-		v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
-						pll/8000000, (pll/8)%1000000);
-
-		fin=((u64)src_decimation*pll)>>12;
-		v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
-						"%d.%06d MHz\n",
-						fin/1000000,fin%1000000);
-
-		fsc= (((u64)sc)*pll) >> 24L;
-		v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
-						"%d.%06d MHz\n",
-						fsc/1000000,fsc%1000000);
-
-		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
-			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
-			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
-			" sc 0x%06x\n",
-			hblank, hactive, vblank, vactive, vblank656,
-			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
-	}
-
-	/* Sets horizontal blanking delay and active lines */
-	cx25840_write(client, 0x470, hblank);
-	cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
-	cx25840_write(client, 0x472, hactive>>4);
-
-	/* Sets burst gate delay */
-	cx25840_write(client, 0x473, burst);
-
-	/* Sets vertical blanking delay and active duration */
-	cx25840_write(client, 0x474, vblank);
-	cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
-	cx25840_write(client, 0x476, vactive>>4);
-	cx25840_write(client, 0x477, vblank656);
-
-	/* Sets src decimation rate */
-	cx25840_write(client, 0x478, 0xff&src_decimation);
-	cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
-
-	/* Sets Luma and UV Low pass filters */
-	cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
-
-	/* Enables comb filters */
-	cx25840_write(client, 0x47b, comb);
-
-	/* Sets SC Step*/
-	cx25840_write(client, 0x47c, sc);
-	cx25840_write(client, 0x47d, 0xff&sc>>8);
-	cx25840_write(client, 0x47e, 0xff&sc>>16);
-
-	/* Sets VBI parameters */
-	if (std & V4L2_STD_625_50) {
-		cx25840_write(client, 0x47f, 0x01);
-		state->vbi_line_offset = 5;
-	} else {
-		cx25840_write(client, 0x47f, 0x00);
-		state->vbi_line_offset = 8;
-	}
-}
-
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
@@ -292,8 +148,8 @@
 			/* raw VBI */
 			memset(svbi, 0, sizeof(*svbi));
 
-			/* Setup VBI */
-			cx25840_vbi_setup(client);
+			/* Setup standard */
+			cx25840_std_setup(client);
 
 			/* VBI Offset */
 			cx25840_write(client, 0x47f, vbi_offset);
@@ -304,8 +160,8 @@
 		for (x = 0; x <= 23; x++)
 			lcr[x] = 0x00;
 
-		/* Setup VBI */
-		cx25840_vbi_setup(client);
+		/* Setup standard */
+		cx25840_std_setup(client);
 
 		/* Sliced VBI */
 		cx25840_write(client, 0x404, 0x32);	/* Ancillary data */
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 80c8883..06f171a 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -82,7 +82,6 @@
 
 
 
-
 /****************************************************************************
 			Module global static vars
  ****************************************************************************/
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 6c0c94c..bfdca58 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -715,7 +715,8 @@
 
 	qctrl.id = qmenu->id;
 	blackbird_queryctrl(dev, &qctrl);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+			cx2341x_ctrl_get_menu(&dev->params, qmenu->id));
 }
 
 static int vidioc_querycap (struct file *file, void  *priv,
@@ -737,7 +738,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (f->index != 0)
@@ -749,7 +750,7 @@
 	return 0;
 }
 
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct cx8802_fh  *fh   = priv;
@@ -768,7 +769,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct cx8802_fh  *fh   = priv;
@@ -784,7 +785,7 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct cx8802_fh  *fh   = priv;
@@ -1181,10 +1182,10 @@
 	.minor                = -1,
 	.vidioc_querymenu     = vidioc_querymenu,
 	.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_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index cb6a096..d7406a9 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -103,7 +103,6 @@
 
 	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
 		client->driver->driver.name, client->addr, client->name);
-
 	return 0;
 }
 
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index eea23f9..0fed5cd 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1045,7 +1045,7 @@
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
 
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct cx8800_fh  *fh   = priv;
@@ -1061,7 +1061,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
@@ -1112,11 +1112,11 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct cx8800_fh  *fh   = priv;
-	int err = vidioc_try_fmt_cap (file,priv,f);
+	int err = vidioc_try_fmt_vid_cap (file,priv,f);
 
 	if (0 != err)
 		return err;
@@ -1147,7 +1147,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (unlikely(f->index >= ARRAY_SIZE(formats)))
@@ -1690,13 +1690,13 @@
 	.fops                 = &video_fops,
 	.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_g_fmt_vbi     = cx8800_vbi_fmt,
-	.vidioc_try_fmt_vbi   = cx8800_vbi_fmt,
-	.vidioc_s_fmt_vbi     = cx8800_vbi_fmt,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vbi_cap     = cx8800_vbi_fmt,
+	.vidioc_try_fmt_vbi_cap   = cx8800_vbi_fmt,
+	.vidioc_s_fmt_vbi_cap     = cx8800_vbi_fmt,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 6ce5af4..2080042 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -30,7 +30,6 @@
 #include "cx88.h"
 #include "cx88-vp3054-i2c.h"
 
-
 MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 8cbda43..05f0d5a 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -173,6 +173,27 @@
 			.amux     = 1,
 		} },
 	},
+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
+		.name         = "Hauppauge WinTV HVR 900 (R2)",
+		.vchannels    = 3,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.mts_firmware = 1,
+		.decoder      = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = 1,
+		} },
+	},
 	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
 		.name           = "Hauppauge WinTV HVR 950",
 		.vchannels      = 3,
@@ -196,6 +217,29 @@
 			.amux     = 1,
 		} },
 	},
+	[EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
+		.name           = "Pinnacle PCTV HD Pro Stick",
+		.vchannels      = 3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.tuner_type     = TUNER_XC2028,
+		.mts_firmware   = 1,
+		.has_12mhz_i2s  = 1,
+		.has_dvb        = 1,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = 1,
+		} },
+	},
 	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
 		.name         = "Terratec Hybrid XS",
 		.vchannels    = 3,
@@ -382,6 +426,19 @@
 			.amux     = EM28XX_AMUX_LINE_IN,
 		} },
 	},
+	[EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
+		.name         = "PointNix Intra-Oral Camera",
+		.has_snapshot_button = 1,
+		.vchannels    = 1,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_ABSENT,
+		.decoder      = EM28XX_SAA7113,
+		.input          = { {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = 0,
+		} },
+	},
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -417,10 +474,12 @@
 			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
 	{ USB_DEVICE(0x2304, 0x021a),
 			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x2304, 0x0227),
+			.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
 	{ USB_DEVICE(0x2040, 0x6500),
 			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
 	{ USB_DEVICE(0x2040, 0x6502),
-			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 },
 	{ USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
 			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
 	{ USB_DEVICE(0x2040, 0x6517), /* HP  HVR-950 */
@@ -476,6 +535,7 @@
 static struct em28xx_hash_table em28xx_i2c_hash[] = {
 	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
 	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+	{0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
 };
 
 int em28xx_tuner_callback(void *ptr, int command, int arg)
@@ -508,6 +568,7 @@
 	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
 	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
 	dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+	dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
 }
 
 /* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -542,8 +603,10 @@
 	switch (dev->model) {
 	case EM2880_BOARD_TERRATEC_PRODIGY_XS:
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
 	case EM2880_BOARD_TERRATEC_HYBRID_XS:
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
 		em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
 		em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
 		msleep(50);
@@ -576,7 +639,12 @@
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
 		ctl->demod = XC3028_FE_ZARLINK456;
 		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+		/* djh - Not sure which demod we need here */
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
 		/* FIXME: Better to specify the needed IF */
 		ctl->demod = XC3028_FE_DEFAULT;
 		break;
@@ -754,6 +822,7 @@
 	switch (dev->model) {
 	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
 	{
 		struct tveeprom tv;
@@ -787,6 +856,9 @@
 			em28xx_set_model(dev);
 	}
 
+	if (dev->has_snapshot_button)
+		em28xx_register_snapshot_button(dev);
+
 	/* Allow override tuner type by a module parameter */
 	if (tuner >= 0)
 		dev->tuner_type = tuner;
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 0b2333e..cc61cfb 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -5,6 +5,7 @@
 
  (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
 	- Fixes for the driver to properly work with HVR-950
+	- Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
 
  (c) 2008 Aidan Thornton <makosoft@googlemail.com>
 
@@ -26,6 +27,9 @@
 
 #include "lgdt330x.h"
 #include "zl10353.h"
+#ifdef EM28XX_DRX397XD_SUPPORT
+#include "drx397xD.h"
+#endif
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -227,6 +231,13 @@
 	.if2 = 45600,
 };
 
+#ifdef EM28XX_DRX397XD_SUPPORT
+/* [TODO] djh - not sure yet what the device config needs to contain */
+static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
+	.demod_address = (0xe0 >> 1),
+};
+#endif
+
 /* ------------------------------------------------------------------ */
 
 static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -399,6 +410,7 @@
 	/* init frontend */
 	switch (dev->model) {
 	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
 		dvb->frontend = dvb_attach(lgdt330x_attach,
 					   &em2880_lgdt3303_dev,
 					   &dev->i2c_adap);
@@ -416,6 +428,19 @@
 			goto out_free;
 		}
 		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+#ifdef EM28XX_DRX397XD_SUPPORT
+		/* We don't have the config structure properly populated, so
+		   this is commented out for now */
+		dvb->frontend = dvb_attach(drx397xD_attach,
+					   &em28xx_drx397xD_with_xc3028,
+					   &dev->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+#endif
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n",
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 6a78fd2..9785338 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -432,7 +432,6 @@
 	return I2C_FUNC_SMBUS_EMUL;
 }
 
-
 /*
  * attach_inform()
  * gets called when a device attaches to the i2c bus
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index bb58071..eab3d95 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -30,6 +30,10 @@
 
 #include "em28xx.h"
 
+#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
+#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20
+
 static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
@@ -124,6 +128,89 @@
 	return 1;
 }
 
+static void em28xx_query_sbutton(struct work_struct *work)
+{
+	/* Poll the register and see if the button is depressed */
+	struct em28xx *dev =
+		container_of(work, struct em28xx, sbutton_query_work.work);
+	int ret;
+
+	ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
+
+	if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
+		u8 cleared;
+		/* Button is depressed, clear the register */
+		cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
+		em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
+
+		/* Not emulate the keypress */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 1);
+		/* Now unpress the key */
+		input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+				 0);
+	}
+
+	/* Schedule next poll */
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+}
+
+void em28xx_register_snapshot_button(struct em28xx *dev)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	em28xx_info("Registering snapshot button...\n");
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		em28xx_errdev("input_allocate_device failed\n");
+		return;
+	}
+
+	usb_make_path(dev->udev, dev->snapshot_button_path,
+		      sizeof(dev->snapshot_button_path));
+	strlcat(dev->snapshot_button_path, "/sbutton",
+		sizeof(dev->snapshot_button_path));
+	INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
+
+	input_dev->name = "em28xx snapshot button";
+	input_dev->phys = dev->snapshot_button_path;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+	set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
+	input_dev->keycodesize = 0;
+	input_dev->keycodemax = 0;
+	input_dev->id.bustype = BUS_USB;
+	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &dev->udev->dev;
+
+	err = input_register_device(input_dev);
+	if (err) {
+		em28xx_errdev("input_register_device failed\n");
+		input_free_device(input_dev);
+		return;
+	}
+
+	dev->sbutton_input_dev = input_dev;
+	schedule_delayed_work(&dev->sbutton_query_work,
+			      msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+	return;
+
+}
+
+void em28xx_deregister_snapshot_button(struct em28xx *dev)
+{
+	if (dev->sbutton_input_dev != NULL) {
+		em28xx_info("Deregistering snapshot button\n");
+		cancel_rearming_delayed_work(&dev->sbutton_query_work);
+		input_unregister_device(dev->sbutton_input_dev);
+		dev->sbutton_input_dev = NULL;
+	}
+	return;
+}
+
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 285bc62..2d9f14d 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -683,7 +683,7 @@
 	IOCTL vidioc handling
    ------------------------------------------------------------------*/
 
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct em28xx_fh      *fh  = priv;
@@ -706,7 +706,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct em28xx_fh      *fh    = priv;
@@ -766,7 +766,7 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct em28xx_fh      *fh  = priv;
@@ -777,7 +777,7 @@
 	if (rc < 0)
 		return rc;
 
-	vidioc_try_fmt_cap(file, priv, f);
+	vidioc_try_fmt_vid_cap(file, priv, f);
 
 	mutex_lock(&dev->lock);
 
@@ -826,7 +826,7 @@
 	/* Adjusts width/height, if needed */
 	f.fmt.pix.width = dev->width;
 	f.fmt.pix.height = dev->height;
-	vidioc_try_fmt_cap(file, priv, &f);
+	vidioc_try_fmt_vid_cap(file, priv, &f);
 
 	mutex_lock(&dev->lock);
 
@@ -1277,7 +1277,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *fmtd)
 {
 	if (fmtd->index != 0)
@@ -1292,7 +1292,7 @@
 }
 
 /* Sliced VBI ioctls */
-static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct em28xx_fh      *fh  = priv;
@@ -1316,7 +1316,7 @@
 	return rc;
 }
 
-static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct em28xx_fh      *fh  = priv;
@@ -1590,6 +1590,8 @@
 				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
 				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
 	list_del(&dev->devlist);
+	if (dev->sbutton_input_dev)
+		em28xx_deregister_snapshot_button(dev);
 	if (dev->radio_dev) {
 		if (-1 != dev->radio_dev->minor)
 			video_unregister_device(dev->radio_dev);
@@ -1776,17 +1778,17 @@
 
 	.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_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
 	.vidioc_g_audio             = vidioc_g_audio,
 	.vidioc_s_audio             = vidioc_s_audio,
 	.vidioc_cropcap             = vidioc_cropcap,
 
-	.vidioc_g_fmt_vbi_capture   = vidioc_g_fmt_vbi_capture,
-	.vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
-	.vidioc_s_fmt_vbi_capture   = vidioc_try_set_vbi_capture,
+	.vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+	.vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
 
 	.vidioc_reqbufs             = vidioc_reqbufs,
 	.vidioc_querybuf            = vidioc_querybuf,
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 002f170..89842c5 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -55,6 +55,9 @@
 #define EM2820_BOARD_PROLINK_PLAYTV_USB2	14
 #define EM2800_BOARD_VGEAR_POCKETTV             15
 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO	17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2	18
+#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA  19
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -247,6 +250,7 @@
 	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
 	unsigned int has_dvb:1;
+	unsigned int has_snapshot_button:1;
 
 	enum em28xx_decoder decoder;
 
@@ -326,6 +330,7 @@
 	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
 	unsigned int has_dvb:1;
+	unsigned int has_snapshot_button:1;
 
 	/* Some older em28xx chips needs a waiting time after writing */
 	unsigned int wait_after_write;
@@ -416,6 +421,11 @@
 	/* Caches GPO and GPIO registers */
 	unsigned char	reg_gpo, reg_gpio;
 
+	/* Snapshot button */
+	char snapshot_button_path[30];	/* path of the input dev */
+	struct input_dev *sbutton_input_dev;
+	struct delayed_work sbutton_query_work;
+
 	struct em28xx_dvb *dvb;
 };
 
@@ -481,6 +491,8 @@
 int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 				     u32 *ir_raw);
+void em28xx_register_snapshot_button(struct em28xx *dev);
+void em28xx_deregister_snapshot_button(struct em28xx *dev);
 
 /* printk macros */
 
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
new file mode 100644
index 0000000..42b9074
--- /dev/null
+++ b/drivers/media/video/gspca/Kconfig
@@ -0,0 +1,13 @@
+config USB_GSPCA
+	tristate "USB GSPCA driver"
+	depends on VIDEO_V4L2
+	---help---
+	  Say Y here if you want support for various USB webcams.
+
+	  See <file:Documentation/video4linux/gspca.txt> for more info.
+
+	  This driver uses the Video For Linux API. You must say Y or M to
+	  "Video For Linux" to use this driver.
+
+	  To compile this driver as modules, choose M here: the
+	  modules will be called gspca_xxxx.
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
new file mode 100644
index 0000000..e68a896
--- /dev/null
+++ b/drivers/media/video/gspca/Makefile
@@ -0,0 +1,29 @@
+obj-$(CONFIG_USB_GSPCA)	+= gspca_main.o \
+	gspca_conex.o gspca_etoms.o gspca_mars.o \
+	gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
+	gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
+	gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
+	gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
+	gspca_vc032x.o gspca_zc3xx.o
+
+gspca_main-objs := gspca.o
+gspca_conex-objs := conex.o
+gspca_etoms-objs := etoms.o
+gspca_mars-objs := mars.o
+gspca_ov519-objs := ov519.o
+gspca_pac207-objs := pac207.o
+gspca_pac7311-objs := pac7311.o
+gspca_sonixb-objs := sonixb.o
+gspca_sonixj-objs := sonixj.o
+gspca_spca500-objs := spca500.o
+gspca_spca501-objs := spca501.o
+gspca_spca505-objs := spca505.o
+gspca_spca506-objs := spca506.o
+gspca_spca508-objs := spca508.o
+gspca_spca561-objs := spca561.o
+gspca_stk014-objs := stk014.o
+gspca_sunplus-objs := sunplus.o
+gspca_t613-objs := t613.o
+gspca_tv8532-objs := tv8532.o
+gspca_vc032x-objs := vc032x.o
+gspca_zc3xx-objs := zc3xx.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
new file mode 100644
index 0000000..013d593
--- /dev/null
+++ b/drivers/media/video/gspca/conex.c
@@ -0,0 +1,1051 @@
+/*
+ *		Connexant Cx11646 library
+ *		Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "conex"
+
+#include "gspca.h"
+#define CONEX_CAM 1		/* special JPEG header */
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+
+	unsigned char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id	 = V4L2_CID_BRIGHTNESS,
+		.type	 = V4L2_CTRL_TYPE_INTEGER,
+		.name	 = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step	 = 1,
+#define BRIGHTNESS_DEF 0xd4
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0x0a,
+		.maximum = 0x1f,
+		.step    = 1,
+#define CONTRAST_DEF 0x0c
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 7,
+		.step    = 1,
+#define COLOR_DEF 3
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 3},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* the read bytes are found in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (len > sizeof gspca_dev->usb_buf) {
+		err("reg_r: buffer overflow");
+		return;
+	}
+#endif
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, len,
+			500);
+	PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+			index, gspca_dev->usb_buf[0]);
+}
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static void reg_w_val(struct gspca_dev *gspca_dev,
+			__u16 index,
+			__u8 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	gspca_dev->usb_buf[0] = val;
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  const __u8 *buffer,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (len > sizeof gspca_dev->usb_buf) {
+		err("reg_w: buffer overflow");
+		return;
+	}
+	PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,
+			index, gspca_dev->usb_buf, len, 500);
+}
+
+static const __u8 cx_sensor_init[][4] = {
+	{0x88, 0x11, 0x01, 0x01},
+	{0x88, 0x12, 0x70, 0x01},
+	{0x88, 0x0f, 0x00, 0x01},
+	{0x88, 0x05, 0x01, 0x01},
+	{}
+};
+
+static const __u8 cx11646_fw1[][3] = {
+	{0x00, 0x02, 0x00},
+	{0x01, 0x43, 0x00},
+	{0x02, 0xA7, 0x00},
+	{0x03, 0x8B, 0x01},
+	{0x04, 0xE9, 0x02},
+	{0x05, 0x08, 0x04},
+	{0x06, 0x08, 0x05},
+	{0x07, 0x07, 0x06},
+	{0x08, 0xE7, 0x06},
+	{0x09, 0xC6, 0x07},
+	{0x0A, 0x86, 0x08},
+	{0x0B, 0x46, 0x09},
+	{0x0C, 0x05, 0x0A},
+	{0x0D, 0xA5, 0x0A},
+	{0x0E, 0x45, 0x0B},
+	{0x0F, 0xE5, 0x0B},
+	{0x10, 0x85, 0x0C},
+	{0x11, 0x25, 0x0D},
+	{0x12, 0xC4, 0x0D},
+	{0x13, 0x45, 0x0E},
+	{0x14, 0xE4, 0x0E},
+	{0x15, 0x64, 0x0F},
+	{0x16, 0xE4, 0x0F},
+	{0x17, 0x64, 0x10},
+	{0x18, 0xE4, 0x10},
+	{0x19, 0x64, 0x11},
+	{0x1A, 0xE4, 0x11},
+	{0x1B, 0x64, 0x12},
+	{0x1C, 0xE3, 0x12},
+	{0x1D, 0x44, 0x13},
+	{0x1E, 0xC3, 0x13},
+	{0x1F, 0x24, 0x14},
+	{0x20, 0xA3, 0x14},
+	{0x21, 0x04, 0x15},
+	{0x22, 0x83, 0x15},
+	{0x23, 0xE3, 0x15},
+	{0x24, 0x43, 0x16},
+	{0x25, 0xA4, 0x16},
+	{0x26, 0x23, 0x17},
+	{0x27, 0x83, 0x17},
+	{0x28, 0xE3, 0x17},
+	{0x29, 0x43, 0x18},
+	{0x2A, 0xA3, 0x18},
+	{0x2B, 0x03, 0x19},
+	{0x2C, 0x63, 0x19},
+	{0x2D, 0xC3, 0x19},
+	{0x2E, 0x22, 0x1A},
+	{0x2F, 0x63, 0x1A},
+	{0x30, 0xC3, 0x1A},
+	{0x31, 0x23, 0x1B},
+	{0x32, 0x83, 0x1B},
+	{0x33, 0xE2, 0x1B},
+	{0x34, 0x23, 0x1C},
+	{0x35, 0x83, 0x1C},
+	{0x36, 0xE2, 0x1C},
+	{0x37, 0x23, 0x1D},
+	{0x38, 0x83, 0x1D},
+	{0x39, 0xE2, 0x1D},
+	{0x3A, 0x23, 0x1E},
+	{0x3B, 0x82, 0x1E},
+	{0x3C, 0xC3, 0x1E},
+	{0x3D, 0x22, 0x1F},
+	{0x3E, 0x63, 0x1F},
+	{0x3F, 0xC1, 0x1F},
+	{}
+};
+static void cx11646_fw(struct gspca_dev*gspca_dev)
+{
+	int i = 0;
+
+	reg_w_val(gspca_dev, 0x006a, 0x02);
+	while (cx11646_fw1[i][1]) {
+		reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3);
+		i++;
+	}
+	reg_w_val(gspca_dev, 0x006a, 0x00);
+}
+
+static const __u8 cxsensor[] = {
+	0x88, 0x12, 0x70, 0x01,
+	0x88, 0x0d, 0x02, 0x01,
+	0x88, 0x0f, 0x00, 0x01,
+	0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01,	/* 3 */
+	0x88, 0x02, 0x10, 0x01,
+	0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01,	/* 5 */
+	0x88, 0x0B, 0x00, 0x01,
+	0x88, 0x0A, 0x0A, 0x01,
+	0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01,	/* 8 */
+	0x88, 0x05, 0x01, 0x01,
+	0xA1, 0x18, 0x00, 0x01,
+	0x00
+};
+
+static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
+static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
+static const __u8 reg10[] = { 0xb1, 0xb1 };
+static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e };	/* 640 */
+static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
+	/* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
+static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
+					/* 320{0x04,0x0c,0x05,0x0f}; //320 */
+static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 };	/* 176 */
+static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
+
+static void cx_sensor(struct gspca_dev*gspca_dev)
+{
+	int i = 0;
+	int length;
+	const __u8 *ptsensor = cxsensor;
+
+	reg_w(gspca_dev, 0x0020, reg20, 8);
+	reg_w(gspca_dev, 0x0028, reg28, 8);
+	reg_w(gspca_dev, 0x0010, reg10, 8);
+	reg_w_val(gspca_dev, 0x0092, 0x03);
+
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		reg_w(gspca_dev, 0x0071, reg71a, 4);
+		break;
+	case 1:
+		reg_w(gspca_dev, 0x0071, reg71b, 4);
+		break;
+	default:
+/*	case 2: */
+		reg_w(gspca_dev, 0x0071, reg71c, 4);
+		break;
+	case 3:
+		reg_w(gspca_dev, 0x0071, reg71d, 4);
+		break;
+	}
+	reg_w(gspca_dev, 0x007b, reg7b, 6);
+	reg_w_val(gspca_dev, 0x00f8, 0x00);
+	reg_w(gspca_dev, 0x0010, reg10, 8);
+	reg_w_val(gspca_dev, 0x0098, 0x41);
+	for (i = 0; i < 11; i++) {
+		if (i == 3 || i == 5 || i == 8)
+			length = 8;
+		else
+			length = 4;
+		reg_w(gspca_dev, 0x00e5, ptsensor, length);
+		if (length == 4)
+			reg_r(gspca_dev, 0x00e8, 1);
+		else
+			reg_r(gspca_dev, 0x00e8, length);
+		ptsensor += length;
+	}
+	reg_r(gspca_dev, 0x00e7, 8);
+}
+
+static const __u8 cx_inits_176[] = {
+	0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03,	/* 176x144 */
+	0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
+	0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
+	0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
+	0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
+	0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_320[] = {
+	0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
+	0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
+	0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
+	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
+	0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_352[] = {
+	0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
+	0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
+	0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
+	0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
+	0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
+	0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_640[] = {
+	0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
+	0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
+	0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
+	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+	0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
+	0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void cx11646_initsize(struct gspca_dev *gspca_dev)
+{
+	const __u8 *cxinit;
+	static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
+	static const __u8 reg17[] =
+			{ 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
+
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		cxinit = cx_inits_640;
+		break;
+	case 1:
+		cxinit = cx_inits_352;
+		break;
+	default:
+/*	case 2: */
+		cxinit = cx_inits_320;
+		break;
+	case 3:
+		cxinit = cx_inits_176;
+		break;
+	}
+	reg_w_val(gspca_dev, 0x009a, 0x01);
+	reg_w_val(gspca_dev, 0x0010, 0x10);
+	reg_w(gspca_dev, 0x0012, reg12, 5);
+	reg_w(gspca_dev, 0x0017, reg17, 8);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_w_val(gspca_dev, 0x00c1, 0x04);
+	reg_w_val(gspca_dev, 0x00c2, 0x04);
+
+	reg_w(gspca_dev, 0x0061, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00ca, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00d2, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x00da, cxinit, 6);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0041, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0049, cxinit, 8);
+	cxinit += 8;
+	reg_w(gspca_dev, 0x0051, cxinit, 2);
+
+	reg_r(gspca_dev, 0x0010, 1);
+}
+
+static const __u8 cx_jpeg_init[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15},	/* 1 */
+	{0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
+	{0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
+	{0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
+	{0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
+	{0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
+	{0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
+	{0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
+	{0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
+	{0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
+	{0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
+	{0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
+	{0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
+	{0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
+	{0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
+	{0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
+	{0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
+	{0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05},
+	{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00},
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02},
+	{0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A},
+	{0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01},
+	{0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00},
+	{0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
+	{0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00},
+	{0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05},
+	{0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01},
+	{0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21},
+	{0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22},
+	{0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23},
+	{0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24},
+	{0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17},
+	{0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29},
+	{0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A},
+	{0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A},
+	{0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A},
+	{0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A},
+	{0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A},
+	{0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A},
+	{0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99},
+	{0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8},
+	{0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
+	{0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6},
+	{0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5},
+	{0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3},
+	{0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1},
+	{0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9},
+	{0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04},
+	{0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01},
+	{0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04},
+	{0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07},
+	{0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14},
+	{0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33},
+	{0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16},
+	{0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19},
+	{0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36},
+	{0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46},
+	{0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56},
+	{0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66},
+	{0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76},
+	{0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85},
+	{0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94},
+	{0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3},
+	{0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2},
+	{0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA},
+	{0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9},
+	{0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8},
+	{0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7},
+	{0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6},
+	{0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F},
+	{0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
+	{0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
+	{0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
+	{0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
+	{0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
+	{0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
+	{0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
+	{0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
+	{0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00}	/* 79 */
+};
+
+
+static const __u8 cxjpeg_640[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10},	/* 1 */
+	{0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d},
+	{0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a},
+	{0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d},
+	{0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38},
+	{0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57},
+	{0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F},
+	{0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79},
+	{0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01},
+	{0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E},
+	{0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28},
+	{0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25},
+	{0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33},
+	{0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44},
+	{0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57},
+	{0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71},
+	{0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63},
+	{0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
+};
+static const __u8 cxjpeg_352[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+	{0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
+	{0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
+	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
+	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+	{0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static const __u8 cxjpeg_320[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
+	{0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
+	{0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
+	{0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
+	{0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
+	{0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
+	{0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
+	{0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
+	{0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
+	{0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
+	{0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
+	{0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
+	{0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
+	{0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
+	{0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
+	{0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
+	{0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
+	{0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
+};
+static const __u8 cxjpeg_176[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+	{0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
+	{0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
+	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
+	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+	{0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
+	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
+	{0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
+	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+/* 640 take with the zcx30x part */
+static const __u8 cxjpeg_qtable[][8] = {
+	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
+	{0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
+	{0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
+	{0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f},
+	{0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c},
+	{0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c},
+	{0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30},
+	{0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d},
+	{0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01},
+	{0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
+	{0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 18 */
+};
+
+
+static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
+{
+	int i;
+	int length;
+
+	reg_w_val(gspca_dev, 0x00c0, 0x01);
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_r(gspca_dev, 0x0001, 1);
+	length = 8;
+	for (i = 0; i < 79; i++) {
+		if (i == 78)
+			length = 6;
+		reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length);
+	}
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0055, 0x14);
+}
+
+static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
+static const __u8 regE5_8[] =
+		{ 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
+static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
+static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
+static const __u8 reg51[] = { 0x77, 0x03 };
+#define reg70 0x03
+
+static void cx11646_jpeg(struct gspca_dev*gspca_dev)
+{
+	int i;
+	int length;
+	__u8 Reg55;
+	int retry;
+
+	reg_w_val(gspca_dev, 0x00c0, 0x01);
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+	reg_w_val(gspca_dev, 0x00c0, 0x00);
+	reg_r(gspca_dev, 0x0001, 1);
+	length = 8;
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length);
+		}
+		Reg55 = 0x28;
+		break;
+	case 1:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length);
+		}
+		Reg55 = 0x16;
+		break;
+	default:
+/*	case 2: */
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length);
+		}
+		Reg55 = 0x14;
+		break;
+	case 3:
+		for (i = 0; i < 27; i++) {
+			if (i == 26)
+				length = 2;
+			reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length);
+		}
+		Reg55 = 0x0B;
+		break;
+	}
+
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0055, Reg55);
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0054, 0x02);
+	reg_w_val(gspca_dev, 0x0054, 0x01);
+	reg_w_val(gspca_dev, 0x0000, 0x94);
+	reg_w_val(gspca_dev, 0x0053, 0xc0);
+	reg_w_val(gspca_dev, 0x00fc, 0xe1);
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	/* wait for completion */
+	retry = 50;
+	while (retry--) {
+		reg_r(gspca_dev, 0x0002, 1);
+							/* 0x07 until 0x00 */
+		if (gspca_dev->usb_buf[0] == 0x00)
+			break;
+		reg_w_val(gspca_dev, 0x0053, 0x00);
+	}
+	if (retry == 0)
+		PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+	/* send the qtable now */
+	reg_r(gspca_dev, 0x0001, 1);		/* -> 0x18 */
+	length = 8;
+	for (i = 0; i < 18; i++) {
+		if (i == 17)
+			length = 2;
+		reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length);
+
+	}
+	reg_r(gspca_dev, 0x0002, 1);	/* 0x00 */
+	reg_r(gspca_dev, 0x0053, 1);	/* 0x00 */
+	reg_w_val(gspca_dev, 0x0054, 0x02);
+	reg_w_val(gspca_dev, 0x0054, 0x01);
+	reg_w_val(gspca_dev, 0x0000, 0x94);
+	reg_w_val(gspca_dev, 0x0053, 0xc0);
+
+	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
+	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
+	reg_r(gspca_dev, 0x001f, 1);		/* 0x38 */
+	reg_w(gspca_dev, 0x0012, reg12, 5);
+	reg_w(gspca_dev, 0x00e5, regE5_8, 8);
+	reg_r(gspca_dev, 0x00e8, 8);
+	reg_w(gspca_dev, 0x00e5, regE5a, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg_w_val(gspca_dev, 0x009a, 0x01);
+	reg_w(gspca_dev, 0x00e5, regE5b, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg_w(gspca_dev, 0x00e5, regE5c, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+
+	reg_w(gspca_dev, 0x0051, reg51, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void cx11646_init1(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	reg_w_val(gspca_dev, 0x0010, 0x00);
+	reg_w_val(gspca_dev, 0x0053, 0x00);
+	reg_w_val(gspca_dev, 0x0052, 0x00);
+	reg_w_val(gspca_dev, 0x009b, 0x2f);
+	reg_w_val(gspca_dev, 0x009c, 0x10);
+	reg_r(gspca_dev, 0x0098, 1);
+	reg_w_val(gspca_dev, 0x0098, 0x40);
+	reg_r(gspca_dev, 0x0099, 1);
+	reg_w_val(gspca_dev, 0x0099, 0x07);
+	reg_w_val(gspca_dev, 0x0039, 0x40);
+	reg_w_val(gspca_dev, 0x003c, 0xff);
+	reg_w_val(gspca_dev, 0x003f, 0x1f);
+	reg_w_val(gspca_dev, 0x003d, 0x40);
+/*	reg_w_val(gspca_dev, 0x003d, 0x60); */
+	reg_r(gspca_dev, 0x0099, 1);			/* ->0x07 */
+
+	while (cx_sensor_init[i][0]) {
+		reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]);
+		reg_r(gspca_dev, 0x00e8, 1);		/* -> 0x00 */
+		if (i == 1) {
+			reg_w_val(gspca_dev, 0x00ed, 0x01);
+			reg_r(gspca_dev, 0x00ed, 1);	/* -> 0x01 */
+		}
+		i++;
+	}
+	reg_w_val(gspca_dev, 0x00c3, 0x00);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+
+	sd->qindex = 0;			/* set the quantization */
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	cx11646_init1(gspca_dev);
+	cx11646_initsize(gspca_dev);
+	cx11646_fw(gspca_dev);
+	cx_sensor(gspca_dev);
+	cx11646_jpegInit(gspca_dev);
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	cx11646_initsize(gspca_dev);
+	cx11646_fw(gspca_dev);
+	cx_sensor(gspca_dev);
+	cx11646_jpeg(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	int retry = 50;
+
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	reg_r(gspca_dev, 0x0002, 1);
+	reg_w_val(gspca_dev, 0x0053, 0x00);
+
+	while (retry--) {
+/*		reg_r(gspca_dev, 0x0002, 1);*/
+		reg_r(gspca_dev, 0x0053, 1);
+		if (gspca_dev->usb_buf[0] == 0)
+			break;
+	}
+	reg_w_val(gspca_dev, 0x0000, 0x00);
+	reg_r(gspca_dev, 0x0002, 1);
+
+	reg_w_val(gspca_dev, 0x0010, 0x00);
+	reg_r(gspca_dev, 0x0033, 1);
+	reg_w_val(gspca_dev, 0x00fc, 0xe0);
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	if (data[0] == 0xff && data[1] == 0xd8) {
+
+		/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame,
+				((struct sd *) gspca_dev)->qindex,
+				0x22);
+		data += 2;
+		len -= 2;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev*gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+	__u8 reg51c[2];
+	__u8 bright;
+	__u8 colors;
+
+	bright = sd->brightness;
+	regE5cbx[2] = bright;
+	reg_w(gspca_dev, 0x00e5, regE5cbx, 8);
+	reg_r(gspca_dev, 0x00e8, 8);
+	reg_w(gspca_dev, 0x00e5, regE5c, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+
+	colors = sd->colors;
+	reg51c[0] = 0x77;
+	reg51c[1] = colors;
+	reg_w(gspca_dev, 0x0051, reg51c, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static void setcontrast(struct gspca_dev*gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 };	/* seem MSB */
+/*	__u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01};	 * LSB */
+	__u8 reg51c[2];
+
+	regE5acx[2] = sd->contrast;
+	reg_w(gspca_dev, 0x00e5, regE5acx, 4);
+	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
+	reg51c[0] = 0x77;
+	reg51c[1] = sd->colors;
+	reg_w(gspca_dev, 0x0051, reg51c, 2);
+	reg_w(gspca_dev, 0x0010, reg10, 2);
+	reg_w_val(gspca_dev, 0x0070, reg70);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming) {
+		setbrightness(gspca_dev);
+		setcontrast(gspca_dev);
+	}
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
new file mode 100644
index 0000000..8ab4ea7
--- /dev/null
+++ b/drivers/media/video/gspca/etoms.c
@@ -0,0 +1,956 @@
+/*
+ * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "etoms"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("Etoms USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	char sensor;
+#define SENSOR_PAS106 0
+#define SENSOR_TAS5130CXX 1
+	signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 1,
+	  .maximum = 127,
+	  .step = 1,
+#define BRIGHTNESS_DEF 63
+	  .default_value = BRIGHTNESS_DEF,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 255,
+	  .step = 1,
+#define CONTRAST_DEF 127
+	  .default_value = CONTRAST_DEF,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+	{
+	 {
+	  .id = V4L2_CID_SATURATION,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Color",
+	  .minimum = 0,
+	  .maximum = 15,
+	  .step = 1,
+#define COLOR_DEF 7
+	  .default_value = COLOR_DEF,
+	  },
+	 .set = sd_setcolors,
+	 .get = sd_getcolors,
+	 },
+	{
+	 {
+	  .id = V4L2_CID_AUTOGAIN,
+	  .type = V4L2_CTRL_TYPE_BOOLEAN,
+	  .name = "Auto Gain",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+#define AUTOGAIN_DEF 1
+	  .default_value = AUTOGAIN_DEF,
+	  },
+	 .set = sd_setautogain,
+	 .get = sd_getautogain,
+	 },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+/*	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0}, */
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+#define ETOMS_ALT_SIZE_1000   12
+
+#define ET_GPIO_DIR_CTRL 0x04	/* Control IO bit[0..5] (0 in  1 out) */
+#define ET_GPIO_OUT 0x05	/* Only IO data */
+#define ET_GPIO_IN 0x06		/* Read Only IO data */
+#define ET_RESET_ALL 0x03
+#define ET_ClCK 0x01
+#define ET_CTRL 0x02		/* enable i2c OutClck Powerdown mode */
+
+#define ET_COMP 0x12		/* Compression register */
+#define ET_MAXQt 0x13
+#define ET_MINQt 0x14
+#define ET_COMP_VAL0 0x02
+#define ET_COMP_VAL1 0x03
+
+#define ET_REG1d 0x1d
+#define ET_REG1e 0x1e
+#define ET_REG1f 0x1f
+#define ET_REG20 0x20
+#define ET_REG21 0x21
+#define ET_REG22 0x22
+#define ET_REG23 0x23
+#define ET_REG24 0x24
+#define ET_REG25 0x25
+/* base registers for luma calculation */
+#define ET_LUMA_CENTER 0x39
+
+#define ET_G_RED 0x4d
+#define ET_G_GREEN1 0x4e
+#define ET_G_BLUE 0x4f
+#define ET_G_GREEN2 0x50
+#define ET_G_GR_H 0x51
+#define ET_G_GB_H 0x52
+
+#define ET_O_RED 0x34
+#define ET_O_GREEN1 0x35
+#define ET_O_BLUE 0x36
+#define ET_O_GREEN2 0x37
+
+#define ET_SYNCHRO 0x68
+#define ET_STARTX 0x69
+#define ET_STARTY 0x6a
+#define ET_WIDTH_LOW 0x6b
+#define ET_HEIGTH_LOW 0x6c
+#define ET_W_H_HEIGTH 0x6d
+
+#define ET_REG6e 0x6e		/* OBW */
+#define ET_REG6f 0x6f		/* OBW */
+#define ET_REG70 0x70		/* OBW_AWB */
+#define ET_REG71 0x71		/* OBW_AWB */
+#define ET_REG72 0x72		/* OBW_AWB */
+#define ET_REG73 0x73		/* Clkdelay ns */
+#define ET_REG74 0x74		/* test pattern */
+#define ET_REG75 0x75		/* test pattern */
+
+#define ET_I2C_CLK 0x8c
+#define ET_PXL_CLK 0x60
+
+#define ET_I2C_BASE 0x89
+#define ET_I2C_COUNT 0x8a
+#define ET_I2C_PREFETCH 0x8b
+#define ET_I2C_REG 0x88
+#define ET_I2C_DATA7 0x87
+#define ET_I2C_DATA6 0x86
+#define ET_I2C_DATA5 0x85
+#define ET_I2C_DATA4 0x84
+#define ET_I2C_DATA3 0x83
+#define ET_I2C_DATA2 0x82
+#define ET_I2C_DATA1 0x81
+#define ET_I2C_DATA0 0x80
+
+#define PAS106_REG2 0x02	/* pxlClk = systemClk/(reg2) */
+#define PAS106_REG3 0x03	/* line/frame H [11..4] */
+#define PAS106_REG4 0x04	/* line/frame L [3..0] */
+#define PAS106_REG5 0x05	/* exposure time line offset(default 5) */
+#define PAS106_REG6 0x06	/* exposure time pixel offset(default 6) */
+#define PAS106_REG7 0x07	/* signbit Dac (default 0) */
+#define PAS106_REG9 0x09
+#define PAS106_REG0e 0x0e	/* global gain [4..0](default 0x0e) */
+#define PAS106_REG13 0x13	/* end i2c write */
+
+static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
+
+static const __u8 I2c3[] = { 0x12, 0x05 };
+
+static const __u8 I2c4[] = { 0x41, 0x08 };
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (len > sizeof gspca_dev->usb_buf) {
+		err("reg_r: buffer overflow");
+		return;
+	}
+#endif
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0,
+			index, gspca_dev->usb_buf, len, 500);
+	PDEBUG(D_USBI, "reg read [%02x] -> %02x ..",
+			index, gspca_dev->usb_buf[0]);
+}
+
+static void reg_w_val(struct gspca_dev *gspca_dev,
+			__u16 index,
+			__u8 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	gspca_dev->usb_buf[0] = val;
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0,
+			index, gspca_dev->usb_buf, 1, 500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  const __u8 *buffer,
+		  __u16 len)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (len > sizeof gspca_dev->usb_buf) {
+		err("reg_w: buffer overflow");
+		return;
+	}
+	PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0, index, gspca_dev->usb_buf, len, 500);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev,
+		 __u8 reg,
+		 const __u8 *buffer,
+		 int len, __u8 mode)
+{
+	/* buffer should be [D0..D7] */
+	__u8 ptchcount;
+
+	/* set the base address */
+	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+					 /* sensor base for the pas106 */
+	/* set count and prefetch */
+	ptchcount = ((len & 0x07) << 4) | (mode & 0x03);
+	reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount);
+	/* set the register base */
+	reg_w_val(gspca_dev, ET_I2C_REG, reg);
+	while (--len >= 0)
+		reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]);
+	return 0;
+}
+
+static int i2c_r(struct gspca_dev *gspca_dev,
+			__u8 reg)
+{
+	/* set the base address */
+	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
+					/* sensor base for the pas106 */
+	/* set count and prefetch (cnd: 4 bits - mode: 4 bits) */
+	reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11);
+	reg_w_val(gspca_dev, ET_I2C_REG, reg);	/* set the register base */
+	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02);	/* prefetch */
+	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00);
+	reg_r(gspca_dev, ET_I2C_DATA0, 1);	/* read one byte */
+	return 0;
+}
+
+static int Et_WaitStatus(struct gspca_dev *gspca_dev)
+{
+	int retry = 10;
+
+	while (retry--) {
+		reg_r(gspca_dev, ET_ClCK, 1);
+		if (gspca_dev->usb_buf[0] != 0)
+			return 1;
+	}
+	return 0;
+}
+
+static int et_video(struct gspca_dev *gspca_dev,
+		    int on)
+{
+	int ret;
+
+	reg_w_val(gspca_dev, ET_GPIO_OUT,
+		  on ? 0x10		/* startvideo - set Bit5 */
+		     : 0);		/* stopvideo */
+	ret = Et_WaitStatus(gspca_dev);
+	if (ret != 0)
+		PDEBUG(D_ERR, "timeout video on/off");
+	return ret;
+}
+
+static void Et_init2(struct gspca_dev *gspca_dev)
+{
+	__u8 value;
+	static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
+
+	PDEBUG(D_STREAM, "Open Init2 ET");
+	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f);
+	reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10);
+	reg_r(gspca_dev, ET_GPIO_IN, 1);
+	reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */
+	reg_w_val(gspca_dev, ET_CTRL, 0x1b);
+
+	/*  compression et subsampling */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = ET_COMP_VAL1;	/* 320 */
+	else
+		value = ET_COMP_VAL0;	/* 640 */
+	reg_w_val(gspca_dev, ET_COMP, value);
+	reg_w_val(gspca_dev, ET_MAXQt, 0x1f);
+	reg_w_val(gspca_dev, ET_MINQt, 0x04);
+	/* undocumented registers */
+	reg_w_val(gspca_dev, ET_REG1d, 0xff);
+	reg_w_val(gspca_dev, ET_REG1e, 0xff);
+	reg_w_val(gspca_dev, ET_REG1f, 0xff);
+	reg_w_val(gspca_dev, ET_REG20, 0x35);
+	reg_w_val(gspca_dev, ET_REG21, 0x01);
+	reg_w_val(gspca_dev, ET_REG22, 0x00);
+	reg_w_val(gspca_dev, ET_REG23, 0xff);
+	reg_w_val(gspca_dev, ET_REG24, 0xff);
+	reg_w_val(gspca_dev, ET_REG25, 0x0f);
+	/* colors setting */
+	reg_w_val(gspca_dev, 0x30, 0x11);		/* 0x30 */
+	reg_w_val(gspca_dev, 0x31, 0x40);
+	reg_w_val(gspca_dev, 0x32, 0x00);
+	reg_w_val(gspca_dev, ET_O_RED, 0x00);		/* 0x34 */
+	reg_w_val(gspca_dev, ET_O_GREEN1, 0x00);
+	reg_w_val(gspca_dev, ET_O_BLUE, 0x00);
+	reg_w_val(gspca_dev, ET_O_GREEN2, 0x00);
+	/*************/
+	reg_w_val(gspca_dev, ET_G_RED, 0x80);		/* 0x4d */
+	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);		/* 0x52 */
+	/* Window control registers */
+	reg_w_val(gspca_dev, 0x61, 0x80);		/* use cmc_out */
+	reg_w_val(gspca_dev, 0x62, 0x02);
+	reg_w_val(gspca_dev, 0x63, 0x03);
+	reg_w_val(gspca_dev, 0x64, 0x14);
+	reg_w_val(gspca_dev, 0x65, 0x0e);
+	reg_w_val(gspca_dev, 0x66, 0x02);
+	reg_w_val(gspca_dev, 0x67, 0x02);
+
+	/**************************************/
+	reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f);		/* 0x68 */
+	reg_w_val(gspca_dev, ET_STARTX, 0x69);		/* 0x6a //0x69 */
+	reg_w_val(gspca_dev, ET_STARTY, 0x0d);		/* 0x0d //0x0c */
+	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80);
+	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0);
+	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60);	/* 6d */
+	reg_w_val(gspca_dev, ET_REG6e, 0x86);
+	reg_w_val(gspca_dev, ET_REG6f, 0x01);
+	reg_w_val(gspca_dev, ET_REG70, 0x26);
+	reg_w_val(gspca_dev, ET_REG71, 0x7a);
+	reg_w_val(gspca_dev, ET_REG72, 0x01);
+	/* Clock Pattern registers ***************** */
+	reg_w_val(gspca_dev, ET_REG73, 0x00);
+	reg_w_val(gspca_dev, ET_REG74, 0x18);		/* 0x28 */
+	reg_w_val(gspca_dev, ET_REG75, 0x0f);		/* 0x01 */
+	/**********************************************/
+	reg_w_val(gspca_dev, 0x8a, 0x20);
+	reg_w_val(gspca_dev, 0x8d, 0x0f);
+	reg_w_val(gspca_dev, 0x8e, 0x08);
+	/**************************************/
+	reg_w_val(gspca_dev, 0x03, 0x08);
+	reg_w_val(gspca_dev, ET_PXL_CLK, 0x03);
+	reg_w_val(gspca_dev, 0x81, 0xff);
+	reg_w_val(gspca_dev, 0x80, 0x00);
+	reg_w_val(gspca_dev, 0x81, 0xff);
+	reg_w_val(gspca_dev, 0x80, 0x20);
+	reg_w_val(gspca_dev, 0x03, 0x01);
+	reg_w_val(gspca_dev, 0x03, 0x00);
+	reg_w_val(gspca_dev, 0x03, 0x08);
+	/********************************************/
+
+/*	reg_r(gspca_dev, ET_I2C_BASE, 1);
+					 always 0x40 as the pas106 ??? */
+	/* set the sensor */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = 0x04;		/* 320 */
+	else				/* 640 */
+		value = 0x1e;	/* 0x17	 * setting PixelClock
+					 * 0x03 mean 24/(3+1) = 6 Mhz
+					 * 0x05 -> 24/(5+1) = 4 Mhz
+					 * 0x0b -> 24/(11+1) = 2 Mhz
+					 * 0x17 -> 24/(23+1) = 1 Mhz
+					 */
+	reg_w_val(gspca_dev, ET_PXL_CLK, value);
+	/* now set by fifo the FormatLine setting */
+	reg_w(gspca_dev, 0x62, FormLine, 6);
+
+	/* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
+	reg_w_val(gspca_dev, 0x81, 0x47);	/* 0x47; */
+	reg_w_val(gspca_dev, 0x80, 0x40);	/* 0x40; */
+	/* Pedro change */
+	/* Brightness change Brith+ decrease value */
+	/* Brigth- increase value */
+	/* original value = 0x70; */
+	reg_w_val(gspca_dev, 0x81, 0x30);	/* 0x20; - set brightness */
+	reg_w_val(gspca_dev, 0x80, 0x20);	/* 0x20; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
+	__u8 i2cflags = 0x01;
+	/* __u8 green = 0; */
+	__u8 colors = sd->colors;
+
+	I2cc[3] = colors;	/* red */
+	I2cc[0] = 15 - colors;	/* blue */
+	/* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
+	/* I2cc[1] = I2cc[2] = green; */
+	if (sd->sensor == SENSOR_PAS106) {
+		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+		i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1);
+	}
+/*	PDEBUG(D_CONF , "Etoms red %d blue %d green %d",
+		I2cc[3], I2cc[0], green); */
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+/*		i2c_r(gspca_dev, PAS106_REG9);		 * blue */
+		i2c_r(gspca_dev, PAS106_REG9 + 3);	/* red */
+		sd->colors = gspca_dev->usb_buf[0] & 0x0f;
+	}
+}
+
+static void Et_init1(struct gspca_dev *gspca_dev)
+{
+	__u8 value;
+/*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */
+	__u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
+						/* try 1/120 0x6d 0xcd 0x40 */
+/*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00};
+						 * 1/60000 hmm ?? */
+
+	PDEBUG(D_STREAM, "Open Init1 ET");
+	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7);
+	reg_r(gspca_dev, ET_GPIO_IN, 1);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 1);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0);
+	reg_w_val(gspca_dev, ET_ClCK, 0x10);
+	reg_w_val(gspca_dev, ET_CTRL, 0x19);
+	/*   compression et subsampling */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+		value = ET_COMP_VAL1;
+	else
+		value = ET_COMP_VAL0;
+	PDEBUG(D_STREAM, "Open mode %d Compression %d",
+	       gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv,
+	       value);
+	reg_w_val(gspca_dev, ET_COMP, value);
+	reg_w_val(gspca_dev, ET_MAXQt, 0x1d);
+	reg_w_val(gspca_dev, ET_MINQt, 0x02);
+	/* undocumented registers */
+	reg_w_val(gspca_dev, ET_REG1d, 0xff);
+	reg_w_val(gspca_dev, ET_REG1e, 0xff);
+	reg_w_val(gspca_dev, ET_REG1f, 0xff);
+	reg_w_val(gspca_dev, ET_REG20, 0x35);
+	reg_w_val(gspca_dev, ET_REG21, 0x01);
+	reg_w_val(gspca_dev, ET_REG22, 0x00);
+	reg_w_val(gspca_dev, ET_REG23, 0xf7);
+	reg_w_val(gspca_dev, ET_REG24, 0xff);
+	reg_w_val(gspca_dev, ET_REG25, 0x07);
+	/* colors setting */
+	reg_w_val(gspca_dev, ET_G_RED, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
+	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
+	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
+	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
+	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);
+	/* Window control registers */
+	reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0);
+	reg_w_val(gspca_dev, ET_STARTX, 0x56);		/* 0x56 */
+	reg_w_val(gspca_dev, ET_STARTY, 0x05);		/* 0x04 */
+	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60);
+	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20);
+	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50);
+	reg_w_val(gspca_dev, ET_REG6e, 0x86);
+	reg_w_val(gspca_dev, ET_REG6f, 0x01);
+	reg_w_val(gspca_dev, ET_REG70, 0x86);
+	reg_w_val(gspca_dev, ET_REG71, 0x14);
+	reg_w_val(gspca_dev, ET_REG72, 0x00);
+	/* Clock Pattern registers */
+	reg_w_val(gspca_dev, ET_REG73, 0x00);
+	reg_w_val(gspca_dev, ET_REG74, 0x00);
+	reg_w_val(gspca_dev, ET_REG75, 0x0a);
+	reg_w_val(gspca_dev, ET_I2C_CLK, 0x04);
+	reg_w_val(gspca_dev, ET_PXL_CLK, 0x01);
+	/* set the sensor */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+		I2c0[0] = 0x06;
+		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+		value = 0x06;
+		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+		/* value = 0x1f; */
+		value = 0x04;
+		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+	} else {
+		I2c0[0] = 0x0a;
+
+		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+		value = 0x0a;
+		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
+		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+		value = 0x04;
+		/* value = 0x10; */
+		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
+		/* bit 2 enable bit 1:2 select 0 1 2 3
+		   value = 0x07;                                * curve 0 *
+		   i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1);
+		 */
+	}
+
+/*	value = 0x01; */
+/*	value = 0x22; */
+/*	i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */
+	/* magnetude and sign bit for DAC */
+	i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
+	/* now set by fifo the whole colors setting */
+	reg_w(gspca_dev, ET_G_RED, GainRGBG, 6);
+	getcolors(gspca_dev);
+	setcolors(gspca_dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+/*	switch (vendor) { */
+/*	case 0x102c:		* Etoms */
+		switch (product) {
+		case 0x6151:
+			sd->sensor = SENSOR_PAS106;	/* Etoms61x151 */
+			break;
+		case 0x6251:
+			sd->sensor = SENSOR_TAS5130CXX;	/* Etoms61x251 */
+			break;
+/*		} */
+/*		break; */
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 1;
+	if (sd->sensor == SENSOR_PAS106) {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	} else {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	}
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->autogain = AUTOGAIN_DEF;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106)
+		Et_init1(gspca_dev);
+	else
+		Et_init2(gspca_dev);
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+	et_video(gspca_dev, 0);		/* video off */
+	return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106)
+		Et_init1(gspca_dev);
+	else
+		Et_init2(gspca_dev);
+
+	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
+	et_video(gspca_dev, 1);		/* video on */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	et_video(gspca_dev, 0);		/* video off */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 brightness = sd->brightness;
+
+	for (i = 0; i < 4; i++)
+		reg_w_val(gspca_dev, ET_O_RED + i, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	int brightness = 0;
+
+	for (i = 0; i < 4; i++) {
+		reg_r(gspca_dev, ET_O_RED + i, 1);
+		brightness += gspca_dev->usb_buf[0];
+	}
+	sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+	__u8 contrast = sd->contrast;
+
+	memset(RGBG, contrast, sizeof(RGBG) - 2);
+	reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	int contrast = 0;
+
+	for (i = 0; i < 4; i++) {
+		reg_r(gspca_dev, ET_G_RED + i, 1);
+		contrast += gspca_dev->usb_buf[0];
+	}
+	sd->contrast = contrast >> 2;
+}
+
+static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+		i2c_r(gspca_dev, PAS106_REG0e);
+		PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]);
+		return gspca_dev->usb_buf[0];
+	}
+	return 0x1f;
+}
+
+static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAS106) {
+		__u8 i2cflags = 0x01;
+
+		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
+		i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1);
+	}
+}
+
+#define BLIMIT(bright) \
+	(__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+#define LIMIT(color) \
+	(unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	__u8 luma = 0;
+	__u8 luma_mean = 128;
+	__u8 luma_delta = 20;
+	__u8 spring = 4;
+	int Gbright = 0;
+	__u8 r, g, b;
+
+	Gbright = Et_getgainG(gspca_dev);
+	reg_r(gspca_dev, ET_LUMA_CENTER, 4);
+	g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
+	r = gspca_dev->usb_buf[1];
+	b = gspca_dev->usb_buf[2];
+	r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
+	b = ((b << 7) >> 10);
+	g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
+	luma = LIMIT(r + g + b);
+	PDEBUG(D_FRAM, "Etoms luma G %d", luma);
+	if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
+		Gbright += (luma_mean - luma) >> spring;
+		Gbright = BLIMIT(Gbright);
+		PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright);
+		Et_setgainG(gspca_dev, (__u8) Gbright);
+	}
+}
+
+#undef BLIMIT
+#undef LIMIT
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd;
+	int seqframe;
+
+	seqframe = data[0] & 0x3f;
+	len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+	if (seqframe == 0x3f) {
+		PDEBUG(D_FRAM,
+		       "header packet found datalength %d !!", len);
+		PDEBUG(D_FRAM, "G %d R %d G %d B %d",
+		       data[2], data[3], data[4], data[5]);
+		data += 30;
+		/* don't change datalength as the chips provided it */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		sd = (struct sd *) gspca_dev;
+		if (sd->ag_cnt >= 0) {
+			if (--sd->ag_cnt < 0) {
+				sd->ag_cnt = AG_CNT_START;
+				setautogain(gspca_dev);
+			}
+		}
+		return;
+	}
+	if (len) {
+		data += 8;
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+	} else {			/* Drop Packet */
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+	}
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_ET61X251
+	{USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")},
+#endif
+	{USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
new file mode 100644
index 0000000..16e367c
--- /dev/null
+++ b/drivers/media/video/gspca/gspca.c
@@ -0,0 +1,1905 @@
+/*
+ * Main USB camera driver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ */
+
+#define MODULE_NAME "gspca"
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+#include <asm/page.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+
+#include "gspca.h"
+
+/* global values */
+#define DEF_NURBS 2		/* default number of URBs */
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("GSPCA USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+static int video_nr = -1;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int gspca_debug = D_ERR | D_PROBE;
+EXPORT_SYMBOL(gspca_debug);
+
+static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+{
+	if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
+		PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+			txt,
+			pixfmt & 0xff,
+			(pixfmt >> 8) & 0xff,
+			(pixfmt >> 16) & 0xff,
+			pixfmt >> 24,
+			w, h);
+	} else {
+		PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+			txt,
+			pixfmt,
+			w, h);
+	}
+}
+#else
+#define PDEBUG_MODE(txt, pixfmt, w, h)
+#endif
+
+/* specific memory types - !! should different from V4L2_MEMORY_xxx */
+#define GSPCA_MEMORY_NO 0	/* V4L2_MEMORY_xxx starts from 1 */
+#define GSPCA_MEMORY_READ 7
+
+#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
+
+/*
+ * VMA operations.
+ */
+static void gspca_vm_open(struct vm_area_struct *vma)
+{
+	struct gspca_frame *frame = vma->vm_private_data;
+
+	frame->vma_use_count++;
+	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
+}
+
+static void gspca_vm_close(struct vm_area_struct *vma)
+{
+	struct gspca_frame *frame = vma->vm_private_data;
+
+	if (--frame->vma_use_count <= 0)
+		frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+
+static struct vm_operations_struct gspca_vm_ops = {
+	.open		= gspca_vm_open,
+	.close		= gspca_vm_close,
+};
+
+/*
+ * fill a video frame from an URB and resubmit
+ */
+static void fill_frame(struct gspca_dev *gspca_dev,
+			struct urb *urb)
+{
+	struct gspca_frame *frame;
+	__u8 *data;		/* address of data in the iso message */
+	int i, j, len, st;
+	cam_pkt_op pkt_scan;
+
+	if (urb->status != 0) {
+		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+		return;		/* disconnection ? */
+	}
+	pkt_scan = gspca_dev->sd_desc->pkt_scan;
+	for (i = 0; i < urb->number_of_packets; i++) {
+
+		/* check the availability of the frame buffer */
+		j = gspca_dev->fr_i;
+		j = gspca_dev->fr_queue[j];
+		frame = &gspca_dev->frame[j];
+		if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+					!= V4L2_BUF_FLAG_QUEUED) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			break;
+		}
+
+		/* check the packet status and length */
+		len = urb->iso_frame_desc[i].actual_length;
+		if (len == 0)
+			continue;
+		st = urb->iso_frame_desc[i].status;
+		if (st) {
+			PDEBUG(D_ERR,
+				"ISOC data error: [%d] len=%d, status=%d",
+				i, len, st);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			continue;
+		}
+
+		/* let the packet be analyzed by the subdriver */
+		PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
+			i, urb->iso_frame_desc[i].offset, len);
+		data = (__u8 *) urb->transfer_buffer
+					+ urb->iso_frame_desc[i].offset;
+		pkt_scan(gspca_dev, frame, data, len);
+	}
+
+	/* resubmit the URB */
+	urb->status = 0;
+	st = usb_submit_urb(urb, GFP_ATOMIC);
+	if (st < 0)
+		PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+}
+
+/*
+ * ISOC message interrupt from the USB device
+ *
+ * Analyse each packet and call the subdriver for copy to the frame buffer.
+ */
+static void isoc_irq(struct urb *urb
+)
+{
+	struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+
+	PDEBUG(D_PACK, "isoc irq");
+	if (!gspca_dev->streaming)
+		return;
+	fill_frame(gspca_dev, urb);
+}
+
+/*
+ * add data to the current frame
+ *
+ * This function is called by the subdrivers at interrupt level.
+ *
+ * To build a frame, these ones must add
+ *	- one FIRST_PACKET
+ *	- 0 or many INTER_PACKETs
+ *	- one LAST_PACKET
+ * DISCARD_PACKET invalidates the whole frame.
+ * On LAST_PACKET, a new frame is returned.
+ */
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+				    int packet_type,
+				    struct gspca_frame *frame,
+				    const __u8 *data,
+				    int len)
+{
+	int i, j;
+
+	PDEBUG(D_PACK, "add t:%d l:%d",	packet_type, len);
+
+	/* when start of a new frame, if the current frame buffer
+	 * is not queued, discard the whole frame */
+	if (packet_type == FIRST_PACKET) {
+		if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+						!= V4L2_BUF_FLAG_QUEUED) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return frame;
+		}
+		frame->data_end = frame->data;
+		jiffies_to_timeval(get_jiffies_64(),
+				   &frame->v4l2_buf.timestamp);
+		frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+	} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
+		return frame;
+	}
+
+	/* append the packet to the frame buffer */
+	if (len > 0) {
+		if (frame->data_end - frame->data + len
+						 > frame->v4l2_buf.length) {
+			PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
+				frame->data_end - frame->data + len,
+				frame->v4l2_buf.length);
+			packet_type = DISCARD_PACKET;
+		} else {
+			memcpy(frame->data_end, data, len);
+			frame->data_end += len;
+		}
+	}
+	gspca_dev->last_packet_type = packet_type;
+
+	/* if last packet, wake the application and advance in the queue */
+	if (packet_type == LAST_PACKET) {
+		frame->v4l2_buf.bytesused = frame->data_end - frame->data;
+		frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+		frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
+		atomic_inc(&gspca_dev->nevent);
+		wake_up_interruptible(&gspca_dev->wq);	/* event = new frame */
+		i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
+		gspca_dev->fr_i = i;
+		PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
+			frame->v4l2_buf.bytesused,
+			gspca_dev->fr_q,
+			i,
+			gspca_dev->fr_o);
+		j = gspca_dev->fr_queue[i];
+		frame = &gspca_dev->frame[j];
+	}
+	return frame;
+}
+EXPORT_SYMBOL(gspca_frame_add);
+
+static int gspca_is_compressed(__u32 format)
+{
+	switch (format) {
+	case V4L2_PIX_FMT_MJPEG:
+	case V4L2_PIX_FMT_JPEG:
+	case V4L2_PIX_FMT_SPCA561:
+	case V4L2_PIX_FMT_PAC207:
+		return 1;
+	}
+	return 0;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+/*	size = PAGE_ALIGN(size);	(already done) */
+	mem = vmalloc_32(size);
+	if (mem != NULL) {
+		adr = (unsigned long) mem;
+		while ((long) size > 0) {
+			SetPageReserved(vmalloc_to_page((void *) adr));
+			adr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void *mem, long size)
+{
+	unsigned long adr;
+
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		ClearPageReserved(vmalloc_to_page((void *) adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+
+static int frame_alloc(struct gspca_dev *gspca_dev,
+			unsigned int count)
+{
+	struct gspca_frame *frame;
+	unsigned int frsz;
+	int i;
+
+	i = gspca_dev->curr_mode;
+	frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+	PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
+	frsz = PAGE_ALIGN(frsz);
+	gspca_dev->frsz = frsz;
+	if (count > GSPCA_MAX_FRAMES)
+		count = GSPCA_MAX_FRAMES;
+	gspca_dev->frbuf = rvmalloc(frsz * count);
+	if (!gspca_dev->frbuf) {
+		err("frame alloc failed");
+		return -ENOMEM;
+	}
+	gspca_dev->nframes = count;
+	for (i = 0; i < count; i++) {
+		frame = &gspca_dev->frame[i];
+		frame->v4l2_buf.index = i;
+		frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		frame->v4l2_buf.flags = 0;
+		frame->v4l2_buf.field = V4L2_FIELD_NONE;
+		frame->v4l2_buf.length = frsz;
+		frame->v4l2_buf.memory = gspca_dev->memory;
+		frame->v4l2_buf.sequence = 0;
+		frame->data = frame->data_end =
+					gspca_dev->frbuf + i * frsz;
+		frame->v4l2_buf.m.offset = i * frsz;
+	}
+	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+	gspca_dev->last_packet_type = DISCARD_PACKET;
+	gspca_dev->sequence = 0;
+	atomic_set(&gspca_dev->nevent, 0);
+	return 0;
+}
+
+static void frame_free(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	PDEBUG(D_STREAM, "frame free");
+	if (gspca_dev->frbuf != NULL) {
+		rvfree(gspca_dev->frbuf,
+			gspca_dev->nframes * gspca_dev->frsz);
+		gspca_dev->frbuf = NULL;
+		for (i = 0; i < gspca_dev->nframes; i++)
+			gspca_dev->frame[i].data = NULL;
+	}
+	gspca_dev->nframes = 0;
+}
+
+static void destroy_urbs(struct gspca_dev *gspca_dev)
+{
+	struct urb *urb;
+	unsigned int i;
+
+	PDEBUG(D_STREAM, "kill transfer");
+	for (i = 0; i < MAX_NURBS; ++i) {
+		urb = gspca_dev->urb[i];
+		if (urb == NULL)
+			break;
+
+		gspca_dev->urb[i] = NULL;
+		usb_kill_urb(urb);
+		if (urb->transfer_buffer != NULL)
+			usb_buffer_free(gspca_dev->dev,
+					urb->transfer_buffer_length,
+					urb->transfer_buffer,
+					urb->transfer_dma);
+		usb_free_urb(urb);
+	}
+}
+
+/*
+ * search an input isochronous endpoint in an alternate setting
+ */
+static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
+					  __u8 epaddr)
+{
+	struct usb_host_endpoint *ep;
+	int i, attr;
+
+	epaddr |= USB_DIR_IN;
+	for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+		ep = &alt->endpoint[i];
+		if (ep->desc.bEndpointAddress == epaddr) {
+			attr = ep->desc.bmAttributes
+						& USB_ENDPOINT_XFERTYPE_MASK;
+			if (attr == USB_ENDPOINT_XFER_ISOC)
+				return ep;
+			break;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * search an input isochronous endpoint
+ *
+ * The endpoint is defined by the subdriver.
+ * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
+ * This routine may be called many times when the bandwidth is too small
+ * (the bandwidth is checked on urb submit).
+ */
+struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
+{
+	struct usb_interface *intf;
+	struct usb_host_endpoint *ep;
+	int i, ret;
+
+	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+	ep = NULL;
+	i = gspca_dev->alt;			/* previous alt setting */
+	while (--i > 0) {			/* alt 0 is unusable */
+		ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
+		if (ep)
+			break;
+	}
+	if (ep == NULL) {
+		err("no ISOC endpoint found");
+		return NULL;
+	}
+	PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x",
+			i, ep->desc.bEndpointAddress);
+	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
+	if (ret < 0) {
+		err("set interface err %d", ret);
+		return NULL;
+	}
+	gspca_dev->alt = i;		/* memorize the current alt setting */
+	return ep;
+}
+
+/*
+ * create the isochronous URBs
+ */
+static int create_urbs(struct gspca_dev *gspca_dev,
+			struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	int n, nurbs, i, psize, npkt, bsize;
+
+	/* calculate the packet size and the number of packets */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+	/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+	psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+	npkt = ISO_MAX_SIZE / psize;
+	if (npkt > ISO_MAX_PKT)
+		npkt = ISO_MAX_PKT;
+	bsize = psize * npkt;
+	PDEBUG(D_STREAM,
+		"isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
+	nurbs = DEF_NURBS;
+	gspca_dev->nurbs = nurbs;
+	for (n = 0; n < nurbs; n++) {
+		urb = usb_alloc_urb(npkt, GFP_KERNEL);
+		if (!urb) {
+			err("usb_alloc_urb failed");
+			return -ENOMEM;
+		}
+		urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+						bsize,
+						GFP_KERNEL,
+						&urb->transfer_dma);
+
+		if (urb->transfer_buffer == NULL) {
+			usb_free_urb(urb);
+			destroy_urbs(gspca_dev);
+			err("usb_buffer_urb failed");
+			return -ENOMEM;
+		}
+		gspca_dev->urb[n] = urb;
+		urb->dev = gspca_dev->dev;
+		urb->context = gspca_dev;
+		urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+					    ep->desc.bEndpointAddress);
+		urb->transfer_flags = URB_ISO_ASAP
+					| URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = ep->desc.bInterval;
+		urb->complete = isoc_irq;
+		urb->number_of_packets = npkt;
+		urb->transfer_buffer_length = bsize;
+		for (i = 0; i < npkt; i++) {
+			urb->iso_frame_desc[i].length = psize;
+			urb->iso_frame_desc[i].offset = psize * i;
+		}
+	}
+	return 0;
+}
+
+/*
+ * start the USB transfer
+ */
+static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+{
+	struct usb_host_endpoint *ep;
+	int n, ret;
+
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+
+	/* set the higher alternate setting and
+	 * loop until urb submit succeeds */
+	gspca_dev->alt = gspca_dev->nbalt;
+	for (;;) {
+		PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
+		ep = get_isoc_ep(gspca_dev);
+		if (ep == NULL) {
+			ret = -EIO;
+			goto out;
+		}
+		ret = create_urbs(gspca_dev, ep);
+		if (ret < 0)
+			goto out;
+
+		/* start the cam */
+		gspca_dev->sd_desc->start(gspca_dev);
+		gspca_dev->streaming = 1;
+		atomic_set(&gspca_dev->nevent, 0);
+
+		/* submit the URBs */
+		for (n = 0; n < gspca_dev->nurbs; n++) {
+			ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
+			if (ret < 0) {
+				PDEBUG(D_ERR|D_STREAM,
+					"usb_submit_urb [%d] err %d", n, ret);
+				gspca_dev->streaming = 0;
+				destroy_urbs(gspca_dev);
+				if (ret == -ENOSPC)
+					break;	/* try the previous alt */
+				goto out;
+			}
+		}
+		if (ret >= 0)
+			break;
+	}
+out:
+	mutex_unlock(&gspca_dev->usb_lock);
+	return ret;
+}
+
+static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
+	if (ret < 0)
+		PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);
+	return ret;
+}
+
+/* Note both the queue and the usb lock should be hold when calling this */
+static void gspca_stream_off(struct gspca_dev *gspca_dev)
+{
+	gspca_dev->streaming = 0;
+	atomic_set(&gspca_dev->nevent, 0);
+	if (gspca_dev->present) {
+		gspca_dev->sd_desc->stopN(gspca_dev);
+		destroy_urbs(gspca_dev);
+		gspca_set_alt0(gspca_dev);
+		gspca_dev->sd_desc->stop0(gspca_dev);
+		PDEBUG(D_STREAM, "stream off OK");
+	}
+}
+
+static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	i = gspca_dev->cam.nmodes - 1;	/* take the highest mode */
+	gspca_dev->curr_mode = i;
+	gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
+	gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
+	gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+}
+
+static int wxh_to_mode(struct gspca_dev *gspca_dev,
+			int width, int height)
+{
+	int i;
+
+	for (i = gspca_dev->cam.nmodes; --i > 0; ) {
+		if (width >= gspca_dev->cam.cam_mode[i].width
+		    && height >= gspca_dev->cam.cam_mode[i].height)
+			break;
+	}
+	return i;
+}
+
+/*
+ * search a mode with the right pixel format
+ */
+static int gspca_get_mode(struct gspca_dev *gspca_dev,
+			int mode,
+			int pixfmt)
+{
+	int modeU, modeD;
+
+	modeU = modeD = mode;
+	while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) {
+		if (--modeD >= 0) {
+			if (gspca_dev->cam.cam_mode[modeD].pixelformat
+								== pixfmt)
+				return modeD;
+		}
+		if (++modeU < gspca_dev->cam.nmodes) {
+			if (gspca_dev->cam.cam_mode[modeU].pixelformat
+								== pixfmt)
+				return modeU;
+		}
+	}
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *fmtdesc)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int i, j, index;
+	__u32 fmt_tb[8];
+
+	/* give an index to each format */
+	index = 0;
+	j = 0;
+	for (i = gspca_dev->cam.nmodes; --i >= 0; ) {
+		fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat;
+		j = 0;
+		for (;;) {
+			if (fmt_tb[j] == fmt_tb[index])
+				break;
+			j++;
+		}
+		if (j == index) {
+			if (fmtdesc->index == index)
+				break;		/* new format */
+			index++;
+			if (index >= sizeof fmt_tb / sizeof fmt_tb[0])
+				return -EINVAL;
+		}
+	}
+	if (i < 0)
+		return -EINVAL;		/* no more format */
+
+	fmtdesc->pixelformat = fmt_tb[index];
+	if (gspca_is_compressed(fmt_tb[index]))
+		fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
+	fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
+	fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
+	fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
+	fmtdesc->description[3] = fmtdesc->pixelformat >> 24;
+	fmtdesc->description[4] = '\0';
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int mode;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	mode = gspca_dev->curr_mode;
+	memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+		sizeof fmt->fmt.pix);
+	return 0;
+}
+
+static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
+			struct v4l2_format *fmt)
+{
+	int w, h, mode, mode2;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	w = fmt->fmt.pix.width;
+	h = fmt->fmt.pix.height;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (gspca_debug & D_CONF)
+		PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
+#endif
+	/* search the closest mode for width and height */
+	mode = wxh_to_mode(gspca_dev, w, h);
+
+	/* OK if right palette */
+	if (gspca_dev->cam.cam_mode[mode].pixelformat
+						!= fmt->fmt.pix.pixelformat) {
+
+		/* else, search the closest mode with the same pixel format */
+		mode2 = gspca_get_mode(gspca_dev, mode,
+					fmt->fmt.pix.pixelformat);
+		if (mode2 >= 0)
+			mode = mode2;
+/*		else
+			;		 * no chance, return this mode */
+	}
+	memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+		sizeof fmt->fmt.pix);
+	return mode;			/* used when s_fmt */
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file,
+			      void *priv,
+			      struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int ret;
+
+	ret = try_fmt_vid_cap(gspca_dev, fmt);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *fmt)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	ret = try_fmt_vid_cap(gspca_dev, fmt);
+	if (ret < 0)
+		goto out;
+
+	if (gspca_dev->nframes != 0
+	    && fmt->fmt.pix.sizeimage > gspca_dev->frsz) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (ret == gspca_dev->curr_mode) {
+		ret = 0;
+		goto out;			/* same mode */
+	}
+
+	if (gspca_dev->streaming) {
+		ret = -EBUSY;
+		goto out;
+	}
+	gspca_dev->width = fmt->fmt.pix.width;
+	gspca_dev->height = fmt->fmt.pix.height;
+	gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
+	gspca_dev->curr_mode = ret;
+
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+	struct gspca_dev *gspca_dev;
+	int ret;
+
+	PDEBUG(D_STREAM, "%s open", current->comm);
+	gspca_dev = (struct gspca_dev *) video_devdata(file);
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	if (!gspca_dev->present) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* if not done yet, initialize the sensor */
+	if (gspca_dev->users == 0) {
+		if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+			ret = -ERESTARTSYS;
+			goto out;
+		}
+		ret = gspca_dev->sd_desc->open(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+		if (ret != 0) {
+			PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
+			goto out;
+		}
+	} else if (gspca_dev->users > 4) {	/* (arbitrary value) */
+		ret = -EBUSY;
+		goto out;
+	}
+	gspca_dev->users++;
+	file->private_data = gspca_dev;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	/* activate the v4l2 debug */
+	if (gspca_debug & D_V4L2)
+		gspca_dev->vdev.debug |= 3;
+	else
+		gspca_dev->vdev.debug &= ~3;
+#endif
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	if (ret != 0)
+		PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
+	else
+		PDEBUG(D_STREAM, "open done");
+	return ret;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+	struct gspca_dev *gspca_dev = file->private_data;
+
+	PDEBUG(D_STREAM, "%s close", current->comm);
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	gspca_dev->users--;
+
+	/* if the file did the capture, free the streaming resources */
+	if (gspca_dev->capt_file == file) {
+		mutex_lock(&gspca_dev->usb_lock);
+		if (gspca_dev->streaming)
+			gspca_stream_off(gspca_dev);
+		gspca_dev->sd_desc->close(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+		frame_free(gspca_dev);
+		gspca_dev->capt_file = NULL;
+		gspca_dev->memory = GSPCA_MEMORY_NO;
+	}
+	file->private_data = NULL;
+	mutex_unlock(&gspca_dev->queue_lock);
+	PDEBUG(D_STREAM, "close done");
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+			   struct v4l2_capability *cap)
+{
+	struct gspca_dev *gspca_dev = priv;
+
+	memset(cap, 0, sizeof *cap);
+	strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+	strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card);
+	strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,
+		sizeof cap->bus_info);
+	cap->version = DRIVER_VERSION_NUMBER;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+			  | V4L2_CAP_STREAMING
+			  | V4L2_CAP_READWRITE;
+	return 0;
+}
+
+/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
+static int vidioc_queryctrl(struct file *file, void *priv,
+			   struct v4l2_queryctrl *q_ctrl)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int i;
+	u32 id;
+
+	id = q_ctrl->id;
+	if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+		id &= V4L2_CTRL_ID_MASK;
+		id++;
+		for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+			if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+				memcpy(q_ctrl,
+					&gspca_dev->sd_desc->ctrls[i].qctrl,
+					sizeof *q_ctrl);
+				return 0;
+			}
+		}
+		return -EINVAL;
+	}
+	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+		if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+			memcpy(q_ctrl,
+				&gspca_dev->sd_desc->ctrls[i].qctrl,
+				sizeof *q_ctrl);
+			return 0;
+		}
+	}
+	if (id >= V4L2_CID_BASE
+	    && id <= V4L2_CID_LASTP1) {
+		q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct gspca_dev *gspca_dev = priv;
+	const struct ctrl *ctrls;
+	int i, ret;
+
+	for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+	     i < gspca_dev->sd_desc->nctrls;
+	     i++, ctrls++) {
+		if (ctrl->id != ctrls->qctrl.id)
+			continue;
+		if (ctrl->value < ctrls->qctrl.minimum
+		    && ctrl->value > ctrls->qctrl.maximum)
+			return -ERANGE;
+		PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+			return -ERESTARTSYS;
+		ret = ctrls->set(gspca_dev, ctrl->value);
+		mutex_unlock(&gspca_dev->usb_lock);
+		return ret;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	struct gspca_dev *gspca_dev = priv;
+
+	const struct ctrl *ctrls;
+	int i, ret;
+
+	for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+	     i < gspca_dev->sd_desc->nctrls;
+	     i++, ctrls++) {
+		if (ctrl->id != ctrls->qctrl.id)
+			continue;
+		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+			return -ERESTARTSYS;
+		ret = ctrls->get(gspca_dev, &ctrl->value);
+		mutex_unlock(&gspca_dev->usb_lock);
+		return ret;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+			    struct v4l2_querymenu *qmenu)
+{
+	struct gspca_dev *gspca_dev = priv;
+
+	if (!gspca_dev->sd_desc->querymenu)
+		return -EINVAL;
+	return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+	struct gspca_dev *gspca_dev = priv;
+
+	if (input->index != 0)
+		return -EINVAL;
+	memset(input, 0, sizeof *input);
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	strncpy(input->name, gspca_dev->sd_desc->name,
+		sizeof input->name);
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+	return (0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int i, ret = 0;
+
+	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	switch (rb->memory) {
+	case GSPCA_MEMORY_READ:			/* (internal call) */
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_USERPTR:
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	if (gspca_dev->memory != GSPCA_MEMORY_NO
+	    && gspca_dev->memory != rb->memory) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* only one file may do the capture */
+	if (gspca_dev->capt_file != NULL
+	    && gspca_dev->capt_file != file) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* if allocated, the buffers must not be mapped */
+	for (i = 0; i < gspca_dev->nframes; i++) {
+		if (gspca_dev->frame[i].vma_use_count) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	/* stop streaming */
+	if (gspca_dev->streaming) {
+		mutex_lock(&gspca_dev->usb_lock);
+		gspca_stream_off(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
+
+	/* free the previous allocated buffers, if any */
+	if (gspca_dev->nframes != 0) {
+		frame_free(gspca_dev);
+		gspca_dev->capt_file = NULL;
+	}
+	if (rb->count == 0)			/* unrequest */
+		goto out;
+	gspca_dev->memory = rb->memory;
+	ret = frame_alloc(gspca_dev, rb->count);
+	if (ret == 0) {
+		rb->count = gspca_dev->nframes;
+		gspca_dev->capt_file = file;
+	}
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = priv;
+	struct gspca_frame *frame;
+
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+	    || v4l2_buf->index < 0
+	    || v4l2_buf->index >= gspca_dev->nframes)
+		return -EINVAL;
+
+	frame = &gspca_dev->frame[v4l2_buf->index];
+	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type buf_type)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int ret;
+
+	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	if (!gspca_dev->present) {
+		ret = -ENODEV;
+		goto out;
+	}
+	if (gspca_dev->nframes == 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (!gspca_dev->streaming) {
+		ret = gspca_init_transfer(gspca_dev);
+		if (ret < 0)
+			goto out;
+	}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (gspca_debug & D_STREAM) {
+		PDEBUG_MODE("stream on OK",
+			gspca_dev->pixfmt,
+			gspca_dev->width,
+			gspca_dev->height);
+	}
+#endif
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int i, ret;
+
+	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (!gspca_dev->streaming)
+		return 0;
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	/* stop streaming */
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+		ret = -ERESTARTSYS;
+		goto out;
+	}
+	gspca_stream_off(gspca_dev);
+	mutex_unlock(&gspca_dev->usb_lock);
+
+	/* empty the application queues */
+	for (i = 0; i < gspca_dev->nframes; i++)
+		gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
+	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+	gspca_dev->last_packet_type = DISCARD_PACKET;
+	gspca_dev->sequence = 0;
+	atomic_set(&gspca_dev->nevent, 0);
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+			struct v4l2_jpegcompression *jpegcomp)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int ret;
+
+	if (!gspca_dev->sd_desc->get_jcomp)
+		return -EINVAL;
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+	ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+	mutex_unlock(&gspca_dev->usb_lock);
+	return ret;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+			struct v4l2_jpegcompression *jpegcomp)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
+	if (!gspca_dev->sd_desc->set_jcomp)
+		return -EINVAL;
+	ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+	mutex_unlock(&gspca_dev->usb_lock);
+	return ret;
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+			struct v4l2_streamparm *parm)
+{
+	struct gspca_dev *gspca_dev = priv;
+
+	memset(parm, 0, sizeof *parm);
+	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	parm->parm.capture.readbuffers = gspca_dev->nbufread;
+	return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+			struct v4l2_streamparm *parm)
+{
+	struct gspca_dev *gspca_dev = priv;
+	int n;
+
+	n = parm->parm.capture.readbuffers;
+	if (n == 0 || n > GSPCA_MAX_FRAMES)
+		parm->parm.capture.readbuffers = gspca_dev->nbufread;
+	else
+		gspca_dev->nbufread = n;
+	return 0;
+}
+
+static int vidioc_s_std(struct file *filp, void *priv,
+			v4l2_std_id *parm)
+{
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv,
+			struct video_mbuf *mbuf)
+{
+	struct gspca_dev *gspca_dev = file->private_data;
+	int i;
+
+	PDEBUG(D_STREAM, "cgmbuf");
+	if (gspca_dev->nframes == 0) {
+		int ret;
+
+		{
+			struct v4l2_format fmt;
+
+			memset(&fmt, 0, sizeof fmt);
+			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			i = gspca_dev->cam.nmodes - 1;	/* highest mode */
+			fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
+			fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
+			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
+			ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
+			if (ret != 0)
+				return ret;
+		}
+		{
+			struct v4l2_requestbuffers rb;
+
+			memset(&rb, 0, sizeof rb);
+			rb.count = 4;
+			rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			rb.memory = V4L2_MEMORY_MMAP;
+			ret = vidioc_reqbufs(file, priv, &rb);
+			if (ret != 0)
+				return ret;
+		}
+	}
+	mbuf->frames = gspca_dev->nframes;
+	mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
+	for (i = 0; i < mbuf->frames; i++)
+		mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
+	return 0;
+}
+#endif
+
+static int dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct gspca_dev *gspca_dev = file->private_data;
+	struct gspca_frame *frame;
+	struct page *page;
+	unsigned long addr, start, size;
+	int i, ret;
+
+	start = vma->vm_start;
+	size = vma->vm_end - vma->vm_start;
+	PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+	if (!gspca_dev->present) {
+		ret = -ENODEV;
+		goto out;
+	}
+	if (gspca_dev->capt_file != file) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame = NULL;
+	for (i = 0; i < gspca_dev->nframes; ++i) {
+		if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) {
+			PDEBUG(D_STREAM, "mmap bad memory type");
+			break;
+		}
+		if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT)
+						== vma->vm_pgoff) {
+			frame = &gspca_dev->frame[i];
+			break;
+		}
+	}
+	if (frame == NULL) {
+		PDEBUG(D_STREAM, "mmap no frame buffer found");
+		ret = -EINVAL;
+		goto out;
+	}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	/* v4l1 maps all the buffers */
+	if (i != 0
+	    || size != frame->v4l2_buf.length * gspca_dev->nframes)
+#endif
+	    if (size != frame->v4l2_buf.length) {
+		PDEBUG(D_STREAM, "mmap bad size");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * - VM_IO marks the area as being a mmaped region for I/O to a
+	 *   device. It also prevents the region from being core dumped.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	addr = (unsigned long) frame->data;
+	while (size > 0) {
+		page = vmalloc_to_page((void *) addr);
+		ret = vm_insert_page(vma, start, page);
+		if (ret < 0)
+			goto out;
+		start += PAGE_SIZE;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &gspca_vm_ops;
+	vma->vm_private_data = frame;
+	gspca_vm_open(vma);
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+/*
+ * wait for a video frame
+ *
+ * If a frame is ready, its index is returned.
+ */
+static int frame_wait(struct gspca_dev *gspca_dev,
+			int nonblock_ing)
+{
+	struct gspca_frame *frame;
+	int i, j, ret;
+
+	/* check if a frame is ready */
+	i = gspca_dev->fr_o;
+	j = gspca_dev->fr_queue[i];
+	frame = &gspca_dev->frame[j];
+	if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) {
+		atomic_dec(&gspca_dev->nevent);
+		goto ok;
+	}
+	if (nonblock_ing)			/* no frame yet */
+		return -EAGAIN;
+
+	/* wait till a frame is ready */
+	for (;;) {
+		ret = wait_event_interruptible_timeout(gspca_dev->wq,
+					atomic_read(&gspca_dev->nevent) > 0,
+					msecs_to_jiffies(3000));
+		if (ret <= 0) {
+			if (ret < 0)
+				return ret;	/* interrupt */
+			return -EIO;		/* timeout */
+		}
+		atomic_dec(&gspca_dev->nevent);
+		if (!gspca_dev->streaming || !gspca_dev->present)
+			return -EIO;
+		i = gspca_dev->fr_o;
+		j = gspca_dev->fr_queue[i];
+		frame = &gspca_dev->frame[j];
+		if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+			break;
+	}
+ok:
+	gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
+	PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
+		gspca_dev->fr_q,
+		gspca_dev->fr_i,
+		gspca_dev->fr_o);
+
+	if (gspca_dev->sd_desc->dq_callback) {
+		mutex_lock(&gspca_dev->usb_lock);
+		gspca_dev->sd_desc->dq_callback(gspca_dev);
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
+	return j;
+}
+
+/*
+ * dequeue a video buffer
+ *
+ * If nonblock_ing is false, block until a buffer is available.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv,
+			struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = priv;
+	struct gspca_frame *frame;
+	int i, ret;
+
+	PDEBUG(D_FRAM, "dqbuf");
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (v4l2_buf->memory != gspca_dev->memory)
+		return -EINVAL;
+
+	/* if not streaming, be sure the application will not loop forever */
+	if (!(file->f_flags & O_NONBLOCK)
+	    && !gspca_dev->streaming && gspca_dev->users == 1)
+		return -EINVAL;
+
+	/* only the capturing file may dequeue */
+	if (gspca_dev->capt_file != file)
+		return -EINVAL;
+
+	/* only one dequeue / read at a time */
+	if (mutex_lock_interruptible(&gspca_dev->read_lock))
+		return -ERESTARTSYS;
+
+	ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
+	if (ret < 0)
+		goto out;
+	i = ret;				/* frame index */
+	frame = &gspca_dev->frame[i];
+	if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
+		if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+				 frame->data,
+				 frame->v4l2_buf.bytesused)) {
+			PDEBUG(D_ERR|D_STREAM,
+				"dqbuf cp to user failed");
+			ret = -EFAULT;
+			goto out;
+		}
+	}
+	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+	memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+	PDEBUG(D_FRAM, "dqbuf %d", i);
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->read_lock);
+	return ret;
+}
+
+/*
+ * queue a video buffer
+ *
+ * Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+static int vidioc_qbuf(struct file *file, void *priv,
+			struct v4l2_buffer *v4l2_buf)
+{
+	struct gspca_dev *gspca_dev = priv;
+	struct gspca_frame *frame;
+	int i, index, ret;
+
+	PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+		return -ERESTARTSYS;
+
+	index = v4l2_buf->index;
+	if ((unsigned) index >= gspca_dev->nframes) {
+		PDEBUG(D_FRAM,
+			"qbuf idx %d >= %d", index, gspca_dev->nframes);
+		ret = -EINVAL;
+		goto out;
+	}
+	if (v4l2_buf->memory != gspca_dev->memory) {
+		PDEBUG(D_FRAM, "qbuf bad memory type");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame = &gspca_dev->frame[index];
+	if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {
+		PDEBUG(D_FRAM, "qbuf bad state");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
+/*	frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
+
+	if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
+		frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
+		frame->v4l2_buf.length = v4l2_buf->length;
+	}
+
+	/* put the buffer in the 'queued' queue */
+	i = gspca_dev->fr_q;
+	gspca_dev->fr_queue[i] = index;
+	gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
+	PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
+		gspca_dev->fr_q,
+		gspca_dev->fr_i,
+		gspca_dev->fr_o);
+
+	v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+	v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
+	ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+/*
+ * allocate the resources for read()
+ */
+static int read_alloc(struct gspca_dev *gspca_dev,
+			struct file *file)
+{
+	struct v4l2_buffer v4l2_buf;
+	int i, ret;
+
+	PDEBUG(D_STREAM, "read alloc");
+	if (gspca_dev->nframes == 0) {
+		struct v4l2_requestbuffers rb;
+
+		memset(&rb, 0, sizeof rb);
+		rb.count = gspca_dev->nbufread;
+		rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		rb.memory = GSPCA_MEMORY_READ;
+		ret = vidioc_reqbufs(file, gspca_dev, &rb);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read reqbuf err %d", ret);
+			return ret;
+		}
+		memset(&v4l2_buf, 0, sizeof v4l2_buf);
+		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		v4l2_buf.memory = GSPCA_MEMORY_READ;
+		for (i = 0; i < gspca_dev->nbufread; i++) {
+			v4l2_buf.index = i;
+			ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+			if (ret != 0) {
+				PDEBUG(D_STREAM, "read qbuf err: %d", ret);
+				return ret;
+			}
+		}
+		gspca_dev->memory = GSPCA_MEMORY_READ;
+	}
+
+	/* start streaming */
+	ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	if (ret != 0)
+		PDEBUG(D_STREAM, "read streamon err %d", ret);
+	return ret;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+	struct gspca_dev *gspca_dev = file->private_data;
+	int i, ret;
+
+	PDEBUG(D_FRAM, "poll");
+
+	poll_wait(file, &gspca_dev->wq, wait);
+	if (!gspca_dev->present)
+		return POLLERR;
+
+	/* if reqbufs is not done, the user would use read() */
+	if (gspca_dev->nframes == 0) {
+		if (gspca_dev->memory != GSPCA_MEMORY_NO)
+			return POLLERR;		/* not the 1st time */
+		ret = read_alloc(gspca_dev, file);
+		if (ret != 0)
+			return POLLERR;
+	}
+
+	if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
+		return POLLERR;
+	if (!gspca_dev->present) {
+		ret = POLLERR;
+		goto out;
+	}
+
+	/* check the next incoming buffer */
+	i = gspca_dev->fr_o;
+	i = gspca_dev->fr_queue[i];
+	if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+		ret = POLLIN | POLLRDNORM;	/* something to read */
+	else
+		ret = 0;
+out:
+	mutex_unlock(&gspca_dev->queue_lock);
+	return ret;
+}
+
+static ssize_t dev_read(struct file *file, char __user *data,
+		    size_t count, loff_t *ppos)
+{
+	struct gspca_dev *gspca_dev = file->private_data;
+	struct gspca_frame *frame;
+	struct v4l2_buffer v4l2_buf;
+	struct timeval timestamp;
+	int n, ret, ret2;
+
+	PDEBUG(D_FRAM, "read (%zd)", count);
+	if (!gspca_dev->present)
+		return -ENODEV;
+	switch (gspca_dev->memory) {
+	case GSPCA_MEMORY_NO:			/* first time */
+		ret = read_alloc(gspca_dev, file);
+		if (ret != 0)
+			return ret;
+		break;
+	case GSPCA_MEMORY_READ:
+		if (gspca_dev->capt_file == file)
+			break;
+		/* fall thru */
+	default:
+		return -EINVAL;
+	}
+
+	/* get a frame */
+	jiffies_to_timeval(get_jiffies_64(), &timestamp);
+	timestamp.tv_sec--;
+	n = 2;
+	for (;;) {
+		memset(&v4l2_buf, 0, sizeof v4l2_buf);
+		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		v4l2_buf.memory = GSPCA_MEMORY_READ;
+		ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read dqbuf err %d", ret);
+			return ret;
+		}
+
+		/* if the process slept for more than 1 second,
+		 * get anewer frame */
+		frame = &gspca_dev->frame[v4l2_buf.index];
+		if (--n < 0)
+			break;			/* avoid infinite loop */
+		if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec)
+			break;
+		ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+		if (ret != 0) {
+			PDEBUG(D_STREAM, "read qbuf err %d", ret);
+			return ret;
+		}
+	}
+
+	/* copy the frame */
+	if (count > frame->v4l2_buf.bytesused)
+		count = frame->v4l2_buf.bytesused;
+	ret = copy_to_user(data, frame->data, count);
+	if (ret != 0) {
+		PDEBUG(D_ERR|D_STREAM,
+			"read cp to user lack %d / %zd", ret, count);
+		ret = -EFAULT;
+		goto out;
+	}
+	ret = count;
+out:
+	/* in each case, requeue the buffer */
+	ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+	if (ret2 != 0)
+		return ret2;
+	return ret;
+}
+
+static void dev_release(struct video_device *vfd)
+{
+	/* nothing */
+}
+
+static struct file_operations dev_fops = {
+	.owner = THIS_MODULE,
+	.open = dev_open,
+	.release = dev_close,
+	.read = dev_read,
+	.mmap = dev_mmap,
+	.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = v4l_compat_ioctl32,
+#endif
+	.llseek = no_llseek,
+	.poll	= dev_poll,
+};
+
+static struct video_device gspca_template = {
+	.name = "gspca main driver",
+	.type = VID_TYPE_CAPTURE,
+	.fops = &dev_fops,
+	.release = dev_release,		/* mandatory */
+	.minor = -1,
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+	.vidioc_querymenu	= vidioc_querymenu,
+	.vidioc_enum_input	= vidioc_enum_input,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_g_jpegcomp	= vidioc_g_jpegcomp,
+	.vidioc_s_jpegcomp	= vidioc_s_jpegcomp,
+	.vidioc_g_parm		= vidioc_g_parm,
+	.vidioc_s_parm		= vidioc_s_parm,
+	.vidioc_s_std		= vidioc_s_std,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf          = vidiocgmbuf,
+#endif
+};
+
+/*
+ * probe and create a new gspca device
+ *
+ * This function must be called by the sub-driver when it is
+ * called for probing a new device.
+ */
+int gspca_dev_probe(struct usb_interface *intf,
+		const struct usb_device_id *id,
+		const struct sd_desc *sd_desc,
+		int dev_size,
+		struct module *module)
+{
+	struct usb_interface_descriptor *interface;
+	struct gspca_dev *gspca_dev;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int ret;
+
+	PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
+
+	/* we don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return -ENODEV;
+	interface = &intf->cur_altsetting->desc;
+	if (interface->bInterfaceNumber > 0)
+		return -ENODEV;
+
+	/* create the device */
+	if (dev_size < sizeof *gspca_dev)
+		dev_size = sizeof *gspca_dev;
+	gspca_dev = kzalloc(dev_size, GFP_KERNEL);
+	if (gspca_dev == NULL) {
+		err("couldn't kzalloc gspca struct");
+		return -EIO;
+	}
+	gspca_dev->dev = dev;
+	gspca_dev->iface = interface->bInterfaceNumber;
+	gspca_dev->nbalt = intf->num_altsetting;
+	gspca_dev->sd_desc = sd_desc;
+/*	gspca_dev->users = 0;			(done by kzalloc) */
+	gspca_dev->nbufread = 2;
+
+	/* configure the subdriver */
+	ret = gspca_dev->sd_desc->config(gspca_dev, id);
+	if (ret < 0)
+		goto out;
+	ret = gspca_set_alt0(gspca_dev);
+	if (ret < 0)
+		goto out;
+	gspca_set_default_mode(gspca_dev);
+
+	mutex_init(&gspca_dev->usb_lock);
+	mutex_init(&gspca_dev->read_lock);
+	mutex_init(&gspca_dev->queue_lock);
+	init_waitqueue_head(&gspca_dev->wq);
+
+	/* init video stuff */
+	memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
+	gspca_dev->vdev.dev = &dev->dev;
+	memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops);
+	gspca_dev->vdev.fops = &gspca_dev->fops;
+	gspca_dev->fops.owner = module;		/* module protection */
+	ret = video_register_device(&gspca_dev->vdev,
+				  VFL_TYPE_GRABBER,
+				  video_nr);
+	if (ret < 0) {
+		err("video_register_device err %d", ret);
+		goto out;
+	}
+
+	gspca_dev->present = 1;
+	usb_set_intfdata(intf, gspca_dev);
+	PDEBUG(D_PROBE, "probe ok");
+	return 0;
+out:
+	kfree(gspca_dev);
+	return ret;
+}
+EXPORT_SYMBOL(gspca_dev_probe);
+
+/*
+ * USB disconnection
+ *
+ * This function must be called by the sub-driver
+ * when the device disconnects, after the specific resources are freed.
+ */
+void gspca_disconnect(struct usb_interface *intf)
+{
+	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+	if (!gspca_dev)
+		return;
+	gspca_dev->present = 0;
+	mutex_lock(&gspca_dev->queue_lock);
+	mutex_lock(&gspca_dev->usb_lock);
+	gspca_dev->streaming = 0;
+	destroy_urbs(gspca_dev);
+	mutex_unlock(&gspca_dev->usb_lock);
+	mutex_unlock(&gspca_dev->queue_lock);
+	while (gspca_dev->users != 0) {		/* wait until fully closed */
+		atomic_inc(&gspca_dev->nevent);
+		wake_up_interruptible(&gspca_dev->wq);	/* wake processes */
+		schedule();
+	}
+/* We don't want people trying to open up the device */
+	video_unregister_device(&gspca_dev->vdev);
+/* Free the memory */
+	kfree(gspca_dev);
+	PDEBUG(D_PROBE, "disconnect complete");
+}
+EXPORT_SYMBOL(gspca_disconnect);
+
+/* -- cam driver utility functions -- */
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+   http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee)
+{
+	int i, steps, gain, orig_gain, exposure, orig_exposure, autogain;
+	const struct ctrl *gain_ctrl = NULL;
+	const struct ctrl *exposure_ctrl = NULL;
+	const struct ctrl *autogain_ctrl = NULL;
+	int retval = 0;
+
+	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
+			gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
+		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
+			exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
+		if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN)
+			autogain_ctrl = &gspca_dev->sd_desc->ctrls[i];
+	}
+	if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) {
+		PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called "
+			"on cam without (auto)gain/exposure");
+		return 0;
+	}
+
+	if (gain_ctrl->get(gspca_dev, &gain) ||
+			exposure_ctrl->get(gspca_dev, &exposure) ||
+			autogain_ctrl->get(gspca_dev, &autogain) || !autogain)
+		return 0;
+
+	orig_gain = gain;
+	orig_exposure = exposure;
+
+	/* If we are of a multiple of deadzone, do multiple steps to reach the
+	   desired lumination fast (with the risc of a slight overshoot) */
+	steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",
+		avg_lum, desired_avg_lum, steps);
+
+	for (i = 0; i < steps; i++) {
+		if (avg_lum > desired_avg_lum) {
+			if (gain > gain_knee)
+				gain--;
+			else if (exposure > exposure_knee)
+				exposure--;
+			else if (gain > gain_ctrl->qctrl.default_value)
+				gain--;
+			else if (exposure > exposure_ctrl->qctrl.minimum)
+				exposure--;
+			else if (gain > gain_ctrl->qctrl.minimum)
+				gain--;
+			else
+				break;
+		} else {
+			if (gain < gain_ctrl->qctrl.default_value)
+				gain++;
+			else if (exposure < exposure_knee)
+				exposure++;
+			else if (gain < gain_knee)
+				gain++;
+			else if (exposure < exposure_ctrl->qctrl.maximum)
+				exposure++;
+			else if (gain < gain_ctrl->qctrl.maximum)
+				gain++;
+			else
+				break;
+		}
+	}
+
+	if (gain != orig_gain) {
+		gain_ctrl->set(gspca_dev, gain);
+		retval = 1;
+	}
+	if (exposure != orig_exposure) {
+		exposure_ctrl->set(gspca_dev, exposure);
+		retval = 1;
+	}
+
+	return retval;
+}
+EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
+
+/* -- module insert / remove -- */
+static int __init gspca_init(void)
+{
+	info("main v%s registered", version);
+	return 0;
+}
+static void __exit gspca_exit(void)
+{
+	info("main deregistered");
+}
+
+module_init(gspca_init);
+module_exit(gspca_exit);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(debug, gspca_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		"Debug (bit) 0x01:error 0x02:probe 0x04:config"
+		" 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+		" 0x0100: v4l2");
+#endif
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
new file mode 100644
index 0000000..3fd2c4e
--- /dev/null
+++ b/drivers/media/video/gspca/gspca.h
@@ -0,0 +1,176 @@
+#ifndef GSPCAV2_H
+#define GSPCAV2_H
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* GSPCA our debug messages */
+extern int gspca_debug;
+#define PDEBUG(level, fmt, args...) \
+	do {\
+		if (gspca_debug & (level)) \
+			printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+	} while (0)
+#define D_ERR  0x01
+#define D_PROBE 0x02
+#define D_CONF 0x04
+#define D_STREAM 0x08
+#define D_FRAM 0x10
+#define D_PACK 0x20
+#define D_USBI 0x40
+#define D_USBO 0x80
+#define D_V4L2 0x0100
+#else
+#define PDEBUG(level, fmt, args...)
+#endif
+#undef err
+#define err(fmt, args...) \
+	do {\
+		printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \
+	} while (0)
+#undef info
+#define info(fmt, args...) \
+	do {\
+		printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+	} while (0)
+#undef warn
+#define warn(fmt, args...) \
+	do {\
+		printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \
+	} while (0)
+
+#define GSPCA_MAX_FRAMES 16	/* maximum number of video frame buffers */
+/* ISOC transfers */
+#define MAX_NURBS 16		/* max number of URBs */
+#define ISO_MAX_PKT 32		/* max number of packets in an ISOC transfer */
+#define ISO_MAX_SIZE 0x8000	/* max size of one URB buffer (32 Kb) */
+
+/* device information - set at probe time */
+struct cam {
+	char *dev_name;
+	struct v4l2_pix_format *cam_mode;	/* size nmodes */
+	char nmodes;
+	__u8 epaddr;
+};
+
+struct gspca_dev;
+struct gspca_frame;
+
+/* subdriver operations */
+typedef int (*cam_op) (struct gspca_dev *);
+typedef void (*cam_v_op) (struct gspca_dev *);
+typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
+typedef int (*cam_jpg_op) (struct gspca_dev *,
+				struct v4l2_jpegcompression *);
+typedef int (*cam_qmnu_op) (struct gspca_dev *,
+			struct v4l2_querymenu *);
+typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
+				struct gspca_frame *frame,
+				__u8 *data,
+				int len);
+
+struct ctrl {
+	struct v4l2_queryctrl qctrl;
+	int (*set)(struct gspca_dev *, __s32);
+	int (*get)(struct gspca_dev *, __s32 *);
+};
+
+/* subdriver description */
+struct sd_desc {
+/* information */
+	const char *name;	/* sub-driver name */
+/* controls */
+	const struct ctrl *ctrls;
+	int nctrls;
+/* operations */
+	cam_cf_op config;	/* called on probe */
+	cam_op open;		/* called on open */
+	cam_v_op start;		/* called on stream on */
+	cam_v_op stopN;		/* called on stream off - main alt */
+	cam_v_op stop0;		/* called on stream off - alt 0 */
+	cam_v_op close;		/* called on close */
+	cam_pkt_op pkt_scan;
+/* optional operations */
+	cam_v_op dq_callback;	/* called when a frame has been dequeued */
+	cam_jpg_op get_jcomp;
+	cam_jpg_op set_jcomp;
+	cam_qmnu_op querymenu;
+};
+
+/* packet types when moving from iso buf to frame buf */
+#define DISCARD_PACKET	0
+#define FIRST_PACKET	1
+#define INTER_PACKET	2
+#define LAST_PACKET	3
+
+struct gspca_frame {
+	__u8 *data;			/* frame buffer */
+	__u8 *data_end;			/* end of frame while filling */
+	int vma_use_count;
+	struct v4l2_buffer v4l2_buf;
+};
+
+struct gspca_dev {
+	struct video_device vdev;	/* !! must be the first item */
+	struct file_operations fops;
+	struct usb_device *dev;
+	struct file *capt_file;		/* file doing video capture */
+
+	struct cam cam;				/* device information */
+	const struct sd_desc *sd_desc;		/* subdriver description */
+
+	__u8 usb_buf[8];			/* buffer for USB exchanges */
+	struct urb *urb[MAX_NURBS];
+
+	__u8 *frbuf;				/* buffer for nframes */
+	struct gspca_frame frame[GSPCA_MAX_FRAMES];
+	__u32 frsz;				/* frame size */
+	char nframes;				/* number of frames */
+	char fr_i;				/* frame being filled */
+	char fr_q;				/* next frame to queue */
+	char fr_o;				/* next frame to dequeue */
+	signed char fr_queue[GSPCA_MAX_FRAMES];	/* frame queue */
+	char last_packet_type;
+
+	__u8 iface;			/* USB interface number */
+	__u8 alt;			/* USB alternate setting */
+	__u8 curr_mode;			/* current camera mode */
+	__u32 pixfmt;			/* current mode parameters */
+	__u16 width;
+	__u16 height;
+
+	atomic_t nevent;		/* number of frames done */
+	wait_queue_head_t wq;		/* wait queue */
+	struct mutex usb_lock;		/* usb exchange protection */
+	struct mutex read_lock;		/* read protection */
+	struct mutex queue_lock;	/* ISOC queue protection */
+	__u32 sequence;			/* frame sequence number */
+	char streaming;
+	char users;			/* number of opens */
+	char present;			/* device connected */
+	char nbufread;			/* number of buffers for read() */
+	char nurbs;			/* number of allocated URBs */
+	char memory;			/* memory type (V4L2_MEMORY_xxx) */
+	__u8 nbalt;			/* number of USB alternate settings */
+};
+
+int gspca_dev_probe(struct usb_interface *intf,
+		const struct usb_device_id *id,
+		const struct sd_desc *sd_desc,
+		int dev_size,
+		struct module *module);
+void gspca_disconnect(struct usb_interface *intf);
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+				    int packet_type,
+				    struct gspca_frame *frame,
+				    const __u8 *data,
+				    int len);
+int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
+#endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h
new file mode 100644
index 0000000..d823b47
--- /dev/null
+++ b/drivers/media/video/gspca/jpeg.h
@@ -0,0 +1,301 @@
+#ifndef JPEG_H
+#define JPEG_H 1
+/*
+ * Insert a JPEG header at start of frame
+ *
+ * This module is used by the gspca subdrivers.
+ * A special case is done for Conexant webcams.
+ *
+ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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
+ * 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
+ *
+ */
+
+/* start of jpeg frame + quantization table */
+static const unsigned char quant[][0x88] = {
+/* index 0 - Q40*/
+    {
+	0xff, 0xd8,			/* jpeg */
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,					/* quantization table part 1 */
+     20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
+     33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
+     70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
+     109,
+     119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115,
+     126, 129, 124,
+1,					/* quantization table part 2 */
+     21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124,
+     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+     124, 124, 124,
+     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+     124, 124, 124,
+     124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+     124, 124, 124},
+/* index 1 - Q50 */
+    {
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+     16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
+     26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
+     56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87,
+     95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101,
+     103, 99,
+1,
+    17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+/* index 2 Q60 */
+    {
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+     13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
+     21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
+     45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70,
+     76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79,
+1,
+     14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79,
+     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+     79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79},
+/* index 3 - Q70 */
+    {
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+     10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24,
+     16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31,
+     34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52,
+     57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59,
+1,
+     10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59,
+     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59},
+/* index 4 - Q80 */
+    {
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+      6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16,
+     10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20,
+     22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35,
+     38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40,
+1,
+      7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40,
+     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+     40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},
+/* index 5 - Q85 */
+    {
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+     5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12,
+     8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
+     17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26,
+     29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30,
+1,
+     5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30,
+     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+/* index 6 - 86 */
+{
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+	0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
+	0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
+	0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A,
+	0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E,
+	0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13,
+	0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18,
+	0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20,
+	0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C,
+1,
+	0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
+	0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ },
+/* index 7 - 88 */
+{
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+	0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
+	0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A,
+	0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
+	0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C,
+	0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10,
+	0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15,
+	0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B,
+	0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18,
+1,
+	0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
+	0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+},
+/* index 8 - ?? */
+{
+	0xff, 0xd8,
+	0xff, 0xdb, 0x00, 0x84,		/* DQT */
+0,
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
+	0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
+	0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
+	0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09,
+	0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B,
+	0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E,
+	0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C,
+1,
+	0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
+	0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
+}
+};
+
+/* huffman table + start of SOF0 */
+static unsigned char huffman[] = {
+	0xff, 0xc4, 0x01, 0xa2,
+	0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+	0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+	0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03,
+	0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
+	0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
+	0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
+	0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+	0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
+	0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82,
+	0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+	0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
+	0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
+	0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56,
+	0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
+	0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+	0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86,
+	0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
+	0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+	0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
+	0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+	0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+	0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+	0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+	0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+	0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
+	0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
+	0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+	0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06,
+	0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
+	0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+	0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62,
+	0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+	0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28,
+	0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+	0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+	0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+	0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+	0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+	0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+	0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+	0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
+	0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
+	0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+#ifdef CONEX_CAM
+/* the Conexant frames start with SOF0 */
+#else
+	0xff, 0xc0, 0x00, 0x11,		/* SOF0 (start of frame 0 */
+	0x08,				/* data precision */
+#endif
+};
+
+#ifndef CONEX_CAM
+/* variable part:
+ *	0x01, 0xe0,			 height
+ *	0x02, 0x80,			 width
+ *	0x03,				 component number
+ *		0x01,
+ *			0x21,			samples Y
+ */
+
+/* end of header */
+static unsigned char eoh[] = {
+			0x00,		/* quant Y */
+		0x02, 0x11, 0x01,	/* samples CbCr - quant CbCr */
+		0x03, 0x11, 0x01,
+
+	0xff, 0xda, 0x00, 0x0c,		/* SOS (start of scan) */
+	0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+#endif
+
+/* -- output the JPEG header -- */
+static void jpeg_put_header(struct gspca_dev *gspca_dev,
+			    struct gspca_frame *frame,
+			    int qindex,
+			    int samplesY)
+{
+#ifndef CONEX_CAM
+	unsigned char tmpbuf[8];
+#endif
+
+	gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			(unsigned char *) quant[qindex], sizeof quant[0]);
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			(unsigned char *) huffman, sizeof huffman);
+#ifndef CONEX_CAM
+	tmpbuf[0] = gspca_dev->height >> 8;
+	tmpbuf[1] = gspca_dev->height & 0xff;
+	tmpbuf[2] = gspca_dev->width >> 8;
+	tmpbuf[3] = gspca_dev->width & 0xff;
+	tmpbuf[4] = 0x03;		/* component number */
+	tmpbuf[5] = 0x01;		/* first component */
+	tmpbuf[6] = samplesY;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			tmpbuf, 7);
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			eoh, sizeof eoh);
+#endif
+}
+#endif
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
new file mode 100644
index 0000000..88c2b02
--- /dev/null
+++ b/drivers/media/video/gspca/mars.c
@@ -0,0 +1,464 @@
+/*
+ *		Mars-Semi MR97311A library
+ *		Copyright (C) 2005 <bradlch@hotmail.com>
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "mars"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 589,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+};
+
+/* MI Register table //elvis */
+enum {
+	REG_HW_MI_0,
+	REG_HW_MI_1,
+	REG_HW_MI_2,
+	REG_HW_MI_3,
+	REG_HW_MI_4,
+	REG_HW_MI_5,
+	REG_HW_MI_6,
+	REG_HW_MI_7,
+	REG_HW_MI_9 = 0x09,
+	REG_HW_MI_B = 0x0B,
+	REG_HW_MI_C,
+	REG_HW_MI_D,
+	REG_HW_MI_1E = 0x1E,
+	REG_HW_MI_20 = 0x20,
+	REG_HW_MI_2B = 0x2B,
+	REG_HW_MI_2C,
+	REG_HW_MI_2D,
+	REG_HW_MI_2E,
+	REG_HW_MI_35 = 0x35,
+	REG_HW_MI_5F = 0x5f,
+	REG_HW_MI_60,
+	REG_HW_MI_61,
+	REG_HW_MI_62,
+	REG_HW_MI_63,
+	REG_HW_MI_64,
+	REG_HW_MI_F1 = 0xf1,
+	ATTR_TOTAL_MI_REG = 0xf2
+};
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static int reg_w(struct gspca_dev *gspca_dev,
+		 __u16 index, int len)
+{
+	int rc;
+
+	rc = usb_control_msg(gspca_dev->dev,
+			 usb_sndbulkpipe(gspca_dev->dev, 4),
+			 0x12,
+			 0xc8,		/* ?? */
+			 0,		/* value */
+			 index, gspca_dev->usb_buf, len, 500);
+	if (rc < 0)
+		PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+	return rc;
+}
+
+static int reg_w_buf(struct gspca_dev *gspca_dev,
+			__u16 index, __u8 *buf, int len)
+{
+	int rc;
+
+	rc = usb_control_msg(gspca_dev->dev,
+			 usb_sndbulkpipe(gspca_dev->dev, 4),
+			 0x12,
+			 0xc8,		/* ?? */
+			 0,		/* value */
+			 index, buf, len, 500);
+	if (rc < 0)
+		PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+	return rc;
+}
+
+static void bulk_w(struct gspca_dev *gspca_dev,
+		   __u16 *pch,
+		   __u16 Address)
+{
+	gspca_dev->usb_buf[0] = 0x1f;
+	gspca_dev->usb_buf[1] = 0;			/* control byte */
+	gspca_dev->usb_buf[2] = Address;
+	gspca_dev->usb_buf[3] = *pch >> 8;		/* high byte */
+	gspca_dev->usb_buf[4] = *pch;			/* low byte */
+
+	reg_w(gspca_dev, Address, 5);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	sd->qindex = 1;			/* set the quantization table */
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	int err_code;
+	__u8 *data;
+	__u16 *MI_buf;
+	int h_size, v_size;
+	int intpipe;
+
+	PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
+	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8) < 0) {
+		PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
+		return;
+	}
+
+	data = gspca_dev->usb_buf;
+	data[0] = 0x01;		/* address */
+	data[1] = 0x01;
+
+	err_code = reg_w(gspca_dev, data[0], 2);
+	if (err_code < 0)
+		return;
+
+	/*
+	   Initialize the MR97113 chip register
+	 */
+	data = kmalloc(16, GFP_KERNEL);
+	data[0] = 0x00;		/* address */
+	data[1] = 0x0c | 0x01;	/* reg 0 */
+	data[2] = 0x01;		/* reg 1 */
+	h_size = gspca_dev->width;
+	v_size = gspca_dev->height;
+	data[3] = h_size / 8;	/* h_size , reg 2 */
+	data[4] = v_size / 8;	/* v_size , reg 3 */
+	data[5] = 0x30;		/* reg 4, MI, PAS5101 :
+				 *	0x30 for 24mhz , 0x28 for 12mhz */
+	data[6] = 4;		/* reg 5, H start */
+	data[7] = 0xc0;		/* reg 6, gamma 1.5 */
+	data[8] = 3;		/* reg 7, V start */
+/*	if (h_size == 320 ) */
+/*		data[9]= 0x56;	 * reg 8, 24MHz, 2:1 scale down */
+/*	else */
+	data[9] = 0x52;		/* reg 8, 24MHz, no scale down */
+	data[10] = 0x5d;	/* reg 9, I2C device address
+				 *	[for PAS5101 (0x40)] [for MI (0x5d)] */
+
+	err_code = reg_w_buf(gspca_dev, data[0], data, 11);
+	kfree(data);
+	if (err_code < 0)
+		return;
+
+	data = gspca_dev->usb_buf;
+	data[0] = 0x23;		/* address */
+	data[1] = 0x09;		/* reg 35, append frame header */
+
+	err_code = reg_w(gspca_dev, data[0], 2);
+	if (err_code < 0)
+		return;
+
+	data[0] = 0x3c;		/* address */
+/*	if (gspca_dev->width == 1280) */
+/*		data[1] = 200;	 * reg 60, pc-cam frame size
+				 *	(unit: 4KB) 800KB */
+/*	else */
+	data[1] = 50;		/* 50 reg 60, pc-cam frame size
+				 *	(unit: 4KB) 200KB */
+	err_code = reg_w(gspca_dev, data[0], 2);
+	if (err_code < 0)
+		return;
+
+	if (0) {			/* fixed dark-gain */
+		data[1] = 0;		/* reg 94, Y Gain (1.75) */
+		data[2] = 0;		/* reg 95, UV Gain (1.75) */
+		data[3] = 0x3f;		/* reg 96, Y Gain/UV Gain/disable
+					 *	auto dark-gain */
+		data[4] = 0;		/* reg 97, set fixed dark level */
+		data[5] = 0;		/* reg 98, don't care */
+	} else {			/* auto dark-gain */
+		data[1] = 0;		/* reg 94, Y Gain (auto) */
+		data[2] = 0;		/* reg 95, UV Gain (1.75) */
+		data[3] = 0x78;		/* reg 96, Y Gain/UV Gain/disable
+					 *	auto dark-gain */
+		switch (gspca_dev->width) {
+/*		case 1280: */
+/*			data[4] = 154;
+				 * reg 97, %3 shadow point (unit: 256 pixel) */
+/*			data[5] = 51;
+				 * reg 98, %1 highlight point
+				 *	(uint: 256 pixel) */
+/*			break; */
+		default:
+/*		case 640: */
+			data[4] = 36;	/* reg 97, %3 shadow point
+					 *	(unit: 256 pixel) */
+			data[5] = 12;	/* reg 98, %1 highlight point
+					 *	(uint: 256 pixel) */
+			break;
+		case 320:
+			data[4] = 9;	/* reg 97, %3 shadow point
+					 *	(unit: 256 pixel) */
+			data[5] = 3;	/* reg 98, %1 highlight point
+					 *	(uint: 256 pixel) */
+			break;
+		}
+	}
+	/* auto dark-gain */
+	data[0] = 0x5e;		/* address */
+
+	err_code = reg_w(gspca_dev, data[0], 6);
+	if (err_code < 0)
+		return;
+
+	data[0] = 0x67;
+	data[1] = 0x13;		/* reg 103, first pixel B, disable sharpness */
+	err_code = reg_w(gspca_dev, data[0], 2);
+	if (err_code < 0)
+		return;
+
+	/*
+	 * initialize the value of MI sensor...
+	 */
+	MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL);
+	MI_buf[REG_HW_MI_1] = 0x000a;
+	MI_buf[REG_HW_MI_2] = 0x000c;
+	MI_buf[REG_HW_MI_3] = 0x0405;
+	MI_buf[REG_HW_MI_4] = 0x0507;
+	/* mi_Attr_Reg_[REG_HW_MI_5]	 = 0x01ff;//13 */
+	MI_buf[REG_HW_MI_5] = 0x0013;	/* 13 */
+	MI_buf[REG_HW_MI_6] = 0x001f;	/* vertical blanking */
+	/* mi_Attr_Reg_[REG_HW_MI_6]	 = 0x0400;  // vertical blanking */
+	MI_buf[REG_HW_MI_7] = 0x0002;
+	/* mi_Attr_Reg_[REG_HW_MI_9]	 = 0x015f; */
+	/* mi_Attr_Reg_[REG_HW_MI_9]	 = 0x030f; */
+	MI_buf[REG_HW_MI_9] = 0x0374;
+	MI_buf[REG_HW_MI_B] = 0x0000;
+	MI_buf[REG_HW_MI_C] = 0x0000;
+	MI_buf[REG_HW_MI_D] = 0x0000;
+	MI_buf[REG_HW_MI_1E] = 0x8000;
+/* mi_Attr_Reg_[REG_HW_MI_20]	  = 0x1104; */
+	MI_buf[REG_HW_MI_20] = 0x1104;	/* 0x111c; */
+	MI_buf[REG_HW_MI_2B] = 0x0008;
+/* mi_Attr_Reg_[REG_HW_MI_2C]	  = 0x000f; */
+	MI_buf[REG_HW_MI_2C] = 0x001f;	/* lita suggest */
+	MI_buf[REG_HW_MI_2D] = 0x0008;
+	MI_buf[REG_HW_MI_2E] = 0x0008;
+	MI_buf[REG_HW_MI_35] = 0x0051;
+	MI_buf[REG_HW_MI_5F] = 0x0904;	/* fail to write */
+	MI_buf[REG_HW_MI_60] = 0x0000;
+	MI_buf[REG_HW_MI_61] = 0x0000;
+	MI_buf[REG_HW_MI_62] = 0x0498;
+	MI_buf[REG_HW_MI_63] = 0x0000;
+	MI_buf[REG_HW_MI_64] = 0x0000;
+	MI_buf[REG_HW_MI_F1] = 0x0001;
+	/* changing while setting up the different value of dx/dy */
+
+	if (gspca_dev->width != 1280) {
+		MI_buf[0x01] = 0x010a;
+		MI_buf[0x02] = 0x014c;
+		MI_buf[0x03] = 0x01e5;
+		MI_buf[0x04] = 0x0287;
+	}
+	MI_buf[0x20] = 0x1104;
+
+	bulk_w(gspca_dev, MI_buf + 1, 1);
+	bulk_w(gspca_dev, MI_buf + 2, 2);
+	bulk_w(gspca_dev, MI_buf + 3, 3);
+	bulk_w(gspca_dev, MI_buf + 4, 4);
+	bulk_w(gspca_dev, MI_buf + 5, 5);
+	bulk_w(gspca_dev, MI_buf + 6, 6);
+	bulk_w(gspca_dev, MI_buf + 7, 7);
+	bulk_w(gspca_dev, MI_buf + 9, 9);
+	bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b);
+	bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c);
+	bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d);
+	bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e);
+	bulk_w(gspca_dev, MI_buf + 0x20, 0x20);
+	bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b);
+	bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c);
+	bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d);
+	bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e);
+	bulk_w(gspca_dev, MI_buf + 0x35, 0x35);
+	bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f);
+	bulk_w(gspca_dev, MI_buf + 0x60, 0x60);
+	bulk_w(gspca_dev, MI_buf + 0x61, 0x61);
+	bulk_w(gspca_dev, MI_buf + 0x62, 0x62);
+	bulk_w(gspca_dev, MI_buf + 0x63, 0x63);
+	bulk_w(gspca_dev, MI_buf + 0x64, 0x64);
+	bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1);
+	kfree(MI_buf);
+
+	intpipe = usb_sndintpipe(gspca_dev->dev, 0);
+	err_code = usb_clear_halt(gspca_dev->dev, intpipe);
+
+	data[0] = 0x00;
+	data[1] = 0x4d;		/* ISOC transfering enable... */
+	reg_w(gspca_dev, data[0], 2);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	int result;
+
+	gspca_dev->usb_buf[0] = 1;
+	gspca_dev->usb_buf[1] = 0;
+	result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2);
+	if (result < 0)
+		PDEBUG(D_ERR, "Camera Stop failed");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int p;
+
+	if (len < 6) {
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	for (p = 0; p < len - 6; p++) {
+		if (data[0 + p] == 0xff
+		    && data[1 + p] == 0xff
+		    && data[2 + p] == 0x00
+		    && data[3 + p] == 0xff
+		    && data[4 + p] == 0x96) {
+			if (data[5 + p] == 0x64
+			    || data[5 + p] == 0x65
+			    || data[5 + p] == 0x66
+			    || data[5 + p] == 0x67) {
+				PDEBUG(D_PACK, "sof offset: %d leng: %d",
+					p, len);
+				frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+							frame, data, 0);
+
+				/* put the JPEG header */
+				jpeg_put_header(gspca_dev, frame,
+						sd->qindex, 0x21);
+				data += 16;
+				len -= 16;
+				break;
+			}
+		}
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
new file mode 100644
index 0000000..08d99c3
--- /dev/null
+++ b/drivers/media/video/gspca/ov519.c
@@ -0,0 +1,2186 @@
+/**
+ * OV519 driver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * (This module is adapted from the ov51x-jpeg package)
+ *
+ * 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
+ * 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
+ *
+ */
+#define MODULE_NAME "ov519"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("OV519 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* global parameters */
+static int frame_rate;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 10;
+
+/* ov519 device descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	/* Determined by sensor type */
+	short maxwidth;
+	short maxheight;
+
+	unsigned char primary_i2c_slave;	/* I2C write id of sensor */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+
+	char compress;		/* Should the next frame be compressed? */
+	char compress_inited;	/* Are compression params uploaded? */
+	char stopped;		/* Streaming is temporarily paused */
+
+	char frame_rate;	/* current Framerate (OV519 only) */
+	char clockdiv;		/* clockdiv override for OV519 only */
+
+	char sensor;		/* Type of image sensor chip (SEN_*) */
+#define SEN_UNKNOWN 0
+#define SEN_OV6620 1
+#define SEN_OV6630 2
+#define SEN_OV7610 3
+#define SEN_OV7620 4
+#define SEN_OV7630 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
+
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 589,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 589,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 589,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* OV519 Camera interface register numbers */
+#define OV519_CAM_H_SIZE		0x10
+#define OV519_CAM_V_SIZE		0x11
+#define OV519_CAM_X_OFFSETL		0x12
+#define OV519_CAM_X_OFFSETH		0x13
+#define OV519_CAM_Y_OFFSETL		0x14
+#define OV519_CAM_Y_OFFSETH		0x15
+#define OV519_CAM_DIVIDER		0x16
+#define OV519_CAM_DFR			0x20
+#define OV519_CAM_FORMAT		0x25
+
+/* OV519 System Controller register numbers */
+#define OV519_SYS_RESET1 0x51
+#define OV519_SYS_EN_CLK1 0x54
+
+#define OV519_GPIO_DATA_OUT0		0x71
+#define OV519_GPIO_IO_CTRL0		0x72
+
+#define OV511_ENDPOINT_ADDRESS  1	/* Isoc endpoint number */
+
+/* I2C registers */
+#define R51x_I2C_W_SID		0x41
+#define R51x_I2C_SADDR_3	0x42
+#define R51x_I2C_SADDR_2	0x43
+#define R51x_I2C_R_SID		0x44
+#define R51x_I2C_DATA		0x45
+#define R518_I2C_CTL		0x47	/* OV518(+) only */
+
+/* I2C ADDRESSES */
+#define OV7xx0_SID   0x42
+#define OV8xx0_SID   0xa0
+#define OV6xx0_SID   0xc0
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN		0x00	/* gain setting (5:0) */
+#define OV7610_REG_SAT		0x03	/* saturation */
+#define OV8610_REG_HUE		0x04	/* 04 reserved */
+#define OV7610_REG_CNT		0x05	/* Y contrast */
+#define OV7610_REG_BRT		0x06	/* Y brightness */
+#define OV7610_REG_COM_C	0x14	/* misc common regs */
+#define OV7610_REG_ID_HIGH	0x1c	/* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW	0x1d	/* manufacturer ID LSB */
+#define OV7610_REG_COM_I	0x29	/* misc settings */
+
+/* OV7670 registers */
+#define OV7670_REG_GAIN        0x00    /* Gain lower 8 bits (rest in vref) */
+#define OV7670_REG_BLUE        0x01    /* blue gain */
+#define OV7670_REG_RED         0x02    /* red gain */
+#define OV7670_REG_VREF        0x03    /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_REG_COM1        0x04    /* Control 1 */
+#define OV7670_REG_AECHH       0x07    /* AEC MS 5 bits */
+#define OV7670_REG_COM3        0x0c    /* Control 3 */
+#define OV7670_REG_COM4        0x0d    /* Control 4 */
+#define OV7670_REG_COM5        0x0e    /* All "reserved" */
+#define OV7670_REG_COM6        0x0f    /* Control 6 */
+#define OV7670_REG_AECH        0x10    /* More bits of AEC value */
+#define OV7670_REG_CLKRC       0x11    /* Clock control */
+#define OV7670_REG_COM7        0x12    /* Control 7 */
+#define   OV7670_COM7_FMT_VGA    0x00
+#define   OV7670_COM7_YUV        0x00    /* YUV */
+#define   OV7670_COM7_FMT_QVGA   0x10    /* QVGA format */
+#define   OV7670_COM7_FMT_MASK   0x38
+#define   OV7670_COM7_RESET      0x80    /* Register reset */
+#define OV7670_REG_COM8        0x13    /* Control 8 */
+#define   OV7670_COM8_AEC        0x01    /* Auto exposure enable */
+#define   OV7670_COM8_AWB        0x02    /* White balance enable */
+#define   OV7670_COM8_AGC        0x04    /* Auto gain enable */
+#define   OV7670_COM8_BFILT      0x20    /* Band filter enable */
+#define   OV7670_COM8_AECSTEP    0x40    /* Unlimited AEC step size */
+#define   OV7670_COM8_FASTAEC    0x80    /* Enable fast AGC/AEC */
+#define OV7670_REG_COM9        0x14    /* Control 9  - gain ceiling */
+#define OV7670_REG_COM10       0x15    /* Control 10 */
+#define OV7670_REG_HSTART      0x17    /* Horiz start high bits */
+#define OV7670_REG_HSTOP       0x18    /* Horiz stop high bits */
+#define OV7670_REG_VSTART      0x19    /* Vert start high bits */
+#define OV7670_REG_VSTOP       0x1a    /* Vert stop high bits */
+#define OV7670_REG_MVFP        0x1e    /* Mirror / vflip */
+#define   OV7670_MVFP_MIRROR     0x20    /* Mirror image */
+#define OV7670_REG_AEW         0x24    /* AGC upper limit */
+#define OV7670_REG_AEB         0x25    /* AGC lower limit */
+#define OV7670_REG_VPT         0x26    /* AGC/AEC fast mode op region */
+#define OV7670_REG_HREF        0x32    /* HREF pieces */
+#define OV7670_REG_TSLB        0x3a    /* lots of stuff */
+#define OV7670_REG_COM11       0x3b    /* Control 11 */
+#define   OV7670_COM11_EXP       0x02
+#define   OV7670_COM11_HZAUTO    0x10    /* Auto detect 50/60 Hz */
+#define OV7670_REG_COM12       0x3c    /* Control 12 */
+#define OV7670_REG_COM13       0x3d    /* Control 13 */
+#define   OV7670_COM13_GAMMA     0x80    /* Gamma enable */
+#define   OV7670_COM13_UVSAT     0x40    /* UV saturation auto adjustment */
+#define OV7670_REG_COM14       0x3e    /* Control 14 */
+#define OV7670_REG_EDGE        0x3f    /* Edge enhancement factor */
+#define OV7670_REG_COM15       0x40    /* Control 15 */
+#define   OV7670_COM15_R00FF     0xc0    /*            00 to FF */
+#define OV7670_REG_COM16       0x41    /* Control 16 */
+#define   OV7670_COM16_AWBGAIN   0x08    /* AWB gain enable */
+#define OV7670_REG_BRIGHT      0x55    /* Brightness */
+#define OV7670_REG_CONTRAS     0x56    /* Contrast control */
+#define OV7670_REG_GFIX        0x69    /* Fix gain control */
+#define OV7670_REG_RGB444      0x8c    /* RGB 444 control */
+#define OV7670_REG_HAECC1      0x9f    /* Hist AEC/AGC control 1 */
+#define OV7670_REG_HAECC2      0xa0    /* Hist AEC/AGC control 2 */
+#define OV7670_REG_BD50MAX     0xa5    /* 50hz banding step limit */
+#define OV7670_REG_HAECC3      0xa6    /* Hist AEC/AGC control 3 */
+#define OV7670_REG_HAECC4      0xa7    /* Hist AEC/AGC control 4 */
+#define OV7670_REG_HAECC5      0xa8    /* Hist AEC/AGC control 5 */
+#define OV7670_REG_HAECC6      0xa9    /* Hist AEC/AGC control 6 */
+#define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
+#define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
+
+struct ovsensor_window {
+	short x;
+	short y;
+	short width;
+	short height;
+/*	int format; */
+	short quarter;		/* Scale width and height down 2x */
+	short clockdiv;		/* Clock divisor setting */
+};
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+	if (v > 127)
+		return v & 0x7f;
+	return (128 - v) | 0x80;
+}
+
+/* Write a OV519 register */
+static int reg_w(struct sd *sd, __u16 index, __u8 value)
+{
+	int ret;
+
+	sd->gspca_dev.usb_buf[0] = value;
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+			1,			/* REQ_IO (ov518/519) */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, index,
+			sd->gspca_dev.usb_buf, 1, 500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);
+	return ret;
+}
+
+/* Read from a OV519 register */
+/* returns: negative is error, pos or zero is data */
+static int reg_r(struct sd *sd, __u16 index)
+{
+	int ret;
+
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+			1,			/* REQ_IO */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, index, sd->gspca_dev.usb_buf, 1, 500);
+
+	if (ret >= 0)
+		ret = sd->gspca_dev.usb_buf[0];
+	else
+		PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+	return ret;
+}
+
+/* Read 8 values from a OV519 register */
+static int reg_r8(struct sd *sd,
+		  __u16 index)
+{
+	int ret;
+
+	ret = usb_control_msg(sd->gspca_dev.dev,
+			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+			1,			/* REQ_IO */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0, index, sd->gspca_dev.usb_buf, 8, 500);
+
+	if (ret >= 0)
+		ret = sd->gspca_dev.usb_buf[0];
+	else
+		PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+	return ret;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int reg_w_mask(struct sd *sd,
+			__u16 index,
+			__u8 value,
+			__u8 mask)
+{
+	int ret;
+	__u8 oldval;
+
+	if (mask != 0xff) {
+		value &= mask;			/* Enforce mask on value */
+		ret = reg_r(sd, index);
+		if (ret < 0)
+			return ret;
+
+		oldval = ret & ~mask;		/* Clear the masked bits */
+		value |= oldval;		/* Set the desired bits */
+	}
+	return reg_w(sd, index, value);
+}
+
+/*
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_w(struct sd *sd,
+		__u8 reg,
+		__u8 value)
+{
+	int rc;
+
+	PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+	/* Select camera register */
+	rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
+	if (rc < 0)
+		return rc;
+
+	/* Write "value" to I2C data port of OV511 */
+	rc = reg_w(sd, R51x_I2C_DATA, value);
+	if (rc < 0)
+		return rc;
+
+	/* Initiate 3-byte write cycle */
+	rc = reg_w(sd, R518_I2C_CTL, 0x01);
+
+	/* wait for write complete */
+	msleep(4);
+	if (rc < 0)
+		return rc;
+	return reg_r8(sd, R518_I2C_CTL);
+}
+
+/*
+ * returns: negative is error, pos or zero is data
+ *
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+	int rc, value;
+
+	/* Select camera register */
+	rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
+	if (rc < 0)
+		return rc;
+
+	/* Initiate 2-byte write cycle */
+	rc = reg_w(sd, R518_I2C_CTL, 0x03);
+	if (rc < 0)
+		return rc;
+
+	/* Initiate 2-byte read cycle */
+	rc = reg_w(sd, R518_I2C_CTL, 0x05);
+	if (rc < 0)
+		return rc;
+	value = reg_r(sd, R51x_I2C_DATA);
+	PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+	return value;
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int i2c_w_mask(struct sd *sd,
+		   __u8 reg,
+		   __u8 value,
+		   __u8 mask)
+{
+	int rc;
+	__u8 oldval;
+
+	value &= mask;			/* Enforce mask on value */
+	rc = i2c_r(sd, reg);
+	if (rc < 0)
+		return rc;
+	oldval = rc & ~mask;		/* Clear the masked bits */
+	value |= oldval;		/* Set the desired bits */
+	return i2c_w(sd, reg, value);
+}
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov51x_stop(struct sd *sd)
+{
+	PDEBUG(D_STREAM, "stopping");
+	sd->stopped = 1;
+	return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+}
+
+/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
+ * actually stopped (for performance). */
+static inline int ov51x_restart(struct sd *sd)
+{
+	PDEBUG(D_STREAM, "restarting");
+	if (!sd->stopped)
+		return 0;
+	sd->stopped = 0;
+
+	/* Reinitialize the stream */
+	return reg_w(sd, OV519_SYS_RESET1, 0x00);
+}
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 on failure.
+ */
+static int init_ov_sensor(struct sd *sd)
+{
+	int i, success;
+
+	/* Reset the sensor */
+	if (i2c_w(sd, 0x12, 0x80) < 0)
+		return -EIO;
+
+	/* Wait for it to initialize */
+	msleep(150);
+
+	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+		if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
+		    i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
+			success = 1;
+			continue;
+		}
+
+		/* Reset the sensor */
+		if (i2c_w(sd, 0x12, 0x80) < 0)
+			return -EIO;
+		/* Wait for it to initialize */
+		msleep(150);
+		/* Dummy read to sync I2C */
+		if (i2c_r(sd, 0x00) < 0)
+			return -EIO;
+	}
+	if (!success)
+		return -EIO;
+	PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
+	return 0;
+}
+
+/* Switch on standard JPEG compression. Returns 0 for success. */
+static int ov519_init_compression(struct sd *sd)
+{
+	if (!sd->compress_inited) {
+		if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) {
+			PDEBUG(D_ERR, "Error switching to compressed mode");
+			return -EIO;
+		}
+		sd->compress_inited = 1;
+	}
+	return 0;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1).
+ * This should not be called from outside the i2c I/O functions.
+ * Sets I2C read and write slave IDs. Returns <0 for error
+ */
+static int ov51x_set_slave_ids(struct sd *sd,
+				__u8 slave)
+{
+	int rc;
+
+	rc = reg_w(sd, R51x_I2C_W_SID, slave);
+	if (rc < 0)
+		return rc;
+	return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+}
+
+struct ov_regvals {
+	__u8 reg;
+	__u8 val;
+};
+struct ov_i2c_regvals {
+	__u8 reg;
+	__u8 val;
+};
+
+static int write_regvals(struct sd *sd,
+			 const struct ov_regvals *regvals,
+			 int n)
+{
+	int rc;
+
+	while (--n >= 0) {
+		rc = reg_w(sd, regvals->reg, regvals->val);
+		if (rc < 0)
+			return rc;
+		regvals++;
+	}
+	return 0;
+}
+
+static int write_i2c_regvals(struct sd *sd,
+			     const struct ov_i2c_regvals *regvals,
+			     int n)
+{
+	int rc;
+
+	while (--n >= 0) {
+		rc = i2c_w(sd, regvals->reg, regvals->val);
+		if (rc < 0)
+			return rc;
+		regvals++;
+	}
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
+ * the same register settings as the OV8610, since they are very similar.
+ */
+static int ov8xx0_configure(struct sd *sd)
+{
+	int rc;
+	static const struct ov_i2c_regvals norm_8610[] = {
+		{ 0x12, 0x80 },
+		{ 0x00, 0x00 },
+		{ 0x01, 0x80 },
+		{ 0x02, 0x80 },
+		{ 0x03, 0xc0 },
+		{ 0x04, 0x30 },
+		{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+		{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+		{ 0x0a, 0x86 },
+		{ 0x0b, 0xb0 },
+		{ 0x0c, 0x20 },
+		{ 0x0d, 0x20 },
+		{ 0x11, 0x01 },
+		{ 0x12, 0x25 },
+		{ 0x13, 0x01 },
+		{ 0x14, 0x04 },
+		{ 0x15, 0x01 }, /* Lin and Win think different about UV order */
+		{ 0x16, 0x03 },
+		{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+		{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+		{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+		{ 0x1a, 0xf5 },
+		{ 0x1b, 0x00 },
+		{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+		{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+		{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+		{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+		{ 0x26, 0xa2 },
+		{ 0x27, 0xea },
+		{ 0x28, 0x00 },
+		{ 0x29, 0x00 },
+		{ 0x2a, 0x80 },
+		{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+		{ 0x2c, 0xac },
+		{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+		{ 0x2e, 0x80 },
+		{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+		{ 0x4c, 0x00 },
+		{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+		{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+		{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+		{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+		{ 0x63, 0xff },
+		{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+				 * maybe thats wrong */
+		{ 0x65, 0x00 },
+		{ 0x66, 0x55 },
+		{ 0x67, 0xb0 },
+		{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+		{ 0x69, 0x02 },
+		{ 0x6a, 0x22 },
+		{ 0x6b, 0x00 },
+		{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+				   deleting bit7 colors the first images red */
+		{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+		{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+		{ 0x6f, 0x01 },
+		{ 0x70, 0x8b },
+		{ 0x71, 0x00 },
+		{ 0x72, 0x14 },
+		{ 0x73, 0x54 },
+		{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+		{ 0x75, 0x0e },
+		{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+		{ 0x77, 0xff },
+		{ 0x78, 0x80 },
+		{ 0x79, 0x80 },
+		{ 0x7a, 0x80 },
+		{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+		{ 0x7c, 0x00 },
+		{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+		{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+		{ 0x7f, 0xfb },
+		{ 0x80, 0x28 },
+		{ 0x81, 0x00 },
+		{ 0x82, 0x23 },
+		{ 0x83, 0x0b },
+		{ 0x84, 0x00 },
+		{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+		{ 0x86, 0xc9 },
+		{ 0x87, 0x00 },
+		{ 0x88, 0x00 },
+		{ 0x89, 0x01 },
+		{ 0x12, 0x20 },
+		{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+	};
+
+	PDEBUG(D_PROBE, "starting ov8xx0 configuration");
+
+	if (init_ov_sensor(sd) < 0)
+		PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
+	else
+		PDEBUG(D_PROBE, "OV86x0 initialized");
+
+	/* Detect sensor (sub)type */
+	rc = i2c_r(sd, OV7610_REG_COM_I);
+	if (rc < 0) {
+		PDEBUG(D_ERR, "Error detecting sensor type");
+		return -1;
+	}
+	if ((rc & 3) == 1) {
+		PDEBUG(D_PROBE, "Sensor is an OV8610");
+		sd->sensor = SEN_OV8610;
+	} else {
+		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+		return -1;
+	}
+	PDEBUG(D_PROBE, "Writing 8610 registers");
+	if (write_i2c_regvals(sd,
+			norm_8610,
+			sizeof norm_8610 / sizeof norm_8610[0]))
+		return -1;
+
+	/* Set sensor-specific vars */
+	sd->maxwidth = 640;
+	sd->maxheight = 480;
+	return 0;
+}
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int ov7xx0_configure(struct sd *sd)
+{
+	int rc, high, low;
+
+	/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+	 *
+	 * Register 0x0f in the 7610 has the following effects:
+	 *
+	 * 0x85 (AEC method 1): Best overall, good contrast range
+	 * 0x45 (AEC method 2): Very overexposed
+	 * 0xa5 (spec sheet default): Ok, but the black level is
+	 *	shifted resulting in loss of contrast
+	 * 0x05 (old driver setting): very overexposed, too much
+	 *	contrast
+	 */
+	static const struct ov_i2c_regvals norm_7610[] = {
+		{ 0x10, 0xff },
+		{ 0x16, 0x06 },
+		{ 0x28, 0x24 },
+		{ 0x2b, 0xac },
+		{ 0x12, 0x00 },
+		{ 0x38, 0x81 },
+		{ 0x28, 0x24 },	/* 0c */
+		{ 0x0f, 0x85 },	/* lg's setting */
+		{ 0x15, 0x01 },
+		{ 0x20, 0x1c },
+		{ 0x23, 0x2a },
+		{ 0x24, 0x10 },
+		{ 0x25, 0x8a },
+		{ 0x26, 0xa2 },
+		{ 0x27, 0xc2 },
+		{ 0x2a, 0x04 },
+		{ 0x2c, 0xfe },
+		{ 0x2d, 0x93 },
+		{ 0x30, 0x71 },
+		{ 0x31, 0x60 },
+		{ 0x32, 0x26 },
+		{ 0x33, 0x20 },
+		{ 0x34, 0x48 },
+		{ 0x12, 0x24 },
+		{ 0x11, 0x01 },
+		{ 0x0c, 0x24 },
+		{ 0x0d, 0x24 },
+	};
+
+	static const struct ov_i2c_regvals norm_7620[] = {
+		{ 0x00, 0x00 },		/* gain */
+		{ 0x01, 0x80 },		/* blue gain */
+		{ 0x02, 0x80 },		/* red gain */
+		{ 0x03, 0xc0 },		/* OV7670_REG_VREF */
+		{ 0x06, 0x60 },
+		{ 0x07, 0x00 },
+		{ 0x0c, 0x24 },
+		{ 0x0c, 0x24 },
+		{ 0x0d, 0x24 },
+		{ 0x11, 0x01 },
+		{ 0x12, 0x24 },
+		{ 0x13, 0x01 },
+		{ 0x14, 0x84 },
+		{ 0x15, 0x01 },
+		{ 0x16, 0x03 },
+		{ 0x17, 0x2f },
+		{ 0x18, 0xcf },
+		{ 0x19, 0x06 },
+		{ 0x1a, 0xf5 },
+		{ 0x1b, 0x00 },
+		{ 0x20, 0x18 },
+		{ 0x21, 0x80 },
+		{ 0x22, 0x80 },
+		{ 0x23, 0x00 },
+		{ 0x26, 0xa2 },
+		{ 0x27, 0xea },
+		{ 0x28, 0x20 },
+		{ 0x29, 0x00 },
+		{ 0x2a, 0x10 },
+		{ 0x2b, 0x00 },
+		{ 0x2c, 0x88 },
+		{ 0x2d, 0x91 },
+		{ 0x2e, 0x80 },
+		{ 0x2f, 0x44 },
+		{ 0x60, 0x27 },
+		{ 0x61, 0x02 },
+		{ 0x62, 0x5f },
+		{ 0x63, 0xd5 },
+		{ 0x64, 0x57 },
+		{ 0x65, 0x83 },
+		{ 0x66, 0x55 },
+		{ 0x67, 0x92 },
+		{ 0x68, 0xcf },
+		{ 0x69, 0x76 },
+		{ 0x6a, 0x22 },
+		{ 0x6b, 0x00 },
+		{ 0x6c, 0x02 },
+		{ 0x6d, 0x44 },
+		{ 0x6e, 0x80 },
+		{ 0x6f, 0x1d },
+		{ 0x70, 0x8b },
+		{ 0x71, 0x00 },
+		{ 0x72, 0x14 },
+		{ 0x73, 0x54 },
+		{ 0x74, 0x00 },
+		{ 0x75, 0x8e },
+		{ 0x76, 0x00 },
+		{ 0x77, 0xff },
+		{ 0x78, 0x80 },
+		{ 0x79, 0x80 },
+		{ 0x7a, 0x80 },
+		{ 0x7b, 0xe2 },
+		{ 0x7c, 0x00 },
+	};
+
+	/* 7640 and 7648. The defaults should be OK for most registers. */
+	static const struct ov_i2c_regvals norm_7640[] = {
+		{ 0x12, 0x80 },
+		{ 0x12, 0x14 },
+	};
+
+	/* 7670. Defaults taken from OmniVision provided data,
+	*  as provided by Jonathan Corbet of OLPC		*/
+	static const struct ov_i2c_regvals norm_7670[] = {
+		{ OV7670_REG_COM7, OV7670_COM7_RESET },
+		{ OV7670_REG_TSLB, 0x04 },		/* OV */
+		{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+		{ OV7670_REG_CLKRC, 0x1 },
+	/*
+	 * Set the hardware window.  These values from OV don't entirely
+	 * make sense - hstop is less than hstart.  But they work...
+	 */
+		{ OV7670_REG_HSTART, 0x13 },	{ OV7670_REG_HSTOP, 0x01 },
+		{ OV7670_REG_HREF, 0xb6 },	{ OV7670_REG_VSTART, 0x02 },
+		{ OV7670_REG_VSTOP, 0x7a },	{ OV7670_REG_VREF, 0x0a },
+
+		{ OV7670_REG_COM3, 0 },	{ OV7670_REG_COM14, 0 },
+	/* Mystery scaling numbers */
+		{ 0x70, 0x3a },		{ 0x71, 0x35 },
+		{ 0x72, 0x11 },		{ 0x73, 0xf0 },
+		{ 0xa2, 0x02 },
+/* jfm */
+/* { OV7670_REG_COM10, 0x0 }, */
+
+	/* Gamma curve values */
+		{ 0x7a, 0x20 },
+/* jfm:win 7b=1c */
+		{ 0x7b, 0x10 },
+/* jfm:win 7c=28 */
+		{ 0x7c, 0x1e },
+/* jfm:win 7d=3c */
+		{ 0x7d, 0x35 },
+		{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
+		{ 0x80, 0x76 },		{ 0x81, 0x80 },
+		{ 0x82, 0x88 },		{ 0x83, 0x8f },
+		{ 0x84, 0x96 },		{ 0x85, 0xa3 },
+		{ 0x86, 0xaf },		{ 0x87, 0xc4 },
+		{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
+
+	/* AGC and AEC parameters.  Note we start by disabling those features,
+	   then turn them only after tweaking the values. */
+		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+				 | OV7670_COM8_AECSTEP
+				 | OV7670_COM8_BFILT },
+		{ OV7670_REG_GAIN, 0 },	{ OV7670_REG_AECH, 0 },
+		{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+/* jfm:win 14=38 */
+		{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+		{ OV7670_REG_BD50MAX, 0x05 },	{ OV7670_REG_BD60MAX, 0x07 },
+		{ OV7670_REG_AEW, 0x95 },	{ OV7670_REG_AEB, 0x33 },
+		{ OV7670_REG_VPT, 0xe3 },	{ OV7670_REG_HAECC1, 0x78 },
+		{ OV7670_REG_HAECC2, 0x68 },
+/* jfm:win a1=0b */
+		{ 0xa1, 0x03 }, /* magic */
+		{ OV7670_REG_HAECC3, 0xd8 },	{ OV7670_REG_HAECC4, 0xd8 },
+		{ OV7670_REG_HAECC5, 0xf0 },	{ OV7670_REG_HAECC6, 0x90 },
+		{ OV7670_REG_HAECC7, 0x94 },
+		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+				| OV7670_COM8_AECSTEP
+				| OV7670_COM8_BFILT
+				| OV7670_COM8_AGC
+				| OV7670_COM8_AEC },
+
+	/* Almost all of these are magic "reserved" values.  */
+		{ OV7670_REG_COM5, 0x61 },	{ OV7670_REG_COM6, 0x4b },
+		{ 0x16, 0x02 },
+/* jfm */
+/*		{ OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */
+		{ OV7670_REG_MVFP, 0x07 },
+		{ 0x21, 0x02 },		{ 0x22, 0x91 },
+		{ 0x29, 0x07 },		{ 0x33, 0x0b },
+		{ 0x35, 0x0b },		{ 0x37, 0x1d },
+		{ 0x38, 0x71 },		{ 0x39, 0x2a },
+		{ OV7670_REG_COM12, 0x78 },	{ 0x4d, 0x40 },
+		{ 0x4e, 0x20 },		{ OV7670_REG_GFIX, 0 },
+		{ 0x6b, 0x4a },		{ 0x74, 0x10 },
+		{ 0x8d, 0x4f },		{ 0x8e, 0 },
+		{ 0x8f, 0 },		{ 0x90, 0 },
+		{ 0x91, 0 },		{ 0x96, 0 },
+		{ 0x9a, 0 },		{ 0xb0, 0x84 },
+		{ 0xb1, 0x0c },		{ 0xb2, 0x0e },
+		{ 0xb3, 0x82 },		{ 0xb8, 0x0a },
+
+	/* More reserved magic, some of which tweaks white balance */
+		{ 0x43, 0x0a },		{ 0x44, 0xf0 },
+		{ 0x45, 0x34 },		{ 0x46, 0x58 },
+		{ 0x47, 0x28 },		{ 0x48, 0x3a },
+		{ 0x59, 0x88 },		{ 0x5a, 0x88 },
+		{ 0x5b, 0x44 },		{ 0x5c, 0x67 },
+		{ 0x5d, 0x49 },		{ 0x5e, 0x0e },
+		{ 0x6c, 0x0a },		{ 0x6d, 0x55 },
+		{ 0x6e, 0x11 },		{ 0x6f, 0x9f },
+						/* "9e for advance AWB" */
+		{ 0x6a, 0x40 },		{ OV7670_REG_BLUE, 0x40 },
+		{ OV7670_REG_RED, 0x60 },
+		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+				| OV7670_COM8_AECSTEP
+				| OV7670_COM8_BFILT
+				| OV7670_COM8_AGC
+				| OV7670_COM8_AEC
+				| OV7670_COM8_AWB },
+
+	/* Matrix coefficients */
+		{ 0x4f, 0x80 },		{ 0x50, 0x80 },
+		{ 0x51, 0 },		{ 0x52, 0x22 },
+		{ 0x53, 0x5e },		{ 0x54, 0x80 },
+		{ 0x58, 0x9e },
+
+		{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+		{ OV7670_REG_EDGE, 0 },
+		{ 0x75, 0x05 },		{ 0x76, 0xe1 },
+		{ 0x4c, 0 },		{ 0x77, 0x01 },
+		{ OV7670_REG_COM13, 0xc3 },	{ 0x4b, 0x09 },
+		{ 0xc9, 0x60 },		{ OV7670_REG_COM16, 0x38 },
+		{ 0x56, 0x40 },
+
+		{ 0x34, 0x11 },
+		{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+		{ 0xa4, 0x88 },		{ 0x96, 0 },
+		{ 0x97, 0x30 },		{ 0x98, 0x20 },
+		{ 0x99, 0x30 },		{ 0x9a, 0x84 },
+		{ 0x9b, 0x29 },		{ 0x9c, 0x03 },
+		{ 0x9d, 0x4c },		{ 0x9e, 0x3f },
+		{ 0x78, 0x04 },
+
+	/* Extra-weird stuff.  Some sort of multiplexor register */
+		{ 0x79, 0x01 },		{ 0xc8, 0xf0 },
+		{ 0x79, 0x0f },		{ 0xc8, 0x00 },
+		{ 0x79, 0x10 },		{ 0xc8, 0x7e },
+		{ 0x79, 0x0a },		{ 0xc8, 0x80 },
+		{ 0x79, 0x0b },		{ 0xc8, 0x01 },
+		{ 0x79, 0x0c },		{ 0xc8, 0x0f },
+		{ 0x79, 0x0d },		{ 0xc8, 0x20 },
+		{ 0x79, 0x09 },		{ 0xc8, 0x80 },
+		{ 0x79, 0x02 },		{ 0xc8, 0xc0 },
+		{ 0x79, 0x03 },		{ 0xc8, 0x40 },
+		{ 0x79, 0x05 },		{ 0xc8, 0x30 },
+		{ 0x79, 0x26 },
+
+	/* Format YUV422 */
+		{ OV7670_REG_COM7, OV7670_COM7_YUV },  /* Selects YUV mode */
+		{ OV7670_REG_RGB444, 0 },	/* No RGB444 please */
+		{ OV7670_REG_COM1, 0 },
+		{ OV7670_REG_COM15, OV7670_COM15_R00FF },
+		{ OV7670_REG_COM9, 0x18 },
+				/* 4x gain ceiling; 0x8 is reserved bit */
+		{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
+		{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
+		{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
+		{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
+		{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
+		{ OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT },
+};
+
+	PDEBUG(D_PROBE, "starting OV7xx0 configuration");
+
+/* jfm:already done? */
+	if (init_ov_sensor(sd) < 0)
+		PDEBUG(D_ERR, "Failed to read sensor ID");
+	else
+		PDEBUG(D_PROBE, "OV7xx0 initialized");
+
+	/* Detect sensor (sub)type */
+	rc = i2c_r(sd, OV7610_REG_COM_I);
+
+	/* add OV7670 here
+	 * it appears to be wrongly detected as a 7610 by default */
+	if (rc < 0) {
+		PDEBUG(D_ERR, "Error detecting sensor type");
+		return -1;
+	}
+	if ((rc & 3) == 3) {
+		/* quick hack to make OV7670s work */
+		high = i2c_r(sd, 0x0a);
+		low = i2c_r(sd, 0x0b);
+		/* info("%x, %x", high, low); */
+		if (high == 0x76 && low == 0x73) {
+			PDEBUG(D_PROBE, "Sensor is an OV7670");
+			sd->sensor = SEN_OV7670;
+		} else {
+			PDEBUG(D_PROBE, "Sensor is an OV7610");
+			sd->sensor = SEN_OV7610;
+		}
+	} else if ((rc & 3) == 1) {
+		/* I don't know what's different about the 76BE yet. */
+		if (i2c_r(sd, 0x15) & 1)
+			PDEBUG(D_PROBE, "Sensor is an OV7620AE");
+		else
+			PDEBUG(D_PROBE, "Sensor is an OV76BE");
+
+		/* OV511+ will return all zero isoc data unless we
+		 * configure the sensor as a 7620. Someone needs to
+		 * find the exact reg. setting that causes this. */
+		sd->sensor = SEN_OV76BE;
+	} else if ((rc & 3) == 0) {
+		/* try to read product id registers */
+		high = i2c_r(sd, 0x0a);
+		if (high < 0) {
+			PDEBUG(D_ERR, "Error detecting camera chip PID");
+			return high;
+		}
+		low = i2c_r(sd, 0x0b);
+		if (low < 0) {
+			PDEBUG(D_ERR, "Error detecting camera chip VER");
+			return low;
+		}
+		if (high == 0x76) {
+			if (low == 0x30) {
+				PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
+				sd->sensor = SEN_OV7630;
+			} else if (low == 0x40) {
+				PDEBUG(D_PROBE, "Sensor is an OV7645");
+				sd->sensor = SEN_OV7640; /* FIXME */
+			} else if (low == 0x45) {
+				PDEBUG(D_PROBE, "Sensor is an OV7645B");
+				sd->sensor = SEN_OV7640; /* FIXME */
+			} else if (low == 0x48) {
+				PDEBUG(D_PROBE, "Sensor is an OV7648");
+				sd->sensor = SEN_OV7640; /* FIXME */
+			} else {
+				PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
+				return -1;
+			}
+		} else {
+			PDEBUG(D_PROBE, "Sensor is an OV7620");
+			sd->sensor = SEN_OV7620;
+		}
+	} else {
+		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+		return -1;
+	}
+
+	if (sd->sensor == SEN_OV7620) {
+		PDEBUG(D_PROBE, "Writing 7620 registers");
+		if (write_i2c_regvals(sd, norm_7620,
+				sizeof norm_7620 / sizeof norm_7620[0]))
+			return -1;
+	} else if (sd->sensor == SEN_OV7630) {
+		PDEBUG(D_ERR, "7630 is not supported by this driver version");
+		return -1;
+	} else if (sd->sensor == SEN_OV7640) {
+		PDEBUG(D_PROBE, "Writing 7640 registers");
+		if (write_i2c_regvals(sd, norm_7640,
+				sizeof norm_7640 / sizeof norm_7640[0]))
+			return -1;
+	} else if (sd->sensor == SEN_OV7670) {
+		PDEBUG(D_PROBE, "Writing 7670 registers");
+		if (write_i2c_regvals(sd, norm_7670,
+				sizeof norm_7670 / sizeof norm_7670[0]))
+			return -1;
+	} else {
+		PDEBUG(D_PROBE, "Writing 7610 registers");
+		if (write_i2c_regvals(sd, norm_7610,
+				sizeof norm_7610 / sizeof norm_7610[0]))
+			return -1;
+	}
+
+	/* Set sensor-specific vars */
+	sd->maxwidth = 640;
+	sd->maxheight = 480;
+	return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int ov6xx0_configure(struct sd *sd)
+{
+	int rc;
+	static const struct ov_i2c_regvals norm_6x20[] = {
+		{ 0x12, 0x80 }, /* reset */
+		{ 0x11, 0x01 },
+		{ 0x03, 0x60 },
+		{ 0x05, 0x7f }, /* For when autoadjust is off */
+		{ 0x07, 0xa8 },
+		/* The ratio of 0x0c and 0x0d  controls the white point */
+		{ 0x0c, 0x24 },
+		{ 0x0d, 0x24 },
+		{ 0x0f, 0x15 }, /* COMS */
+		{ 0x10, 0x75 }, /* AEC Exposure time */
+		{ 0x12, 0x24 }, /* Enable AGC */
+		{ 0x14, 0x04 },
+		/* 0x16: 0x06 helps frame stability with moving objects */
+		{ 0x16, 0x06 },
+/*		{ 0x20, 0x30 },  * Aperture correction enable */
+		{ 0x26, 0xb2 }, /* BLC enable */
+		/* 0x28: 0x05 Selects RGB format if RGB on */
+		{ 0x28, 0x05 },
+		{ 0x2a, 0x04 }, /* Disable framerate adjust */
+/*		{ 0x2b, 0xac },  * Framerate; Set 2a[7] first */
+		{ 0x2d, 0x99 },
+		{ 0x33, 0xa0 }, /* Color Processing Parameter */
+		{ 0x34, 0xd2 }, /* Max A/D range */
+		{ 0x38, 0x8b },
+		{ 0x39, 0x40 },
+
+		{ 0x3c, 0x39 }, /* Enable AEC mode changing */
+		{ 0x3c, 0x3c }, /* Change AEC mode */
+		{ 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+		{ 0x3d, 0x80 },
+		/* These next two registers (0x4a, 0x4b) are undocumented.
+		 * They control the color balance */
+		{ 0x4a, 0x80 },
+		{ 0x4b, 0x80 },
+		{ 0x4d, 0xd2 }, /* This reduces noise a bit */
+		{ 0x4e, 0xc1 },
+		{ 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+	};
+
+	static const struct ov_i2c_regvals norm_6x30[] = {
+		{ 0x12, 0x80 }, /* Reset */
+		{ 0x00, 0x1f }, /* Gain */
+		{ 0x01, 0x99 }, /* Blue gain */
+		{ 0x02, 0x7c }, /* Red gain */
+		{ 0x03, 0xc0 }, /* Saturation */
+		{ 0x05, 0x0a }, /* Contrast */
+		{ 0x06, 0x95 }, /* Brightness */
+		{ 0x07, 0x2d }, /* Sharpness */
+		{ 0x0c, 0x20 },
+		{ 0x0d, 0x20 },
+		{ 0x0e, 0x20 },
+		{ 0x0f, 0x05 },
+		{ 0x10, 0x9a },
+		{ 0x11, 0x00 }, /* Pixel clock = fastest */
+		{ 0x12, 0x24 }, /* Enable AGC and AWB */
+		{ 0x13, 0x21 },
+		{ 0x14, 0x80 },
+		{ 0x15, 0x01 },
+		{ 0x16, 0x03 },
+		{ 0x17, 0x38 },
+		{ 0x18, 0xea },
+		{ 0x19, 0x04 },
+		{ 0x1a, 0x93 },
+		{ 0x1b, 0x00 },
+		{ 0x1e, 0xc4 },
+		{ 0x1f, 0x04 },
+		{ 0x20, 0x20 },
+		{ 0x21, 0x10 },
+		{ 0x22, 0x88 },
+		{ 0x23, 0xc0 }, /* Crystal circuit power level */
+		{ 0x25, 0x9a }, /* Increase AEC black ratio */
+		{ 0x26, 0xb2 }, /* BLC enable */
+		{ 0x27, 0xa2 },
+		{ 0x28, 0x00 },
+		{ 0x29, 0x00 },
+		{ 0x2a, 0x84 }, /* 60 Hz power */
+		{ 0x2b, 0xa8 }, /* 60 Hz power */
+		{ 0x2c, 0xa0 },
+		{ 0x2d, 0x95 }, /* Enable auto-brightness */
+		{ 0x2e, 0x88 },
+		{ 0x33, 0x26 },
+		{ 0x34, 0x03 },
+		{ 0x36, 0x8f },
+		{ 0x37, 0x80 },
+		{ 0x38, 0x83 },
+		{ 0x39, 0x80 },
+		{ 0x3a, 0x0f },
+		{ 0x3b, 0x3c },
+		{ 0x3c, 0x1a },
+		{ 0x3d, 0x80 },
+		{ 0x3e, 0x80 },
+		{ 0x3f, 0x0e },
+		{ 0x40, 0x00 }, /* White bal */
+		{ 0x41, 0x00 }, /* White bal */
+		{ 0x42, 0x80 },
+		{ 0x43, 0x3f }, /* White bal */
+		{ 0x44, 0x80 },
+		{ 0x45, 0x20 },
+		{ 0x46, 0x20 },
+		{ 0x47, 0x80 },
+		{ 0x48, 0x7f },
+		{ 0x49, 0x00 },
+		{ 0x4a, 0x00 },
+		{ 0x4b, 0x80 },
+		{ 0x4c, 0xd0 },
+		{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+		{ 0x4e, 0x40 },
+		{ 0x4f, 0x07 }, /* UV avg., col. killer: max */
+		{ 0x50, 0xff },
+		{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
+		{ 0x55, 0xff },
+		{ 0x56, 0x12 },
+		{ 0x57, 0x81 },
+		{ 0x58, 0x75 },
+		{ 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+		{ 0x5a, 0x2c },
+		{ 0x5b, 0x0f }, /* AWB chrominance levels */
+		{ 0x5c, 0x10 },
+		{ 0x3d, 0x80 },
+		{ 0x27, 0xa6 },
+		{ 0x12, 0x20 }, /* Toggle AWB */
+		{ 0x12, 0x24 },
+	};
+
+	PDEBUG(D_PROBE, "starting sensor configuration");
+
+	if (init_ov_sensor(sd) < 0) {
+		PDEBUG(D_ERR, "Failed to read sensor ID.");
+		return -1;
+	}
+	PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+
+	/* Detect sensor (sub)type */
+	rc = i2c_r(sd, OV7610_REG_COM_I);
+	if (rc < 0) {
+		PDEBUG(D_ERR, "Error detecting sensor type");
+		return -1;
+	}
+
+	/* Ugh. The first two bits are the version bits, but
+	 * the entire register value must be used. I guess OVT
+	 * underestimated how many variants they would make. */
+	if (rc == 0x00) {
+		sd->sensor = SEN_OV6630;
+		PDEBUG(D_ERR,
+			"WARNING: Sensor is an OV66308. Your camera may have");
+		PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+	} else if (rc == 0x01) {
+		sd->sensor = SEN_OV6620;
+		PDEBUG(D_PROBE, "Sensor is an OV6620");
+	} else if (rc == 0x02) {
+		sd->sensor = SEN_OV6630;
+		PDEBUG(D_PROBE, "Sensor is an OV66308AE");
+	} else if (rc == 0x03) {
+		sd->sensor = SEN_OV6630;
+		PDEBUG(D_PROBE, "Sensor is an OV66308AF");
+	} else if (rc == 0x90) {
+		sd->sensor = SEN_OV6630;
+		PDEBUG(D_ERR,
+			"WARNING: Sensor is an OV66307. Your camera may have");
+		PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+	} else {
+		PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
+		return -1;
+	}
+
+	/* Set sensor-specific vars */
+	sd->maxwidth = 352;
+	sd->maxheight = 288;
+
+	if (sd->sensor == SEN_OV6620) {
+		PDEBUG(D_PROBE, "Writing 6x20 registers");
+		if (write_i2c_regvals(sd, norm_6x20,
+				sizeof norm_6x20 / sizeof norm_6x20[0]))
+			return -1;
+	} else {
+		PDEBUG(D_PROBE, "Writing 6x30 registers");
+		if (write_i2c_regvals(sd, norm_6x30,
+				sizeof norm_6x30 / sizeof norm_6x30[0]))
+			return -1;
+	}
+	return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
+static void ov51x_led_control(struct sd *sd, int on)
+{
+	PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off");
+
+/*	if (sd->bridge == BRG_OV511PLUS) */
+/*		reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */
+/*	else if (sd->bridge == BRG_OV519) */
+		reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);	/* 0 / 1 */
+/*	else if (sd->bclass == BCL_OV518) */
+/*		reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+/* (from ov519_configure) */
+	static const struct ov_regvals init_519[] = {
+		{ 0x5a,  0x6d }, /* EnableSystem */
+/* jfm trace usbsnoop3-1.txt */
+/* jfm 53 = fb */
+		{ 0x53,  0x9b },
+		{ 0x54,  0xff }, /* set bit2 to enable jpeg */
+		{ 0x5d,  0x03 },
+		{ 0x49,  0x01 },
+		{ 0x48,  0x00 },
+		/* Set LED pin to output mode. Bit 4 must be cleared or sensor
+		 * detection will fail. This deserves further investigation. */
+		{ OV519_GPIO_IO_CTRL0,   0xee },
+		{ 0x51,  0x0f }, /* SetUsbInit */
+		{ 0x51,  0x00 },
+		{ 0x22,  0x00 },
+		/* windows reads 0x55 at this point*/
+	};
+
+	if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+		goto error;
+/* jfm: not seen in windows trace */
+	if (ov519_init_compression(sd))
+		goto error;
+	ov51x_led_control(sd, 0);	/* turn LED off */
+
+	/* Test for 76xx */
+	sd->primary_i2c_slave = OV7xx0_SID;
+	if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
+		goto error;
+
+	/* The OV519 must be more aggressive about sensor detection since
+	 * I2C write will never fail if the sensor is not present. We have
+	 * to try to initialize the sensor to detect its presence */
+	if (init_ov_sensor(sd) < 0) {
+		/* Test for 6xx0 */
+		sd->primary_i2c_slave = OV6xx0_SID;
+		if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
+			goto error;
+
+		if (init_ov_sensor(sd) < 0) {
+			/* Test for 8xx0 */
+			sd->primary_i2c_slave = OV8xx0_SID;
+			if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
+				goto error;
+
+			if (init_ov_sensor(sd) < 0) {
+				PDEBUG(D_ERR,
+					"Can't determine sensor slave IDs");
+				goto error;
+			} else {
+				if (ov8xx0_configure(sd) < 0) {
+					PDEBUG(D_ERR,
+					   "Failed to configure OV8xx0 sensor");
+					goto error;
+				}
+			}
+		} else {
+			if (ov6xx0_configure(sd) < 0) {
+				PDEBUG(D_ERR, "Failed to configure OV6xx0");
+				goto error;
+			}
+		}
+	} else {
+		if (ov7xx0_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure OV7xx0");
+			goto error;
+		}
+	}
+
+	cam = &gspca_dev->cam;
+	cam->epaddr = OV511_ENDPOINT_ADDRESS;
+	if (sd->maxwidth == 640) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	}
+	cam->dev_name = (char *) id->driver_info;
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	return 0;
+error:
+	PDEBUG(D_ERR, "OV519 Config failed");
+	return -EBUSY;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+/* Sets up the OV519 with the given image parameters
+ *
+ * OV519 needs a completely different approach, until we can figure out what
+ * the individual registers do.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov519_mode_init_regs(struct sd *sd,
+				int width, int height)
+{
+	static const struct ov_regvals mode_init_519_ov7670[] = {
+		{ 0x5d,	0x03 }, /* Turn off suspend mode */
+		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */
+		{ 0x54,	0x0f }, /* bit2 (jpeg enable) */
+		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */
+		{ 0xa3,	0x18 },
+		{ 0xa4,	0x04 },
+		{ 0xa5,	0x28 },
+		{ 0x37,	0x00 },	/* SetUsbInit */
+		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */
+		/* Enable both fields, YUV Input, disable defect comp (why?) */
+		{ 0x20,	0x0c },
+		{ 0x21,	0x38 },
+		{ 0x22,	0x1d },
+		{ 0x17,	0x50 }, /* undocumented */
+		{ 0x37,	0x00 }, /* undocumented */
+		{ 0x40,	0xff }, /* I2C timeout counter */
+		{ 0x46,	0x00 }, /* I2C clock prescaler */
+		{ 0x59,	0x04 },	/* new from windrv 090403 */
+		{ 0xff,	0x00 }, /* undocumented */
+		/* windows reads 0x55 at this point, why? */
+	};
+
+	static const struct ov_regvals mode_init_519[] = {
+		{ 0x5d,	0x03 }, /* Turn off suspend mode */
+		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */
+		{ 0x54,	0x0f }, /* bit2 (jpeg enable) */
+		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */
+		{ 0xa3,	0x18 },
+		{ 0xa4,	0x04 },
+		{ 0xa5,	0x28 },
+		{ 0x37,	0x00 },	/* SetUsbInit */
+		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */
+		/* Enable both fields, YUV Input, disable defect comp (why?) */
+		{ 0x22,	0x1d },
+		{ 0x17,	0x50 }, /* undocumented */
+		{ 0x37,	0x00 }, /* undocumented */
+		{ 0x40,	0xff }, /* I2C timeout counter */
+		{ 0x46,	0x00 }, /* I2C clock prescaler */
+		{ 0x59,	0x04 },	/* new from windrv 090403 */
+		{ 0xff,	0x00 }, /* undocumented */
+		/* windows reads 0x55 at this point, why? */
+	};
+
+/* int hi_res; */
+
+	PDEBUG(D_CONF, "mode init %dx%d", width, height);
+
+/*	if (width >= 800 && height >= 600)
+		hi_res = 1;
+	else
+		hi_res = 0; */
+
+/*	if (ov51x_stop(sd) < 0)
+		return -EIO; */
+
+	/******** Set the mode ********/
+	if (sd->sensor != SEN_OV7670) {
+		if (write_regvals(sd, mode_init_519,
+				  ARRAY_SIZE(mode_init_519)))
+			return -EIO;
+	} else {
+		if (write_regvals(sd, mode_init_519_ov7670,
+				  ARRAY_SIZE(mode_init_519_ov7670)))
+			return -EIO;
+	}
+
+	if (sd->sensor == SEN_OV7640) {
+		/* Select 8-bit input mode */
+		reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+	}
+
+	reg_w(sd, OV519_CAM_H_SIZE,	width >> 4);
+	reg_w(sd, OV519_CAM_V_SIZE,	height >> 3);
+	reg_w(sd, OV519_CAM_X_OFFSETL,	0x00);
+	reg_w(sd, OV519_CAM_X_OFFSETH,	0x00);
+	reg_w(sd, OV519_CAM_Y_OFFSETL,	0x00);
+	reg_w(sd, OV519_CAM_Y_OFFSETH,	0x00);
+	reg_w(sd, OV519_CAM_DIVIDER,	0x00);
+	reg_w(sd, OV519_CAM_FORMAT,	0x03); /* YUV422 */
+	reg_w(sd, 0x26,			0x00); /* Undocumented */
+
+	/******** Set the framerate ********/
+	if (frame_rate > 0)
+		sd->frame_rate = frame_rate;
+
+/* FIXME: These are only valid at the max resolution. */
+	sd->clockdiv = 0;
+	if (sd->sensor == SEN_OV7640) {
+		switch (sd->frame_rate) {
+/*jfm: default was 30 fps */
+		case 30:
+			reg_w(sd, 0xa4, 0x0c);
+			reg_w(sd, 0x23, 0xff);
+			break;
+		case 25:
+			reg_w(sd, 0xa4, 0x0c);
+			reg_w(sd, 0x23, 0x1f);
+			break;
+		case 20:
+			reg_w(sd, 0xa4, 0x0c);
+			reg_w(sd, 0x23, 0x1b);
+			break;
+		default:
+/*		case 15: */
+			reg_w(sd, 0xa4, 0x04);
+			reg_w(sd, 0x23, 0xff);
+			sd->clockdiv = 1;
+			break;
+		case 10:
+			reg_w(sd, 0xa4, 0x04);
+			reg_w(sd, 0x23, 0x1f);
+			sd->clockdiv = 1;
+			break;
+		case 5:
+			reg_w(sd, 0xa4, 0x04);
+			reg_w(sd, 0x23, 0x1b);
+			sd->clockdiv = 1;
+			break;
+		}
+	} else if (sd->sensor == SEN_OV8610) {
+		switch (sd->frame_rate) {
+		default:	/* 15 fps */
+/*		case 15: */
+			reg_w(sd, 0xa4, 0x06);
+			reg_w(sd, 0x23, 0xff);
+			break;
+		case 10:
+			reg_w(sd, 0xa4, 0x06);
+			reg_w(sd, 0x23, 0x1f);
+			break;
+		case 5:
+			reg_w(sd, 0xa4, 0x06);
+			reg_w(sd, 0x23, 0x1b);
+			break;
+		}
+		sd->clockdiv = 0;
+	} else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
+		PDEBUG(D_STREAM, "Setting framerate to %d fps",
+				 (sd->frame_rate == 0) ? 15 : sd->frame_rate);
+		switch (sd->frame_rate) {
+		case 30:
+			reg_w(sd, 0xa4, 0x10);
+			reg_w(sd, 0x23, 0xff);
+			break;
+		case 20:
+			reg_w(sd, 0xa4, 0x10);
+			reg_w(sd, 0x23, 0x1b);
+			break;
+		default: /* 15 fps */
+/*			case 15: */
+			reg_w(sd, 0xa4, 0x10);
+			reg_w(sd, 0x23, 0xff);
+			sd->clockdiv = 1;
+			break;
+		}
+	}
+
+/*	if (ov51x_restart(sd) < 0)
+		return -EIO; */
+
+	/* Reset it just for good measure */
+/*	if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0)
+		return -EIO; */
+	return 0;
+}
+
+static int mode_init_ov_sensor_regs(struct sd *sd,
+				struct ovsensor_window *win)
+{
+	int qvga = win->quarter;
+
+	/******** Mode (VGA/QVGA) and sensor specific regs ********/
+	switch (sd->sensor) {
+	case SEN_OV8610:
+		/* For OV8610 qvga means qsvga */
+		i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+		break;
+	case SEN_OV7610:
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		break;
+	case SEN_OV7620:
+/*		i2c_w(sd, 0x2b, 0x00); */
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
+		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
+		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+		break;
+	case SEN_OV76BE:
+/*		i2c_w(sd, 0x2b, 0x00); */
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		break;
+	case SEN_OV7640:
+/*		i2c_w(sd, 0x2b, 0x00); */
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+/*		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
+/*		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */
+/*		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
+/*		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
+/*		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+		break;
+	case SEN_OV7670:
+		/* set COM7_FMT_VGA or COM7_FMT_QVGA
+		 * do we need to set anything else?
+		 *	HSTART etc are set in set_ov_sensor_window itself */
+		i2c_w_mask(sd, OV7670_REG_COM7,
+			 qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
+			 OV7670_COM7_FMT_MASK);
+		break;
+	case SEN_OV6620:
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		break;
+	case SEN_OV6630:
+		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/******** Palette-specific regs ********/
+/* Need to do work here for the OV7670 */
+
+		if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+			/* not valid on the OV6620/OV7620/6630? */
+			i2c_w_mask(sd, 0x0e, 0x00, 0x40);
+		}
+
+		/* The OV518 needs special treatment. Although both the OV518
+		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+		 * bus is actually used. The UV bus is tied to ground.
+		 * Therefore, the OV6630 needs to be in 8-bit multiplexed
+		 * output mode */
+
+		/* OV7640 is 8-bit only */
+
+		if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+			i2c_w_mask(sd, 0x13, 0x00, 0x20);
+/*	} */
+
+	/******** Clock programming ********/
+	/* The OV6620 needs special handling. This prevents the
+	 * severe banding that normally occurs */
+	if (sd->sensor == SEN_OV6620) {
+
+		/* Clock down */
+		i2c_w(sd, 0x2a, 0x04);
+		i2c_w(sd, 0x11, win->clockdiv);
+		i2c_w(sd, 0x2a, 0x84);
+		/* This next setting is critical. It seems to improve
+		 * the gain or the contrast. The "reserved" bits seem
+		 * to have some effect in this case. */
+		i2c_w(sd, 0x2d, 0x85);
+	} else if (win->clockdiv >= 0) {
+		i2c_w(sd, 0x11, win->clockdiv);
+	}
+
+	/******** Special Features ********/
+/* no evidence this is possible with OV7670, either */
+	/* Test Pattern */
+	if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670)
+		i2c_w_mask(sd, 0x12, 0x00, 0x02);
+
+	/* Enable auto white balance */
+	if (sd->sensor == SEN_OV7670)
+		i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+				OV7670_COM8_AWB);
+	else
+		i2c_w_mask(sd, 0x12, 0x04, 0x04);
+
+	/* This will go away as soon as ov51x_mode_init_sensor_regs() */
+	/* is fully tested. */
+	/* 7620/6620/6630? don't have register 0x35, so play it safe */
+	if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+		if (win->width == 640 /*&& win->height == 480*/)
+			i2c_w(sd, 0x35, 0x9e);
+		else
+			i2c_w(sd, 0x35, 0x1e);
+	}
+	return 0;
+}
+
+static int set_ov_sensor_window(struct sd *sd,
+				struct ovsensor_window *win)
+{
+	int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
+	int ret, hstart, hstop, vstop, vstart;
+	__u8 v;
+
+	/* The different sensor ICs handle setting up of window differently.
+	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
+	switch (sd->sensor) {
+	case SEN_OV8610:
+		hwsbase = 0x1e;
+		hwebase = 0x1e;
+		vwsbase = 0x02;
+		vwebase = 0x02;
+		break;
+	case SEN_OV7610:
+	case SEN_OV76BE:
+		hwsbase = 0x38;
+		hwebase = 0x3a;
+		vwsbase = vwebase = 0x05;
+		break;
+	case SEN_OV6620:
+	case SEN_OV6630:
+		hwsbase = 0x38;
+		hwebase = 0x3a;
+		vwsbase = 0x05;
+		vwebase = 0x06;
+		break;
+	case SEN_OV7620:
+		hwsbase = 0x2f;		/* From 7620.SET (spec is wrong) */
+		hwebase = 0x2f;
+		vwsbase = vwebase = 0x05;
+		break;
+	case SEN_OV7640:
+		hwsbase = 0x1a;
+		hwebase = 0x1a;
+		vwsbase = vwebase = 0x03;
+		break;
+	case SEN_OV7670:
+		/*handling of OV7670 hardware sensor start and stop values
+		 * is very odd, compared to the other OV sensors */
+		vwsbase = vwebase = hwebase = hwsbase = 0x00;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (sd->sensor) {
+	case SEN_OV6620:
+	case SEN_OV6630:
+		if (win->quarter) {	/* QCIF */
+			hwscale = 0;
+			vwscale = 0;
+		} else {		/* CIF */
+			hwscale = 1;
+			vwscale = 1;	/* The datasheet says 0;
+					 * it's wrong */
+		}
+		break;
+	case SEN_OV8610:
+		if (win->quarter) {	/* QSVGA */
+			hwscale = 1;
+			vwscale = 1;
+		} else {		/* SVGA */
+			hwscale = 2;
+			vwscale = 2;
+		}
+		break;
+	default:			/* SEN_OV7xx0 */
+		if (win->quarter) {	/* QVGA */
+			hwscale = 1;
+			vwscale = 0;
+		} else {		/* VGA */
+			hwscale = 2;
+			vwscale = 1;
+		}
+	}
+
+	ret = mode_init_ov_sensor_regs(sd, win);
+	if (ret < 0)
+		return ret;
+
+	if (sd->sensor == SEN_OV8610) {
+		i2c_w_mask(sd, 0x2d, 0x05, 0x40);
+				/* old 0x95, new 0x05 from windrv 090403 */
+						/* bits 5-7: reserved */
+		i2c_w_mask(sd, 0x28, 0x20, 0x20);
+					/* bit 5: progressive mode on */
+	}
+
+	/* The below is wrong for OV7670s because their window registers
+	 * only store the high bits in 0x17 to 0x1a */
+
+	/* SRH Use sd->max values instead of requested win values */
+	/* SCS Since we're sticking with only the max hardware widths
+	 * for a given mode */
+	/* I can hard code this for OV7670s */
+	/* Yes, these numbers do look odd, but they're tested and work! */
+	if (sd->sensor == SEN_OV7670) {
+		if (win->quarter) {	/* QVGA from ov7670.c by
+					 * Jonathan Corbet */
+			hstart = 164;
+			hstop = 20;
+			vstart = 14;
+			vstop = 494;
+		} else {		/* VGA */
+			hstart = 158;
+			hstop = 14;
+			vstart = 10;
+			vstop = 490;
+		}
+		/* OV7670 hardware window registers are split across
+		 * multiple locations */
+		i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff);
+		i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff);
+		v = i2c_r(sd, OV7670_REG_HREF);
+		v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
+		msleep(10);	/* need to sleep between read and write to
+				 * same reg! */
+		i2c_w(sd, OV7670_REG_HREF, v);
+
+		i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff);
+		i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
+		v = i2c_r(sd, OV7670_REG_VREF);
+		v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
+		msleep(10);	/* need to sleep between read and write to
+				 * same reg! */
+		i2c_w(sd, OV7670_REG_VREF, v);
+
+	} else {
+		i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale));
+		i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale));
+		i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale));
+		i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale));
+	}
+	return 0;
+}
+
+static int ov_sensor_mode_setup(struct sd *sd,
+				int width, int height)
+{
+	struct ovsensor_window win;
+
+/*	win.format = mode; */
+
+	/* Unless subcapture is enabled,
+	 * center the image window and downsample
+	 * if possible to increase the field of view */
+	/* NOTE: OV518(+) and OV519 does downsampling on its own */
+	win.width = width;
+	win.height = height;
+	if (width == sd->maxwidth)
+		win.quarter = 0;
+	else
+		win.quarter = 1;
+
+	/* Center it */
+	win.x = (win.width - width) / 2;
+	win.y = (win.height - height) / 2;
+
+	/* Clock is determined by OV519 frame rate code */
+	win.clockdiv = sd->clockdiv;
+
+	PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv);
+	return set_ov_sensor_window(sd, &win);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+
+	ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height);
+	if (ret < 0)
+		goto out;
+	ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
+	if (ret < 0)
+		goto out;
+
+	ret = ov51x_restart((struct sd *) gspca_dev);
+	if (ret < 0)
+		goto out;
+	PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+	ov51x_led_control(sd, 1);
+	return;
+out:
+	PDEBUG(D_ERR, "camera start error:%d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	ov51x_stop((struct sd *) gspca_dev);
+	ov51x_led_control((struct sd *) gspca_dev, 0);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	/* Header of ov519 is 16 bytes:
+	 *     Byte     Value      Description
+	 *	0	0xff	magic
+	 *	1	0xff	magic
+	 *	2	0xff	magic
+	 *	3	0xXX	0x50 = SOF, 0x51 = EOF
+	 *	9	0xXX	0x01 initial frame without data,
+	 *			0x00 standard frame with image
+	 *	14	Lo	in EOF: length of image data / 8
+	 *	15	Hi
+	 */
+
+	if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
+		switch (data[3]) {
+		case 0x50:		/* start of frame */
+#define HDRSZ 16
+			data += HDRSZ;
+			len -= HDRSZ;
+#undef HDRSZ
+			if (data[0] == 0xff || data[1] == 0xd8)
+				gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+						data, len);
+			else
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		case 0x51:		/* end of frame */
+			if (data[9] != 0)
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+			return;
+		}
+	}
+
+	/* intermediate packet */
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			data, len);
+}
+
+/* -- management routines -- */
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int val;
+/*	int was_streaming; */
+
+	val = sd->brightness;
+	PDEBUG(D_CONF, "brightness:%d", val);
+/*	was_streaming = gspca_dev->streaming;
+ *	if (was_streaming)
+ *		ov51x_stop(sd); */
+	switch (sd->sensor) {
+	case SEN_OV8610:
+	case SEN_OV7610:
+	case SEN_OV76BE:
+	case SEN_OV6620:
+	case SEN_OV6630:
+	case SEN_OV7640:
+		i2c_w(sd, OV7610_REG_BRT, val);
+		break;
+	case SEN_OV7620:
+		/* 7620 doesn't like manual changes when in auto mode */
+/*fixme
+ *		if (!sd->auto_brt) */
+			i2c_w(sd, OV7610_REG_BRT, val);
+		break;
+	case SEN_OV7670:
+/*jfm - from windblows
+ *		i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
+		i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+		break;
+	}
+/*	if (was_streaming)
+ *		ov51x_restart(sd); */
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int val;
+/*	int was_streaming; */
+
+	val = sd->contrast;
+	PDEBUG(D_CONF, "contrast:%d", val);
+/*	was_streaming = gspca_dev->streaming;
+	if (was_streaming)
+		ov51x_stop(sd); */
+	switch (sd->sensor) {
+	case SEN_OV7610:
+	case SEN_OV6620:
+		i2c_w(sd, OV7610_REG_CNT, val);
+		break;
+	case SEN_OV6630:
+		i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+	case SEN_OV8610: {
+		static const __u8 ctab[] = {
+			0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
+		};
+
+		/* Use Y gamma control instead. Bit 0 enables it. */
+		i2c_w(sd, 0x64, ctab[val >> 5]);
+		break;
+	    }
+	case SEN_OV7620: {
+		static const __u8 ctab[] = {
+			0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+			0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+		};
+
+		/* Use Y gamma control instead. Bit 0 enables it. */
+		i2c_w(sd, 0x64, ctab[val >> 4]);
+		break;
+	    }
+	case SEN_OV7640:
+		/* Use gain control instead. */
+		i2c_w(sd, OV7610_REG_GAIN, val >> 2);
+		break;
+	case SEN_OV7670:
+		/* check that this isn't just the same as ov7610 */
+		i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
+		break;
+	}
+/*	if (was_streaming)
+		ov51x_restart(sd); */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int val;
+/*	int was_streaming; */
+
+	val = sd->colors;
+	PDEBUG(D_CONF, "saturation:%d", val);
+/*	was_streaming = gspca_dev->streaming;
+	if (was_streaming)
+		ov51x_stop(sd); */
+	switch (sd->sensor) {
+	case SEN_OV8610:
+	case SEN_OV7610:
+	case SEN_OV76BE:
+	case SEN_OV6620:
+	case SEN_OV6630:
+		i2c_w(sd, OV7610_REG_SAT, val);
+		break;
+	case SEN_OV7620:
+		/* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+/*		rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
+		if (rc < 0)
+			goto out; */
+		i2c_w(sd, OV7610_REG_SAT, val);
+		break;
+	case SEN_OV7640:
+		i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
+		break;
+	case SEN_OV7670:
+		/* supported later once I work out how to do it
+		 * transparently fail now! */
+		/* set REG_COM13 values for UV sat auto mode */
+		break;
+	}
+/*	if (was_streaming)
+		ov51x_restart(sd); */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")},
+	{USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")},
+	{USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")},
+	{USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")},
+	{USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")},
+	{USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")},
+	{USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")},
+	{USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")},
+	{USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")},
+	{USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")},
+	{USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")},
+	{USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")},
+	{USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")},
+	{}
+};
+#undef DVNAME
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(frame_rate, int, 0644);
+MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
+
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
new file mode 100644
index 0000000..fa7abc4
--- /dev/null
+++ b/drivers/media/video/gspca/pac207.c
@@ -0,0 +1,622 @@
+/*
+ * Pixart PAC207BCA library
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ *
+ */
+
+#define MODULE_NAME "pac207"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Pixart PAC207");
+MODULE_LICENSE("GPL");
+
+#define PAC207_CTRL_TIMEOUT		100  /* ms */
+
+#define PAC207_BRIGHTNESS_MIN		0
+#define PAC207_BRIGHTNESS_MAX		255
+#define PAC207_BRIGHTNESS_DEFAULT	4 /* power on default: 4 */
+
+/* An exposure value of 4 also works (3 does not) but then we need to lower
+   the compression balance setting when in 352x288 mode, otherwise the usb
+   bandwidth is not enough and packets get dropped resulting in corrupt
+   frames. The problem with this is that when the compression balance gets
+   lowered below 0x80, the pac207 starts using a different compression
+   algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
+   and currently we do not know how to decompress these lines, so for now
+   we use a minimum exposure value of 5 */
+#define PAC207_EXPOSURE_MIN		5
+#define PAC207_EXPOSURE_MAX		26
+#define PAC207_EXPOSURE_DEFAULT		5 /* power on default: 3 ?? */
+#define PAC207_EXPOSURE_KNEE		11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+
+#define PAC207_GAIN_MIN			0
+#define PAC207_GAIN_MAX			31
+#define PAC207_GAIN_DEFAULT         	9 /* power on default: 9 */
+#define PAC207_GAIN_KNEE		20
+
+#define PAC207_AUTOGAIN_DEADZONE	30
+/* We calculating the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define PAC207_AUTOGAIN_IGNORE_FRAMES	3
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	u8 mode;
+
+	u8 brightness;
+	u8 exposure;
+	u8 autogain;
+	u8 gain;
+
+	u8 sof_read;
+	u8 header_read;
+	u8 autogain_ignore_frames;
+
+	atomic_t avg_lum;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = PAC207_BRIGHTNESS_MIN,
+		.maximum = PAC207_BRIGHTNESS_MAX,
+		.step = 1,
+		.default_value = PAC207_BRIGHTNESS_DEFAULT,
+		.flags = 0,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_EXPOSURE 1
+	{
+	    {
+		.id = V4L2_CID_EXPOSURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "exposure",
+		.minimum = PAC207_EXPOSURE_MIN,
+		.maximum = PAC207_EXPOSURE_MAX,
+		.step = 1,
+		.default_value = PAC207_EXPOSURE_DEFAULT,
+		.flags = 0,
+	    },
+	    .set = sd_setexposure,
+	    .get = sd_getexposure,
+	},
+#define SD_AUTOGAIN 2
+	{
+	    {
+		.id	  = V4L2_CID_AUTOGAIN,
+		.type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.name	= "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step	= 1,
+		.default_value = 1,
+		.flags = 0,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+#define SD_GAIN 3
+	{
+	    {
+		.id = V4L2_CID_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "gain",
+		.minimum = PAC207_GAIN_MIN,
+		.maximum = PAC207_GAIN_MAX,
+		.step = 1,
+		.default_value = PAC207_GAIN_DEFAULT,
+		.flags = 0,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = (176 + 2) * 144,
+			/* uncompressed, add 2 bytes / line for line header */
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+			/* compressed, but only when needed (not compressed
+			   when the framerate is low) */
+		.sizeimage = (352 + 2) * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+static const __u8 pac207_sensor_init[][8] = {
+	{0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
+	{0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
+	{0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
+	{0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
+	{0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
+};
+
+			/* 48 reg_72 Rate Control end BalSize_4a =0x36 */
+static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
+
+static const unsigned char pac207_sof_marker[5] =
+		{ 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
+	const u8 *buffer, u16 length)
+{
+	struct usb_device *udev = gspca_dev->dev;
+	int err;
+
+	memcpy(gspca_dev->usb_buf, buffer, length);
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0x00, index,
+			gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
+	if (err < 0)
+		PDEBUG(D_ERR,
+			"Failed to write registers to index 0x%04X, error %d)",
+			index, err);
+
+	return err;
+}
+
+
+int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
+{
+	struct usb_device *udev = gspca_dev->dev;
+	int err;
+
+	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
+	if (err)
+		PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+			" value 0x%02X, error %d)", index, value, err);
+
+	return err;
+}
+
+
+int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
+{
+	struct usb_device *udev = gspca_dev->dev;
+	int res;
+
+	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0x00, index,
+			gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
+	if (res < 0) {
+		PDEBUG(D_ERR,
+			"Failed to read a register (index 0x%04X, error %d)",
+			index, res);
+		return res;
+	}
+
+	return gspca_dev->usb_buf[0];
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	u8 idreg[2];
+
+	idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
+	idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
+	idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
+	idreg[1] = idreg[1] & 0x0f;
+	PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
+		idreg[0], idreg[1]);
+
+	if (idreg[0] != 0x27) {
+		PDEBUG(D_PROBE, "Error invalid sensor ID!");
+		return -ENODEV;
+	}
+
+	pac207_write_reg(gspca_dev, 0x41, 0x00);
+				/* Bit_0=Image Format,
+				 * Bit_1=LED,
+				 * Bit_2=Compression test mode enable */
+	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+	pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
+
+	PDEBUG(D_PROBE,
+		"Pixart PAC207BCA Image Processor and Control Chip detected"
+		" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x05;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = ARRAY_SIZE(sif_mode);
+	sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
+	sd->exposure = PAC207_EXPOSURE_DEFAULT;
+	sd->gain = PAC207_GAIN_DEFAULT;
+
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = 1;
+	return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 mode;
+
+	pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
+	pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
+	pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
+	pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
+	pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
+	pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
+	pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
+
+	/* Compression Balance */
+	if (gspca_dev->width == 176)
+		pac207_write_reg(gspca_dev, 0x4a, 0xff);
+	else
+		pac207_write_reg(gspca_dev, 0x4a, 0x88);
+	pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
+	pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+
+	/* PGA global gain (Bit 4-0) */
+	pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+	pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
+
+	mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
+	if (gspca_dev->width == 176) {	/* 176x144 */
+		mode |= 0x01;
+		PDEBUG(D_STREAM, "pac207_start mode 176x144");
+	} else {				/* 352x288 */
+		PDEBUG(D_STREAM, "pac207_start mode 352x288");
+	}
+	pac207_write_reg(gspca_dev, 0x41, mode);
+
+	pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+	pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+	msleep(10);
+	pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
+
+	sd->sof_read = 0;
+	sd->autogain_ignore_frames = 0;
+	atomic_set(&sd->avg_lum, -1);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
+	pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
+	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int avg_lum = atomic_read(&sd->avg_lum);
+
+	if (avg_lum == -1)
+		return;
+
+	if (sd->autogain_ignore_frames > 0)
+		sd->autogain_ignore_frames--;
+	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+			100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
+			PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
+		sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
+}
+
+static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
+					unsigned char *m, int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+
+	/* Search for the SOF marker (fixed part) in the header */
+	for (i = 0; i < len; i++) {
+		if (m[i] == pac207_sof_marker[sd->sof_read]) {
+			sd->sof_read++;
+			if (sd->sof_read == sizeof(pac207_sof_marker)) {
+				PDEBUG(D_STREAM,
+					"SOF found, bytes to analyze: %u."
+					" Frame starts at byte #%u",
+					len, i + 1);
+				sd->sof_read = 0;
+				return m + i + 1;
+			}
+		} else {
+			sd->sof_read = 0;
+		}
+	}
+
+	return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,
+			__u8 *data,
+			int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned char *sof;
+
+	sof = pac207_find_sof(gspca_dev, data, len);
+	if (sof) {
+		int n;
+
+		/* finish decoding current frame */
+		n = sof - data;
+		if (n > sizeof pac207_sof_marker)
+			n -= sizeof pac207_sof_marker;
+		else
+			n = 0;
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, n);
+		sd->header_read = 0;
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+		len -= sof - data;
+		data = sof;
+	}
+	if (sd->header_read < 11) {
+		int needed;
+
+		/* get average lumination from frame header (byte 5) */
+		if (sd->header_read < 5) {
+			needed = 5 - sd->header_read;
+			if (len >= needed)
+				atomic_set(&sd->avg_lum, data[needed - 1]);
+		}
+		/* skip the rest of the header */
+		needed = 11 - sd->header_read;
+		if (len <= needed) {
+			sd->header_read += len;
+			return;
+		}
+		data += needed;
+		len -= needed;
+		sd->header_read = 11;
+	}
+
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
+	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	pac207_write_reg(gspca_dev, 0x02, sd->exposure);
+	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
+	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
+	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->autogain) {
+		sd->exposure = PAC207_EXPOSURE_DEFAULT;
+		sd->gain = PAC207_GAIN_DEFAULT;
+		if (gspca_dev->streaming) {
+			sd->autogain_ignore_frames =
+				PAC207_AUTOGAIN_IGNORE_FRAMES;
+			setexposure(gspca_dev);
+			setgain(gspca_dev);
+		}
+	}
+
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.dq_callback = pac207_do_auto_gain,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
+	{USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
+	{USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
+	{USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
+	{USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
+	{USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
+	{USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
+	{USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
+	{USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
new file mode 100644
index 0000000..5c052e3
--- /dev/null
+++ b/drivers/media/video/gspca/pac7311.c
@@ -0,0 +1,760 @@
+/*
+ *		Pixart PAC7311 library
+ *		Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "pac7311"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_DESCRIPTION("Pixart PAC7311");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int avg_lum;
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	char ffseq;
+	signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+#define BRIGHTNESS_MAX 0x20
+		.maximum = BRIGHTNESS_MAX,
+		.step    = 1,
+#define BRIGHTNESS_DEF 0x10
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define CONTRAST_DEF 127
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define COLOR_DEF 127
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define AUTOGAIN_DEF 1
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header)	/* (594) */
+
+static const __u8 pac7311_jpeg_header[] = {
+	0xff, 0xd8,
+	0xff, 0xe0, 0x00, 0x03, 0x20,
+	0xff, 0xc0, 0x00, 0x11, 0x08,
+		0x01, 0xe0,			/* 12: height */
+		0x02, 0x80,			/* 14: width */
+		0x03,				/* 16 */
+			0x01, 0x21, 0x00,
+			0x02, 0x11, 0x01,
+			0x03, 0x11, 0x01,
+	0xff, 0xdb, 0x00, 0x84,
+	0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
+	0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
+	0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
+	0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
+	0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
+	0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
+	0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
+	0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
+	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+	0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+	0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+	0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+	0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+	0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
+	0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
+	0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+	0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+	0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+	0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
+	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+	0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+	0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+	0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+	0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+	0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+	0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+	0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+	0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+	0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+	0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
+	0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
+	0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+	0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
+	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+	0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+	0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+	0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+	0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+	0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+	0x11, 0x00, 0x3f, 0x00
+};
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  const char *buffer, __u16 len)
+{
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			1,		/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, gspca_dev->usb_buf, len,
+			500);
+}
+
+static __u8 reg_r(struct gspca_dev *gspca_dev,
+			     __u16 index)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,			/* value */
+			index, gspca_dev->usb_buf, 1,
+			500);
+	return gspca_dev->usb_buf[0];
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u8 value)
+{
+	gspca_dev->usb_buf[0] = value;
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, gspca_dev->usb_buf, 1,
+			500);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	PDEBUG(D_CONF, "Find Sensor PAC7311");
+	reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0xff, 0x04);
+	reg_w(gspca_dev, 0x27, 0x80);
+	reg_w(gspca_dev, 0x28, 0xca);
+	reg_w(gspca_dev, 0x29, 0x53);
+	reg_w(gspca_dev, 0x2a, 0x0e);
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x3e, 0x20);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x05;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->autogain = AUTOGAIN_DEF;
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int brightness;
+
+/*jfm: inverted?*/
+	brightness = BRIGHTNESS_MAX - sd->brightness;
+	reg_w(gspca_dev, 0xff, 0x04);
+/*	reg_w(gspca_dev, 0x0e, 0x00); */
+	reg_w(gspca_dev, 0x0f, brightness);
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x80, sd->contrast);
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x10, sd->colors);
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0x78, 0x00);	/* Turn on LED */
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
+	reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
+	reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
+	reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
+	reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
+	reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
+	reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
+	reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
+	reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
+	reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
+	reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
+	reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
+	reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
+	reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
+	reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
+	reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
+	reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
+	reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
+	reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
+	reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+
+	reg_w(gspca_dev, 0xff, 0x04);
+	reg_w(gspca_dev, 0x02, 0x04);
+	reg_w(gspca_dev, 0x03, 0x54);
+	reg_w(gspca_dev, 0x04, 0x07);
+	reg_w(gspca_dev, 0x05, 0x2b);
+	reg_w(gspca_dev, 0x06, 0x09);
+	reg_w(gspca_dev, 0x07, 0x0f);
+	reg_w(gspca_dev, 0x08, 0x09);
+	reg_w(gspca_dev, 0x09, 0x00);
+	reg_w(gspca_dev, 0x0c, 0x07);
+	reg_w(gspca_dev, 0x0d, 0x00);
+	reg_w(gspca_dev, 0x0e, 0x00);
+	reg_w(gspca_dev, 0x0f, 0x62);
+	reg_w(gspca_dev, 0x10, 0x08);
+	reg_w(gspca_dev, 0x12, 0x07);
+	reg_w(gspca_dev, 0x13, 0x00);
+	reg_w(gspca_dev, 0x14, 0x00);
+	reg_w(gspca_dev, 0x15, 0x00);
+	reg_w(gspca_dev, 0x16, 0x00);
+	reg_w(gspca_dev, 0x17, 0x00);
+	reg_w(gspca_dev, 0x18, 0x00);
+	reg_w(gspca_dev, 0x19, 0x00);
+	reg_w(gspca_dev, 0x1a, 0x00);
+	reg_w(gspca_dev, 0x1b, 0x03);
+	reg_w(gspca_dev, 0x1c, 0xa0);
+	reg_w(gspca_dev, 0x1d, 0x01);
+	reg_w(gspca_dev, 0x1e, 0xf4);
+	reg_w(gspca_dev, 0x21, 0x00);
+	reg_w(gspca_dev, 0x22, 0x08);
+	reg_w(gspca_dev, 0x24, 0x03);
+	reg_w(gspca_dev, 0x26, 0x00);
+	reg_w(gspca_dev, 0x27, 0x01);
+	reg_w(gspca_dev, 0x28, 0xca);
+	reg_w(gspca_dev, 0x29, 0x10);
+	reg_w(gspca_dev, 0x2a, 0x06);
+	reg_w(gspca_dev, 0x2b, 0x78);
+	reg_w(gspca_dev, 0x2c, 0x00);
+	reg_w(gspca_dev, 0x2d, 0x00);
+	reg_w(gspca_dev, 0x2e, 0x00);
+	reg_w(gspca_dev, 0x2f, 0x00);
+	reg_w(gspca_dev, 0x30, 0x23);
+	reg_w(gspca_dev, 0x31, 0x28);
+	reg_w(gspca_dev, 0x32, 0x04);
+	reg_w(gspca_dev, 0x33, 0x11);
+	reg_w(gspca_dev, 0x34, 0x00);
+	reg_w(gspca_dev, 0x35, 0x00);
+	reg_w(gspca_dev, 0x11, 0x01);
+	setcontrast(gspca_dev);
+	setbrightness(gspca_dev);
+	setcolors(gspca_dev);
+
+	/* set correct resolution */
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 2:					/* 160x120 */
+		reg_w(gspca_dev, 0xff, 0x04);
+		reg_w(gspca_dev, 0x02, 0x03);
+		reg_w(gspca_dev, 0xff, 0x01);
+		reg_w(gspca_dev, 0x08, 0x09);
+		reg_w(gspca_dev, 0x17, 0x20);
+		reg_w(gspca_dev, 0x1b, 0x00);
+/*		reg_w(gspca_dev, 0x80, 0x69); */
+		reg_w(gspca_dev, 0x87, 0x10);
+		break;
+	case 1:					/* 320x240 */
+		reg_w(gspca_dev, 0xff, 0x04);
+		reg_w(gspca_dev, 0x02, 0x03);
+		reg_w(gspca_dev, 0xff, 0x01);
+		reg_w(gspca_dev, 0x08, 0x09);
+		reg_w(gspca_dev, 0x17, 0x30);
+/*		reg_w(gspca_dev, 0x80, 0x3f); */
+		reg_w(gspca_dev, 0x87, 0x11);
+		break;
+	case 0:					/* 640x480 */
+		reg_w(gspca_dev, 0xff, 0x04);
+		reg_w(gspca_dev, 0x02, 0x03);
+		reg_w(gspca_dev, 0xff, 0x01);
+		reg_w(gspca_dev, 0x08, 0x08);
+		reg_w(gspca_dev, 0x17, 0x00);
+/*		reg_w(gspca_dev, 0x80, 0x1c); */
+		reg_w(gspca_dev, 0x87, 0x12);
+		break;
+	}
+
+	/* start stream */
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x78, 0x04);
+	reg_w(gspca_dev, 0x78, 0x05);
+
+	if (sd->autogain) {
+		sd->ag_cnt = AG_CNT_START;
+		sd->avg_lum = 0;
+	} else {
+		sd->ag_cnt = -1;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0xff, 0x04);
+	reg_w(gspca_dev, 0x27, 0x80);
+	reg_w(gspca_dev, 0x28, 0xca);
+	reg_w(gspca_dev, 0x29, 0x53);
+	reg_w(gspca_dev, 0x2a, 0x0e);
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x3e, 0x20);
+	reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0xff, 0x04);
+	reg_w(gspca_dev, 0x27, 0x80);
+	reg_w(gspca_dev, 0x28, 0xca);
+	reg_w(gspca_dev, 0x29, 0x53);
+	reg_w(gspca_dev, 0x2a, 0x0e);
+	reg_w(gspca_dev, 0xff, 0x01);
+	reg_w(gspca_dev, 0x3e, 0x20);
+	reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void setautogain(struct gspca_dev *gspca_dev, int luma)
+{
+	int luma_mean = 128;
+	int luma_delta = 20;
+	__u8 spring = 5;
+	int Gbright;
+
+	Gbright = reg_r(gspca_dev, 0x02);
+	PDEBUG(D_FRAM, "luma mean %d", luma);
+	if (luma < luma_mean - luma_delta ||
+	    luma > luma_mean + luma_delta) {
+		Gbright += (luma_mean - luma) >> spring;
+		if (Gbright > 0x1a)
+			Gbright = 0x1a;
+		else if (Gbright < 4)
+			Gbright = 4;
+		PDEBUG(D_FRAM, "gbright %d", Gbright);
+		reg_w(gspca_dev, 0xff, 0x04);
+		reg_w(gspca_dev, 0x0f, Gbright);
+		/* load registers to sensor (Bit 0, auto clear) */
+		reg_w(gspca_dev, 0x11, 0x01);
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned char tmpbuf[4];
+	int i, p, ffseq;
+
+/*	if (len < 5) { */
+	if (len < 6) {
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+
+	ffseq = sd->ffseq;
+
+	for (p = 0; p < len - 6; p++) {
+		if ((data[0 + p] == 0xff)
+		    && (data[1 + p] == 0xff)
+		    && (data[2 + p] == 0x00)
+		    && (data[3 + p] == 0xff)
+		    && (data[4 + p] == 0x96)) {
+
+			/* start of frame */
+			if (sd->ag_cnt >= 0 && p > 28) {
+				sd->avg_lum += data[p - 23];
+				if (--sd->ag_cnt < 0) {
+					sd->ag_cnt = AG_CNT_START;
+					setautogain(gspca_dev,
+						sd->avg_lum / AG_CNT_START);
+					sd->avg_lum = 0;
+				}
+			}
+
+			/* copy the end of data to the current frame */
+			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+						data, p);
+
+			/* put the JPEG header in the new frame */
+			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+					(unsigned char *) pac7311_jpeg_header,
+					12);
+			tmpbuf[0] = gspca_dev->height >> 8;
+			tmpbuf[1] = gspca_dev->height & 0xff;
+			tmpbuf[2] = gspca_dev->width >> 8;
+			tmpbuf[3] = gspca_dev->width & 0xff;
+			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+					tmpbuf, 4);
+			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+				(unsigned char *) &pac7311_jpeg_header[16],
+				PAC7311_JPEG_HEADER_SIZE - 16);
+
+			data += p + 7;
+			len -= p + 7;
+			ffseq = 0;
+			break;
+		}
+	}
+
+	/* remove the 'ff ff ff xx' sequences */
+	switch (ffseq) {
+	case 3:
+		data += 1;
+		len -= 1;
+		break;
+	case 2:
+		if (data[0] == 0xff) {
+			data += 2;
+			len -= 2;
+			frame->data_end -= 2;
+		}
+		break;
+	case 1:
+		if (data[0] == 0xff
+		    && data[1] == 0xff) {
+			data += 3;
+			len -= 3;
+			frame->data_end -= 1;
+		}
+		break;
+	}
+	for (i = 0; i < len - 4; i++) {
+		if (data[i] == 0xff
+		    && data[i + 1] == 0xff
+		    && data[i + 2] == 0xff) {
+			memmove(&data[i], &data[i + 4], len - i - 4);
+			len -= 4;
+		}
+	}
+	ffseq = 0;
+	if (data[len - 4] == 0xff) {
+		if (data[len - 3] == 0xff
+		    && data[len - 2] == 0xff) {
+			len -= 4;
+		}
+	} else if (data[len - 3] == 0xff) {
+		if (data[len - 2] == 0xff
+		    && data[len - 1] == 0xff)
+			ffseq = 3;
+	} else if (data[len - 2] == 0xff) {
+		if (data[len - 1] == 0xff)
+			ffseq = 2;
+	} else if (data[len - 1] == 0xff)
+		ffseq = 1;
+	sd->ffseq = ffseq;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+/*	sd->brightness = reg_r(gspca_dev, 0x08);
+	return sd->brightness;	*/
+/*	PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
+}
+
+
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+/*	getcontrast(gspca_dev); */
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+/*	getcolors(gspca_dev); */
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val) {
+		sd->ag_cnt = AG_CNT_START;
+		sd->avg_lum = 0;
+	} else {
+		sd->ag_cnt = -1;
+	}
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
+	{USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
+	{USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
+	{USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
+	{USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
+			/* and also ', Trust WB-3350p, SIGMA cam 2350' */
+	{USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
+	{USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
new file mode 100644
index 0000000..dbeebe8
--- /dev/null
+++ b/drivers/media/video/gspca/sonixb.c
@@ -0,0 +1,1477 @@
+/*
+ *		sonix sn9c102 (bayer) library
+ *		Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "sonixb"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 8)
+static const char version[] = "2.1.8";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	struct sd_desc sd_desc;		/* our nctrls differ dependend upon the
+					   sensor, so we use a per cam copy */
+	atomic_t avg_lum;
+
+	unsigned char gain;
+	unsigned char exposure;
+	unsigned char brightness;
+	unsigned char autogain;
+	unsigned char autogain_ignore_frames;
+	unsigned char freq;		/* light freq filter setting */
+	unsigned char saturation;
+	unsigned char hue;
+	unsigned char contrast;
+
+	unsigned char fr_h_sz;		/* size of frame header */
+	char sensor;			/* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_OV6650 1
+#define SENSOR_OV7630 2
+#define SENSOR_OV7630_3 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110 6
+#define SENSOR_TAS5130CXX 7
+	char sensor_has_gain;
+	__u8 sensor_addr;
+};
+
+#define COMP2 0x8f
+#define COMP 0xc7		/* 0x87 //0x07 */
+#define COMP1 0xc9		/* 0x89 //0x09 */
+
+#define MCK_INIT 0x63
+#define MCK_INIT1 0x20		/*fixme: Bayer - 0x50 for JPEG ??*/
+
+#define SYS_CLK 0x04
+
+/* We calculate the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define AUTOGAIN_IGNORE_FRAMES 3
+#define AUTOGAIN_DEADZONE 1000
+#define DESIRED_AVG_LUM 7000
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 127
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_GAIN,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gain",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 200
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+	{
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Exposure",
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+			.default_value = EXPOSURE_DEF,
+			.flags = 0,
+		},
+		.set = sd_setexposure,
+		.get = sd_getexposure,
+	},
+	{
+		{
+			.id = V4L2_CID_AUTOGAIN,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Automatic Gain (and Exposure)",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+#define AUTOGAIN_DEF 1
+			.default_value = AUTOGAIN_DEF,
+			.flags = 0,
+		},
+		.set = sd_setautogain,
+		.get = sd_getautogain,
+	},
+	{
+		{
+			.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+			.type    = V4L2_CTRL_TYPE_MENU,
+			.name    = "Light frequency filter",
+			.minimum = 0,
+			.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+			.step    = 1,
+#define FREQ_DEF 1
+			.default_value = FREQ_DEF,
+		},
+		.set = sd_setfreq,
+		.get = sd_getfreq,
+	},
+	{
+		{
+			.id      = V4L2_CID_SATURATION,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Saturation",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define SATURATION_DEF 127
+			.default_value = SATURATION_DEF,
+		},
+		.set = sd_setsaturation,
+		.get = sd_getsaturation,
+	},
+	{
+		{
+			.id      = V4L2_CID_HUE,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Hue",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define HUE_DEF 127
+			.default_value = HUE_DEF,
+		},
+		.set = sd_sethue,
+		.get = sd_gethue,
+	},
+	{
+		{
+			.id      = V4L2_CID_CONTRAST,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Contrast",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define CONTRAST_DEF 127
+			.default_value = CONTRAST_DEF,
+		},
+		.set = sd_setcontrast,
+		.get = sd_getcontrast,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+static const __u8 probe_ov7630[] = {0x08, 0x44};
+
+static const __u8 initHv7131[] = {
+	0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0x01, 0x00,	/* shift from 0x02 0x01 0x00 */
+	0x28, 0x1e, 0x60, 0x8a, 0x20,
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131_sensor_init[][8] = {
+	{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
+	{0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
+	{0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
+	{0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
+	{0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
+};
+static const __u8 initOv6650[] = {
+	0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
+	0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+};
+static const __u8 ov6650_sensor_init[][8] =
+{
+	/* Bright, contrast, etc are set througth SCBB interface.
+	 * AVCAP on win2 do not send any data on this 	controls. */
+	/* Anyway, some registers appears to alter bright and constrat */
+
+	/* Reset sensor */
+	{0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+	/* Set clock register 0x11 low nibble is clock divider */
+	{0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+	/* Next some unknown stuff */
+	{0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
+/*	{0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
+		 * THIS SET GREEN SCREEN
+		 * (pixels could be innverted in decode kind of "brg",
+		 * but blue wont be there. Avoid this data ... */
+	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
+	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
+	{0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+	/* Enable rgb brightness control */
+	{0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
+	/* HDG: Note windows uses the line below, which sets both register 0x60
+	   and 0x61 I believe these registers of the ov6650 are identical as
+	   those of the ov7630, because if this is true the windows settings
+	   add a bit additional red gain and a lot additional blue gain, which
+	   matches my findings that the windows settings make blue much too
+	   blue and red a little too red.
+	{0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
+	/* Some more unknown stuff */
+	{0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
+	{0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
+};
+
+static const __u8 initOv7630[] = {
+	0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,	/* r01 .. r08 */
+	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* r09 .. r10 */
+	0x00, 0x02, 0x01, 0x0a,				/* r11 .. r14 */
+	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
+	0x68, COMP1, MCK_INIT1,				/* r17 .. r19 */
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c		/* r1a .. r1f */
+};
+static const __u8 initOv7630_3[] = {
+	0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80,	/* r01 .. r08 */
+	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,	/* r09 .. r10 */
+	0x00, 0x01, 0x01, 0x0a,				/* r11 .. r14 */
+	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
+	0x68, 0x8f, MCK_INIT1,				/* r17 .. r19 */
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00,	/* r1a .. r20 */
+	0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
+	0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff  /* r29 .. r30 */
+};
+static const __u8 ov7630_sensor_init_com[][8] = {
+	{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
+/*	{0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10},	   jfm */
+	{0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10},	/* jfm */
+	{0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
+	{0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
+	{0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
+	{0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
+	{0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
+	{0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
+	{0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
+	{0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
+/*	{0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10},	 * jfm */
+	{0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
+	{0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
+	{0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
+	{0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
+	{0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
+	{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
+};
+static const __u8 ov7630_sensor_init[][8] = {
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
+	{0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10},	/* jfm */
+	{0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15},	/* gain */
+};
+static const __u8 ov7630_sensor_init_3[][8] = {
+	{0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10},
+};
+
+static const __u8 initPas106[] = {
+	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
+	0x16, 0x12, 0x28, COMP1, MCK_INIT1,
+	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+/* compression 0x86 mckinit1 0x2b */
+static const __u8 pas106_data[][2] = {
+	{0x02, 0x04},		/* Pixel Clock Divider 6 */
+	{0x03, 0x13},		/* Frame Time MSB */
+/*	{0x03, 0x12},		 * Frame Time MSB */
+	{0x04, 0x06},		/* Frame Time LSB */
+/*	{0x04, 0x05},		 * Frame Time LSB */
+	{0x05, 0x65},		/* Shutter Time Line Offset */
+/*	{0x05, 0x6d},		 * Shutter Time Line Offset */
+/*	{0x06, 0xb1},		 * Shutter Time Pixel Offset */
+	{0x06, 0xcd},		/* Shutter Time Pixel Offset */
+	{0x07, 0xc1},		/* Black Level Subtract Sign */
+/*	{0x07, 0x00},		 * Black Level Subtract Sign */
+	{0x08, 0x06},		/* Black Level Subtract Level */
+	{0x08, 0x06},		/* Black Level Subtract Level */
+/*	{0x08, 0x01},		 * Black Level Subtract Level */
+	{0x09, 0x05},		/* Color Gain B Pixel 5 a */
+	{0x0a, 0x04},		/* Color Gain G1 Pixel 1 5 */
+	{0x0b, 0x04},		/* Color Gain G2 Pixel 1 0 5 */
+	{0x0c, 0x05},		/* Color Gain R Pixel 3 1 */
+	{0x0d, 0x00},		/* Color GainH  Pixel */
+	{0x0e, 0x0e},		/* Global Gain */
+	{0x0f, 0x00},		/* Contrast */
+	{0x10, 0x06},		/* H&V synchro polarity */
+	{0x11, 0x06},		/* ?default */
+	{0x12, 0x06},		/* DAC scale */
+	{0x14, 0x02},		/* ?default */
+	{0x13, 0x01},		/* Validate Settings */
+};
+static const __u8 initPas202[] = {
+	0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x07, 0x03, 0x0a,	/* 6 */
+	0x28, 0x1e, 0x28, 0x89, 0x30,
+	0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 pas202_sensor_init[][8] = {
+	{0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
+	{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
+	{0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+	{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+	{0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
+	{0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
+
+	{0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
+	{0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+	{0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
+	{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+};
+
+static const __u8 initTas5110[] = {
+	0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x01, 0x00, 0x46, 0x09, 0x0a,	/* shift from 0x45 0x09 0x0a */
+	0x16, 0x12, 0x60, 0x86, 0x2b,
+	0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+static const __u8 tas5110_sensor_init[][8] = {
+	{0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
+	{0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
+	{0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+
+static const __u8 initTas5130[] = {
+	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+	0x28, 0x1e, 0x60, COMP, MCK_INIT,
+	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+static const __u8 tas5130_sensor_init[][8] = {
+/* 	{0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+					* shutter 0x47 short exposure? */
+	{0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
+					/* shutter 0x01 long exposure */
+	{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
+};
+
+/* get one byte in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 value)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value,
+			0,			/* index */
+			gspca_dev->usb_buf, 1,
+			500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+		  __u16 value,
+		  const __u8 *buffer,
+		  int len)
+{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	if (len > sizeof gspca_dev->usb_buf) {
+		PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
+		return;
+	}
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x08,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value,
+			0,			/* index */
+			gspca_dev->usb_buf, len,
+			500);
+}
+
+static void reg_w_big(struct gspca_dev *gspca_dev,
+		  __u16 value,
+		  const __u8 *buffer,
+		  int len)
+{
+	__u8 *tmpbuf;
+
+	tmpbuf = kmalloc(len, GFP_KERNEL);
+	memcpy(tmpbuf, buffer, len);
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x08,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value,
+			0,			/* index */
+			tmpbuf, len,
+			500);
+	kfree(tmpbuf);
+}
+
+static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
+{
+	int retry = 60;
+
+	/* is i2c ready */
+	reg_w(gspca_dev, 0x08, buffer, 8);
+	while (retry--) {
+		msleep(10);
+		reg_r(gspca_dev, 0x08);
+		if (gspca_dev->usb_buf[0] & 0x04) {
+			if (gspca_dev->usb_buf[0] & 0x08)
+				return -1;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static void i2c_w_vector(struct gspca_dev *gspca_dev,
+			const __u8 buffer[][8], int len)
+{
+	for (;;) {
+		reg_w(gspca_dev, 0x08, *buffer, 8);
+		len -= 8;
+		if (len <= 0)
+			break;
+		buffer++;
+	}
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+
+	switch (sd->sensor) {
+	case  SENSOR_OV6650:
+	case  SENSOR_OV7630_3:
+	case  SENSOR_OV7630: {
+		__u8 i2cOV[] =
+			{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+		/* change reg 0x06 */
+		i2cOV[1] = sd->sensor_addr;
+		i2cOV[3] = sd->brightness;
+		if (i2c_w(gspca_dev, i2cOV) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_PAS106: {
+		__u8 i2c1[] =
+			{0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
+
+		i2c1[3] = sd->brightness >> 3;
+		i2c1[2] = 0x0e;
+		if (i2c_w(gspca_dev, i2c1) < 0)
+			goto err;
+		i2c1[3] = 0x01;
+		i2c1[2] = 0x13;
+		if (i2c_w(gspca_dev, i2c1) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_PAS202: {
+		/* __u8 i2cpexpo1[] =
+			{0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
+		__u8 i2cpexpo[] =
+			{0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
+		__u8 i2cp202[] =
+			{0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
+		static __u8 i2cpdoit[] =
+			{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
+
+		/* change reg 0x10 */
+		i2cpexpo[4] = 0xff - sd->brightness;
+/*		if(i2c_w(gspca_dev,i2cpexpo1) < 0)
+			goto err; */
+/*		if(i2c_w(gspca_dev,i2cpdoit) < 0)
+			goto err; */
+		if (i2c_w(gspca_dev, i2cpexpo) < 0)
+			goto err;
+		if (i2c_w(gspca_dev, i2cpdoit) < 0)
+			goto err;
+		i2cp202[3] = sd->brightness >> 3;
+		if (i2c_w(gspca_dev, i2cp202) < 0)
+			goto err;
+		if (i2c_w(gspca_dev, i2cpdoit) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_TAS5130CXX: {
+		__u8 i2c[] =
+			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+		value = 0xff - sd->brightness;
+		i2c[4] = value;
+		PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
+		if (i2c_w(gspca_dev, i2c) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_TAS5110:
+		/* FIXME figure out howto control brightness on TAS5110 */
+		break;
+	}
+	return;
+err:
+	PDEBUG(D_ERR, "i2c error brightness");
+}
+
+static void setsensorgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned char gain = sd->gain;
+
+	switch (sd->sensor) {
+
+	case SENSOR_TAS5110: {
+		__u8 i2c[] =
+			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+		i2c[4] = 255 - gain;
+		if (i2c_w(gspca_dev, i2c) < 0)
+			goto err;
+		break;
+	    }
+
+	case SENSOR_OV6650:
+		gain >>= 1;
+		/* fall thru */
+	case SENSOR_OV7630_3: {
+		__u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = gain >> 2;
+		if (i2c_w(gspca_dev, i2c) < 0)
+			goto err;
+		break;
+	    }
+	}
+	return;
+err:
+	PDEBUG(D_ERR, "i2c error gain");
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 gain;
+	__u8 rgb_value;
+
+	gain = sd->gain >> 4;
+
+	/* red and blue gain */
+	rgb_value = gain << 4 | gain;
+	reg_w(gspca_dev, 0x10, &rgb_value, 1);
+	/* green gain */
+	rgb_value = gain;
+	reg_w(gspca_dev, 0x11, &rgb_value, 1);
+
+	if (sd->sensor_has_gain)
+		setsensorgain(gspca_dev);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+	case SENSOR_TAS5110: {
+		__u8 reg;
+
+		/* register 19's high nibble contains the sn9c10x clock divider
+		   The high nibble configures the no fps according to the
+		   formula: 60 / high_nibble. With a maximum of 30 fps */
+		reg = 120 * sd->exposure / 1000;
+		if (reg < 2)
+			reg = 2;
+		else if (reg > 15)
+			reg = 15;
+		reg = (reg << 4) | 0x0b;
+		reg_w(gspca_dev, 0x19, &reg, 1);
+		break;
+	    }
+	case SENSOR_OV6650:
+	case SENSOR_OV7630_3: {
+		/* The ov6650 / ov7630 have 2 registers which both influence
+		   exposure, register 11, whose low nibble sets the nr off fps
+		   according to: fps = 30 / (low_nibble + 1)
+
+		   The fps configures the maximum exposure setting, but it is
+		   possible to use less exposure then what the fps maximum
+		   allows by setting register 10. register 10 configures the
+		   actual exposure as quotient of the full exposure, with 0
+		   being no exposure at all (not very usefull) and reg10_max
+		   being max exposure possible at that framerate.
+
+		   The code maps our 0 - 510 ms exposure ctrl to these 2
+		   registers, trying to keep fps as high as possible.
+		*/
+		__u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
+		int reg10, reg11;
+		/* ov6645 datasheet says reg10_max is 9a, but that uses
+		   tline * 2 * reg10 as formula for calculating texpo, the
+		   ov6650 probably uses the same formula as the 7730 which uses
+		   tline * 4 * reg10, which explains why the reg10max we've
+		   found experimentally for the ov6650 is exactly half that of
+		   the ov6645. The ov7630 datasheet says the max is 0x41. */
+		const int reg10_max = (sd->sensor == SENSOR_OV6650)
+				? 0x4d : 0x41;
+
+		reg11 = (60 * sd->exposure + 999) / 1000;
+		if (reg11 < 1)
+			reg11 = 1;
+		else if (reg11 > 16)
+			reg11 = 16;
+
+		/* frame exposure time in ms = 1000 * reg11 / 30    ->
+		reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
+		reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
+
+		/* Don't allow this to get below 10 when using autogain, the
+		   steps become very large (relatively) when below 10 causing
+		   the image to oscilate from much too dark, to much too bright
+		   and back again. */
+		if (sd->autogain && reg10 < 10)
+			reg10 = 10;
+		else if (reg10 > reg10_max)
+			reg10 = reg10_max;
+
+		/* Write reg 10 and reg11 low nibble */
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = reg10;
+		i2c[4] |= reg11 - 1;
+		if (sd->sensor == SENSOR_OV7630_3) {
+			__u8 reg76 = reg10 & 0x03;
+			__u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00,
+					    0x00, 0x00, 0x00, 0x10};
+			reg10 >>= 2;
+			i2c_reg76[3] = reg76;
+			if (i2c_w(gspca_dev, i2c_reg76) < 0)
+				PDEBUG(D_ERR, "i2c error exposure");
+		}
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error exposure");
+		break;
+	    }
+	}
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+	case SENSOR_OV6650:
+	case SENSOR_OV7630_3: {
+		/* Framerate adjust register for artificial light 50 hz flicker
+		   compensation, identical to ov6630 0x2b register, see ov6630
+		   datasheet.
+		   0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
+		__u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
+		switch (sd->freq) {
+		default:
+/*		case 0:			 * no filter*/
+/*		case 2:			 * 60 hz */
+			i2c[3] = 0;
+			break;
+		case 1:			/* 50 hz */
+			i2c[3] = (sd->sensor == SENSOR_OV6650)
+					? 0x4f : 0x8a;
+			break;
+		}
+		i2c[1] = sd->sensor_addr;
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setfreq");
+		break;
+	    }
+	}
+}
+
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = sd->saturation & 0xf0;
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setsaturation");
+		else
+			PDEBUG(D_CONF, "saturation set to: %d",
+				(int)sd->saturation);
+		break;
+	    }
+	}
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = 0x20 | (sd->hue >> 3);
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setsaturation");
+		else
+			PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
+		break;
+	    }
+	}
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = 0x20 | (sd->contrast >> 3);
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setcontrast");
+		else
+			PDEBUG(D_CONF, "contrast set to: %d",
+				(int)sd->contrast);
+		break;
+	    }
+	}
+}
+
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int avg_lum = atomic_read(&sd->avg_lum);
+
+	if (avg_lum == -1)
+		return;
+
+	if (sd->autogain_ignore_frames > 0)
+		sd->autogain_ignore_frames--;
+	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+			sd->brightness * DESIRED_AVG_LUM / 127,
+			AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
+		PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
+			(int)sd->gain, (int)sd->exposure);
+		sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 product;
+	int sif = 0;
+
+	/* nctrls depends upon the sensor, so we use a per cam copy */
+	memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
+	gspca_dev->sd_desc = &sd->sd_desc;
+
+	sd->fr_h_sz = 12;		/* default size of the frame header */
+	sd->sd_desc.nctrls = 2;		/* default nb of ctrls */
+	sd->autogain = AUTOGAIN_DEF;    /* default is autogain active */
+
+	product = id->idProduct;
+/*	switch (id->idVendor) { */
+/*	case 0x0c45:				 * Sonix */
+		switch (product) {
+		case 0x6001:			/* SN9C102 */
+		case 0x6005:			/* SN9C101 */
+		case 0x6007:			/* SN9C101 */
+			sd->sensor = SENSOR_TAS5110;
+			sd->sensor_has_gain = 1;
+			sd->sd_desc.nctrls = 4;
+			sd->sd_desc.dq_callback = do_autogain;
+			sif = 1;
+			break;
+		case 0x6009:			/* SN9C101 */
+		case 0x600d:			/* SN9C101 */
+		case 0x6029:			/* SN9C101 */
+			sd->sensor = SENSOR_PAS106;
+			sif = 1;
+			break;
+		case 0x6011:			/* SN9C101 - SN9C101G */
+			sd->sensor = SENSOR_OV6650;
+			sd->sensor_has_gain = 1;
+			sd->sensor_addr = 0x60;
+			sd->sd_desc.nctrls = 5;
+			sd->sd_desc.dq_callback = do_autogain;
+			sif = 1;
+			break;
+		case 0x6019:			/* SN9C101 */
+		case 0x602c:			/* SN9C102 */
+		case 0x602e:			/* SN9C102 */
+			sd->sensor = SENSOR_OV7630;
+			sd->sensor_addr = 0x21;
+			break;
+		case 0x60b0:			/* SN9C103 */
+			sd->sensor = SENSOR_OV7630_3;
+			sd->sensor_addr = 0x21;
+			sd->fr_h_sz = 18;	/* size of frame header */
+			sd->sensor_has_gain = 1;
+			sd->sd_desc.nctrls = 8;
+			sd->sd_desc.dq_callback = do_autogain;
+			sd->autogain = 0;
+			break;
+		case 0x6024:			/* SN9C102 */
+		case 0x6025:			/* SN9C102 */
+			sd->sensor = SENSOR_TAS5130CXX;
+			break;
+		case 0x6028:			/* SN9C102 */
+			sd->sensor = SENSOR_PAS202;
+			break;
+		case 0x602d:			/* SN9C102 */
+			sd->sensor = SENSOR_HV7131R;
+			break;
+		case 0x60af:			/* SN9C103 */
+			sd->sensor = SENSOR_PAS202;
+			sd->fr_h_sz = 18;	/* size of frame header (?) */
+			break;
+		}
+/*		break; */
+/*	} */
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	if (!sif) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = ARRAY_SIZE(vga_mode);
+		if (sd->sensor == SENSOR_OV7630_3) {
+			/* We only have 320x240 & 640x480 */
+			cam->cam_mode++;
+			cam->nmodes--;
+		}
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = ARRAY_SIZE(sif_mode);
+	}
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->gain = GAIN_DEF;
+	sd->exposure = EXPOSURE_DEF;
+	sd->freq = FREQ_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->saturation = SATURATION_DEF;
+	sd->hue = HUE_DEF;
+	if (sd->sensor == SENSOR_OV7630_3)	/* jfm: from win trace */
+		reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	reg_r(gspca_dev, 0x00);
+	if (gspca_dev->usb_buf[0] != 0x10)
+		return -ENODEV;
+	return 0;
+}
+
+static void pas106_i2cinit(struct gspca_dev *gspca_dev)
+{
+	int i;
+	const __u8 *data;
+	__u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
+
+	i = ARRAY_SIZE(pas106_data);
+	data = pas106_data[0];
+	while (--i >= 0) {
+		memcpy(&i2c1[2], data, 2);
+					/* copy 2 bytes from the template */
+		if (i2c_w(gspca_dev, i2c1) < 0)
+			PDEBUG(D_ERR, "i2c error pas106");
+		data += 2;
+	}
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int mode, l;
+	const __u8 *sn9c10x;
+	__u8 reg01, reg17;
+	__u8 reg17_19[3];
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		sn9c10x = initHv7131;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | 0x8a;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_OV6650:
+		sn9c10x = initOv6650;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | 0x8b;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_OV7630:
+		sn9c10x = initOv7630;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | COMP2;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_OV7630_3:
+		sn9c10x = initOv7630_3;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | COMP2;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_PAS106:
+		sn9c10x = initPas106;
+		reg17_19[0] = 0x24;		/* 0x28 */
+		reg17_19[1] = (mode << 4) | COMP1;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_PAS202:
+		sn9c10x = initPas202;
+		reg17_19[0] = mode ? 0x24 : 0x20;
+		reg17_19[1] = (mode << 4) | 0x89;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_TAS5110:
+		sn9c10x = initTas5110;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | 0x86;
+		reg17_19[2] = 0x2b;		/* 0xf3; */
+		break;
+	default:
+/*	case SENSOR_TAS5130CXX: */
+		sn9c10x = initTas5130;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | COMP;
+		reg17_19[2] = mode ? 0x23 : 0x43;
+		break;
+	}
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+		reg01 = 0x06;
+		reg17 = 0x29;
+		l = sizeof initOv7630;
+		break;
+	case SENSOR_OV7630_3:
+		reg01 = 0x44;
+		reg17 = 0x68;
+		l = sizeof initOv7630_3;
+		break;
+	default:
+		reg01 = sn9c10x[0];
+		reg17 = sn9c10x[0x17 - 1];
+		l = 0x1f;
+		break;
+	}
+
+	/* reg 0x01 bit 2 video transfert on */
+	reg_w(gspca_dev, 0x01, &reg01, 1);
+	/* reg 0x17 SensorClk enable inv Clk 0x60 */
+	reg_w(gspca_dev, 0x17, &reg17, 1);
+/*fixme: for ov7630 102
+	reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
+	/* Set the registers from the template */
+	reg_w_big(gspca_dev, 0x01, sn9c10x, l);
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		i2c_w_vector(gspca_dev, hv7131_sensor_init,
+				sizeof hv7131_sensor_init);
+		break;
+	case SENSOR_OV6650:
+		i2c_w_vector(gspca_dev, ov6650_sensor_init,
+				sizeof ov6650_sensor_init);
+		break;
+	case SENSOR_OV7630:
+		i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
+				sizeof ov7630_sensor_init_com);
+		msleep(200);
+		i2c_w_vector(gspca_dev, ov7630_sensor_init,
+				sizeof ov7630_sensor_init);
+		break;
+	case SENSOR_OV7630_3:
+		i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
+				sizeof ov7630_sensor_init_com);
+		msleep(200);
+		i2c_w(gspca_dev, ov7630_sensor_init_3[mode]);
+		break;
+	case SENSOR_PAS106:
+		pas106_i2cinit(gspca_dev);
+		break;
+	case SENSOR_PAS202:
+		i2c_w_vector(gspca_dev, pas202_sensor_init,
+				sizeof pas202_sensor_init);
+		break;
+	case SENSOR_TAS5110:
+		i2c_w_vector(gspca_dev, tas5110_sensor_init,
+				sizeof tas5110_sensor_init);
+		break;
+	default:
+/*	case SENSOR_TAS5130CXX: */
+		i2c_w_vector(gspca_dev, tas5130_sensor_init,
+				sizeof tas5130_sensor_init);
+		break;
+	}
+	/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
+	reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
+	/* compression register */
+	reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
+	/* H_start */
+	reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
+	/* V_START */
+	reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
+	/* reset 0x17 SensorClk enable inv Clk 0x60 */
+				/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
+	reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
+	/*MCKSIZE ->3 */	/*fixme: not ov7630*/
+	reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
+	/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
+	reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+	/* Enable video transfert */
+	reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
+	/* Compression */
+	reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
+	msleep(20);
+
+	setgain(gspca_dev);
+	setbrightness(gspca_dev);
+	setexposure(gspca_dev);
+	setfreq(gspca_dev);
+	setsaturation(gspca_dev);
+	sethue(gspca_dev);
+	setcontrast(gspca_dev);
+
+	sd->autogain_ignore_frames = 0;
+	atomic_set(&sd->avg_lum, -1);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	__u8 ByteSend;
+
+	ByteSend = 0x09;	/* 0X00 */
+	reg_w(gspca_dev, 0x01, &ByteSend, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	int i;
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* frames start with:
+	 *	ff ff 00 c4 c4 96	synchro
+	 *	00		(unknown)
+	 *	xx		(frame sequence / size / compression)
+	 *	(xx)		(idem - extra byte for sn9c103)
+	 *	ll mm		brightness sum inside auto exposure
+	 *	ll mm		brightness sum outside auto exposure
+	 *	(xx xx xx xx xx)	audio values for snc103
+	 */
+	if (len > 6 && len < 24) {
+		for (i = 0; i < len - 6; i++) {
+			if (data[0 + i] == 0xff
+			    && data[1 + i] == 0xff
+			    && data[2 + i] == 0x00
+			    && data[3 + i] == 0xc4
+			    && data[4 + i] == 0xc4
+			    && data[5 + i] == 0x96) {	/* start of frame */
+				frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+							frame, data, 0);
+				if (len - i < sd->fr_h_sz) {
+					atomic_set(&sd->avg_lum, -1);
+					PDEBUG(D_STREAM, "packet too short to"
+						" get avg brightness");
+				} else if (sd->fr_h_sz == 12) {
+					atomic_set(&sd->avg_lum,
+						data[i + 8] +
+							(data[i + 9] << 8));
+				} else {
+					atomic_set(&sd->avg_lum,
+						data[i + 9] +
+							(data[i + 10] << 8));
+				}
+				data += i + sd->fr_h_sz;
+				len -= i + sd->fr_h_sz;
+				gspca_frame_add(gspca_dev, FIRST_PACKET,
+						frame, data, len);
+				return;
+			}
+		}
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+			frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->autogain) {
+		sd->exposure = EXPOSURE_DEF;
+		sd->gain = GAIN_DEF;
+		if (gspca_dev->streaming) {
+			sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
+			setexposure(gspca_dev);
+			setgain(gspca_dev);
+		}
+	}
+
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->freq = val;
+	if (gspca_dev->streaming)
+		setfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->freq;
+	return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->saturation = val;
+	if (gspca_dev->streaming)
+		setsaturation(gspca_dev);
+	return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->saturation;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hue;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy((char *) menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+	{USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
+	{USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
+	{USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
+	{USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
+	{USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+#endif
+	{USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
+#ifndef CONFIG_USB_SN9C102
+	{USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
+	{USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
+	{USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
+	{USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
+	{USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
+	{USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
+	{USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
+	{USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
+	{USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
+	{USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
+#endif
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
new file mode 100644
index 0000000..3e68b99
--- /dev/null
+++ b/drivers/media/video/gspca/sonixj.c
@@ -0,0 +1,1671 @@
+/*
+ *		Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
+ *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "sonixj"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	int avg_lum;
+	unsigned int exposure;
+
+	unsigned short brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	signed char ag_cnt;
+#define AG_CNT_START 13
+
+	char qindex;
+	unsigned char bridge;
+#define BRIDGE_SN9C102P 0
+#define BRIDGE_SN9C105 1
+#define BRIDGE_SN9C110 2
+#define BRIDGE_SN9C120 3
+#define BRIDGE_SN9C325 4
+	char sensor;			/* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_MI0360 1
+#define SENSOR_MO4000 2
+#define SENSOR_OV7648 3
+#define SENSOR_OV7660 4
+	unsigned char i2c_base;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xffff,
+		.step    = 1,
+#define BRIGHTNESS_DEF 0x7fff
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 127,
+		.step    = 1,
+#define CONTRAST_DEF 63
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define COLOR_DEF 127
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define AUTOGAIN_DEF 1
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/*Data from sn9c102p+hv71331r */
+static const __u8 sn_hv7131[] = {
+/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+	0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
+/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
+	0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,		/* 00 */
+/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+	0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
+/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_mi0360[] = {
+/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+	0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
+/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+	0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
+/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_mo4000[] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
+	0x12,	0x23,	0x60,	0x00,	0x1A,	0x00,	0x20,	0x18,	0x81,
+/*	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
+	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
+/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
+	0x0b,	0x0f,	0x14,	0x28,	0x1e,	0x40,	0x08,	0x00,	0x00,
+/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
+	0x00,	0x00,	0x00,	0x00,	0x00,	0x08,	0x25,	0x39,	0x4b,
+	0x5c,	0x6b,	0x79,	0x87,	0x95,	0xa2,	0xaf,	0xbb,	0xc7,
+	0xd3,	0xdf,	0xea,	0xf5
+};
+
+static const __u8 sn_ov7648[] = {
+	0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
+	0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_ov7660[]	= {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
+	0x00,	0x61,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,	0x81,
+/* 	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
+	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
+/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
+	0x01,	0x01,	0x14,	0x28,	0x1e,	0x00,	0x07,	0x00,	0x00,
+/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
+	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
+};
+
+/* sequence specific to the sensors - !! index = SENSOR_xxx */
+static const __u8 *sn_tb[] = {
+	sn_hv7131,
+	sn_mi0360,
+	sn_mo4000,
+	sn_ov7648,
+	sn_ov7660
+};
+
+static const __u8 regsn20[] = {
+	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+};
+static const __u8 regsn20_sn9c120[] = {
+	0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90,
+	0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff
+};
+static const __u8 regsn20_sn9c325[] = {
+	0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
+	0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
+};
+
+static const __u8 reg84[] = {
+	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
+	0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
+/*	0x00, 0x00, 0x00, 0x00, 0x00 */
+	0xf7, 0x0f, 0x0a, 0x00, 0x00
+};
+static const __u8 reg84_sn9c120_1[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0c, 0x00, 0x00
+};
+static const __u8 reg84_sn9c120_2[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0c, 0x02, 0x3b
+};
+static const __u8 reg84_sn9c120_3[] = {
+	0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f,
+	0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f,
+	0xf5, 0x0f, 0x0c, 0x02, 0x3b
+};
+static const __u8 reg84_sn9c325[] = {
+	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
+	0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
+	0xf8, 0x0f, 0x00, 0x00, 0x00
+};
+
+static const __u8 hv7131r_sensor_init[][8] = {
+	{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+	{0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+	{0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+	{0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+	{0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+	{0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+	{0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const __u8 mi0360_sensor_init[][8] = {
+	{0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+	{0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+	{0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+	{0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+	{0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+	{0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+	{0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+	{0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+	{0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+	{0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+	{0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+
+	{0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+	{0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+	{0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+	{0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+/*	{0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/*	{0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+	{0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+	{0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+	{}
+};
+static const __u8 mo4000_sensor_init[][8] = {
+	{0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const __u8 ov7660_sensor_init[][8] = {
+	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+	{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+						/* Outformat ?? rawRGB */
+	{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
+	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
+/*	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */
+						/* GAIN BLUE RED VREF */
+	{0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
+						/* COM 1 BAVE GEAVE AECHH */
+	{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
+	{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
+	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
+/*	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */
+						/* AECH CLKRC COM7 COM8 */
+	{0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
+	{0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
+						/* HSTART HSTOP VSTRT VSTOP */
+	{0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
+	{0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
+	{0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
+					/* BOS GBOS GROS ROS (BGGR offset) */
+	{0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
+/*	{0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */
+						/* AEW AEB VPT BBIAS */
+	{0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
+						/* GbBIAS RSVD EXHCH EXHCL */
+	{0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
+						/* RBIAS ADVFL ASDVFH YAVE */
+	{0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
+						/* HSYST HSYEN HREF */
+	{0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
+						/* ADC ACOM OFON TSLB */
+	{0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
+						/* COM11 COM12 COM13 COM14 */
+	{0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
+						/* EDGE COM15 COM16 COM17 */
+	{0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
+	{0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
+	{0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
+	{0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
+	{0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
+						/* LCC1 LCC2 LCC3 LCC4 */
+	{0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
+	{0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+	{0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
+					/* band gap reference [0..3] DBLV */
+	{0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
+	{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
+	{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
+	{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+						/* bits[3..0]reserved */
+	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+						/* VREF vertical frame ctrl */
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
+	{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+/*	{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */
+	{0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+	{0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
+	{0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
+	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+/**********startsensor KO if changed !!****/
+	{0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
+/* here may start the isoc exchanges */
+	{}
+};
+/* reg0x04		reg0x07		reg 0x10 */
+/* expo  = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+
+static const __u8 ov7648_sensor_init[][8] = {
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
+	{0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
+	{0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+	{0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
+	{0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
+	{0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
+	{0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
+	{0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
+	{0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
+	{0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
+	{0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+	{0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
+	{0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
+	{0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
+	{0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
+	{0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
+  /*	{0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * This is currently setting a
+ * blue tint, and some things more , i leave it here for future test if
+ * somene is having problems with color on this sensor
+	{0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10},  */
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
+	{0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
+	{0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
+/*	{0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10},  * Bright/Witene */
+	{}
+};
+
+static const __u8 qtable4[] = {
+	0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+	0x06, 0x08, 0x0A, 0x11,
+	0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+	0x19, 0x19, 0x17, 0x15,
+	0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+	0x21, 0x2E, 0x21, 0x23,
+	0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+	0x25, 0x29, 0x2C, 0x29,
+	0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+	0x17, 0x1B, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29
+};
+
+/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 value, int len)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value, 0,
+			gspca_dev->usb_buf, len,
+			500);
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+			  __u16 value,
+			  const __u8 *buffer,
+			  int len)
+{
+	if (len <= sizeof gspca_dev->usb_buf) {
+		memcpy(gspca_dev->usb_buf, buffer, len);
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0x08,
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				value, 0,
+				gspca_dev->usb_buf, len,
+				500);
+	} else {
+		__u8 *tmpbuf;
+
+		tmpbuf = kmalloc(len, GFP_KERNEL);
+		memcpy(tmpbuf, buffer, len);
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0x08,
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				value, 0,
+				tmpbuf, len,
+				500);
+		kfree(tmpbuf);
+	}
+}
+
+/* I2C write 2 bytes */
+static void i2c_w2(struct gspca_dev *gspca_dev,
+		   const __u8 *buffer)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 mode[8];
+
+	/* is i2c ready */
+	mode[0] = 0x81 | (2 << 4);
+	mode[1] = sd->i2c_base;
+	mode[2] = buffer[0];
+	mode[3] = buffer[1];
+	mode[4] = 0;
+	mode[5] = 0;
+	mode[6] = 0;
+	mode[7] = 0x10;
+	reg_w(gspca_dev, 0x08, mode, 8);
+}
+
+/* I2C write 8 bytes */
+static void i2c_w8(struct gspca_dev *gspca_dev,
+		   const __u8 *buffer)
+{
+	reg_w(gspca_dev, 0x08, buffer, 8);
+	msleep(1);
+}
+
+/* read 5 bytes in gspca_dev->usb_buf */
+static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 mode[8];
+
+	mode[0] = 0x81 | 0x10;
+	mode[1] = sd->i2c_base;
+	mode[2] = reg;
+	mode[3] = 0;
+	mode[4] = 0;
+	mode[5] = 0;
+	mode[6] = 0;
+	mode[7] = 0x10;
+	i2c_w8(gspca_dev, mode);
+	mode[0] = 0x81 | (5 << 4) | 0x02;
+	mode[2] = 0;
+	i2c_w8(gspca_dev, mode);
+	reg_r(gspca_dev, 0x0a, 5);
+}
+
+static int probesensor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 reg02;
+	static const __u8 datasend[] = { 2, 0 };
+	/* reg val1 val2 val3 val4 */
+
+	i2c_w2(gspca_dev, datasend);
+/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
+	msleep(10);
+	reg02 = 0x66;
+	reg_w(gspca_dev, 0x02, &reg02, 1);		/* Gpio on */
+	msleep(10);
+	i2c_r5(gspca_dev, 0);				/* read sensor id */
+	if (gspca_dev->usb_buf[0] == 0x02
+	    && gspca_dev->usb_buf[1] == 0x09
+	    && gspca_dev->usb_buf[2] == 0x01
+	    && gspca_dev->usb_buf[3] == 0x00
+	    && gspca_dev->usb_buf[4] == 0x00) {
+		PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
+		sd->sensor = SENSOR_HV7131R;
+		return SENSOR_HV7131R;
+	}
+	PDEBUG(D_PROBE, "Find Sensor %d %d %d",
+		gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
+		gspca_dev->usb_buf[2]);
+	PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
+	return -ENODEV;
+}
+
+static int configure_gpio(struct gspca_dev *gspca_dev,
+			  const __u8 *sn9c1xx)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
+	__u8 regF1;
+	const __u8 *reg9a;
+	static const __u8 reg9a_def[] =
+		{0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+	static const __u8 reg9a_sn9c120[] =		/* from win trace */
+		{0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+	static const __u8 reg9a_sn9c325[] =
+		{0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+
+
+	regF1 = 0x00;
+	reg_w(gspca_dev, 0xf1, &regF1, 1);
+	reg_w(gspca_dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/
+
+	/* configure gpio */
+	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
+	reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
+	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);	/* jfm was 3 */
+	switch (sd->bridge) {
+	case BRIDGE_SN9C325:
+		reg9a = reg9a_sn9c325;
+		break;
+	case BRIDGE_SN9C120:
+		reg9a = reg9a_sn9c120;
+		break;
+	default:
+		reg9a = reg9a_def;
+		break;
+	}
+	reg_w(gspca_dev, 0x9a, reg9a, 6);
+
+	data = 0x60;				/*fixme:jfm 60 00 00 (3) */
+	reg_w(gspca_dev, 0xd4, &data, 1);
+
+	reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+	switch (sd->bridge) {
+	case BRIDGE_SN9C120:			/* from win trace */
+		data = 0x61;
+		reg_w(gspca_dev, 0x01, &data, 1);
+		data = 0x20;
+		reg_w(gspca_dev, 0x17, &data, 1);
+		data = 0x60;
+		reg_w(gspca_dev, 0x01, &data, 1);
+		break;
+	case BRIDGE_SN9C325:
+		data = 0x43;
+		reg_w(gspca_dev, 0x01, &data, 1);
+		data = 0xae;
+		reg_w(gspca_dev, 0x17, &data, 1);
+		data = 0x42;
+		reg_w(gspca_dev, 0x01, &data, 1);
+		break;
+	default:
+		data = 0x43;
+		reg_w(gspca_dev, 0x01, &data, 1);
+		data = 0x61;
+		reg_w(gspca_dev, 0x17, &data, 1);
+		data = 0x42;
+		reg_w(gspca_dev, 0x01, &data, 1);
+	}
+
+	if (sd->sensor == SENSOR_HV7131R) {
+		if (probesensor(gspca_dev) < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	static const __u8 SetSensorClk[] =	/* 0x08 Mclk */
+		{ 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+	while (hv7131r_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, hv7131r_sensor_init[i]);
+		i++;
+	}
+	i2c_w8(gspca_dev, SetSensorClk);
+}
+
+static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	while (mi0360_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, mi0360_sensor_init[i]);
+		i++;
+	}
+}
+
+static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	while (mo4000_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, mo4000_sensor_init[i]);
+		i++;
+	}
+}
+
+static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	while (ov7648_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, ov7648_sensor_init[i]);
+		i++;
+	}
+}
+
+static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	while (ov7660_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, ov7660_sensor_init[i]);
+		i++;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	sd->sensor = -1;
+	switch (vendor) {
+	case 0x0458:				/* Genius */
+/*		switch (product) {
+		case 0x7025: */
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_base = 0x5d;
+/*			break;
+		} */
+		break;
+	case 0x045e:
+/*		switch (product) {
+		case 0x00f5:
+		case 0x00f7: */
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_base = 0x21;
+/*			break;
+		} */
+		break;
+	case 0x0471:				/* Philips */
+/*		switch (product) {
+		case 0x0327:
+		case 0x0328:
+		case 0x0330: */
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_base = 0x5d;
+/*			break;
+		} */
+		break;
+	case 0x0c45:				/* Sonix */
+		switch (product) {
+		case 0x6040:
+			sd->bridge = BRIDGE_SN9C102P;
+/*			sd->sensor = SENSOR_MI0360;	 * from BW600.inf */
+/*fixme: MI0360 base=5d ? */
+			sd->sensor = SENSOR_HV7131R;	/* gspcav1 value */
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x607a:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C102P;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x607c:
+			sd->bridge = BRIDGE_SN9C102P;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x607e:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C102P;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60c0:
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_base = 0x5d;
+			break;
+/*		case 0x60c8:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_OM6801;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x60cc:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_HV7131GP;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60ec:
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x60ef:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x60fa:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60fb:
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_base = 0x21;
+			break;
+		case 0x60fc:
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x60fe:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C105;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x6108:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_OM6801;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x6122:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C110;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x612a:
+/*			sd->bridge = BRIDGE_SN9C110;	 * in BW600.inf */
+			sd->bridge = BRIDGE_SN9C325;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_base = 0x21;
+/*fixme: sensor_init has base = 00 et 6e!*/
+			break;
+/*		case 0x6123:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C110;
+			sd->sensor = SENSOR_SanyoCCD;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x612c:
+			sd->bridge = BRIDGE_SN9C110;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x612e:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C110;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x612f:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C110;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x6130:
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_base = 0x5d;
+			break;
+		case 0x6138:
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x613a:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x613b:
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_base = 0x21;
+			break;
+		case 0x613c:
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x613e:				* from BW600.inf
+			sd->bridge = BRIDGE_SN9C120;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_base = 0x??;
+			break; */
+		}
+		break;
+	}
+	if (sd->sensor < 0) {
+		PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
+			vendor, product);
+		return -EINVAL;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+
+	sd->qindex = 4;			/* set the quantization table */
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->autogain = AUTOGAIN_DEF;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/*	const __u8 *sn9c1xx; */
+	__u8 regF1;
+	__u8 regGpio[] = { 0x29, 0x74 };
+
+	/* setup a selector by bridge */
+	regF1 = 0x01;
+	reg_w(gspca_dev, 0xf1, &regF1, 1);
+	reg_r(gspca_dev, 0x00, 1);		/* -> regF1 = 0x00 */
+	regF1 = gspca_dev->usb_buf[0];
+	reg_w(gspca_dev, 0xf1, &regF1, 1);
+	reg_r(gspca_dev, 0x00, 1);
+	regF1 = gspca_dev->usb_buf[0];
+	switch (sd->bridge) {
+	case BRIDGE_SN9C102P:
+		if (regF1 != 0x11)
+			return -ENODEV;
+		reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+		break;
+	case BRIDGE_SN9C105:
+		if (regF1 != 0x11)
+			return -ENODEV;
+		reg_w(gspca_dev, 0x02, regGpio, 2);
+		break;
+	case BRIDGE_SN9C110:
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x62;
+		reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+		break;
+	case BRIDGE_SN9C120:
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x70;
+		reg_w(gspca_dev, 0x02, regGpio, 2);
+		break;
+	default:
+/*	case BRIDGE_SN9C325: */
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x62;
+		reg_w(gspca_dev, 0x02, &regGpio[1], 1);
+		break;
+	}
+
+	regF1 = 0x01;
+	reg_w(gspca_dev, 0xf1, &regF1, 1);
+
+	return 0;
+}
+
+static unsigned int setexposure(struct gspca_dev *gspca_dev,
+				unsigned int expo)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static const __u8 doit[] =		/* update sensor */
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+	static const __u8 sensorgo[] =		/* sensor on */
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+	static const __u8 gainMo[] =
+		{ 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R: {
+		__u8 Expodoit[] =
+			{ 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+		Expodoit[3] = expo >> 16;
+		Expodoit[4] = expo >> 8;
+		Expodoit[5] = expo;
+		i2c_w8(gspca_dev, Expodoit);
+		break;
+	    }
+	case SENSOR_MI0360: {
+		__u8 expoMi[] =	 /* exposure 0x0635 -> 4 fp/s 0x10 */
+			{ 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+
+		if (expo > 0x0635)
+			expo = 0x0635;
+		else if (expo < 0x0001)
+			expo = 0x0001;
+		expoMi[3] = expo >> 8;
+		expoMi[4] = expo;
+		i2c_w8(gspca_dev, expoMi);
+		i2c_w8(gspca_dev, doit);
+		i2c_w8(gspca_dev, sensorgo);
+		break;
+	    }
+	case SENSOR_MO4000: {
+		__u8 expoMof[] =
+			{ 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+		__u8 expoMo10[] =
+			{ 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+
+		if (expo > 0x1fff)
+			expo = 0x1fff;
+		else if (expo < 0x0001)
+			expo = 0x0001;
+		expoMof[3] = (expo & 0x03fc) >> 2;
+		i2c_w8(gspca_dev, expoMof);
+		expoMo10[3] = ((expo & 0x1c00) >> 10)
+				| ((expo & 0x0003) << 4);
+		i2c_w8(gspca_dev, expoMo10);
+		i2c_w8(gspca_dev, gainMo);
+		PDEBUG(D_CONF, "set exposure %d",
+			((expoMo10[3] & 0x07) << 10)
+			| (expoMof[3] << 2)
+			| ((expoMo10[3] & 0x30) >> 4));
+		break;
+	    }
+	}
+	return expo;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned int expo;
+	__u8 k2;
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		expo = sd->brightness << 4;
+		if (expo > 0x002dc6c0)
+			expo = 0x002dc6c0;
+		else if (expo < 0x02a0)
+			expo = 0x02a0;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_MI0360:
+		expo = sd->brightness >> 4;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_MO4000:
+		expo = sd->brightness >> 4;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_OV7660:
+		return;				/*jfm??*/
+	}
+
+	k2 = sd->brightness >> 10;
+	reg_w(gspca_dev, 0x96, &k2, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 k2;
+	__u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
+
+	if (sd->sensor == SENSOR_OV7660)
+		return;				/*jfm??*/
+	k2 = sd->contrast;
+	contrast[2] = k2;
+	contrast[0] = (k2 + 1) >> 1;
+	contrast[4] = (k2 + 1) / 5;
+	reg_w(gspca_dev, 0x84, contrast, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
+	int colour;
+
+	colour = sd->colors - 128;
+	if (colour > 0)
+		data = (colour + 32) & 0x7f;	/* blue */
+	else
+		data = (-colour + 32) & 0x7f;	/* red */
+	reg_w(gspca_dev, 0x05, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 data;
+	__u8 reg1;
+	__u8 reg17;
+	const __u8 *sn9c1xx;
+	int mode;
+	static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
+	static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+	static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+	static const __u8 CA_sn9c120[] =
+				 { 0x14, 0xec, 0x0a, 0xf6 };	/* SN9C120 */
+	static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
+	static const __u8 CE_sn9c325[] =
+			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7648 - SN9C325 */
+
+	sn9c1xx = sn_tb[(int) sd->sensor];
+	configure_gpio(gspca_dev, sn9c1xx);
+
+/*fixme:jfm this sequence should appear at end of sd_start */
+/* with
+	data = 0x44;
+	reg_w(gspca_dev, 0x01, &data, 1); */
+	reg_w(gspca_dev, 0x15, &sn9c1xx[0x15], 1);
+	reg_w(gspca_dev, 0x16, &sn9c1xx[0x16], 1);
+	reg_w(gspca_dev, 0x12, &sn9c1xx[0x12], 1);
+	reg_w(gspca_dev, 0x13, &sn9c1xx[0x13], 1);
+	reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
+	reg_w(gspca_dev, 0xd2, &DC29[0], 1);
+	reg_w(gspca_dev, 0xd3, &DC29[1], 1);
+	reg_w(gspca_dev, 0xc6, &DC29[2], 1);
+	reg_w(gspca_dev, 0xc7, &DC29[3], 1);
+	reg_w(gspca_dev, 0xc8, &DC29[4], 1);
+	reg_w(gspca_dev, 0xc9, &DC29[5], 1);
+/*fixme:jfm end of ending sequence */
+	reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1);
+	switch (sd->bridge) {
+	case BRIDGE_SN9C325:
+		data = 0xae;
+		break;
+	case BRIDGE_SN9C120:
+		data = 0xa0;
+		break;
+	default:
+		data = 0x60;
+		break;
+	}
+	reg_w(gspca_dev, 0x17, &data, 1);
+	reg_w(gspca_dev, 0x05, &sn9c1xx[5], 1);
+	reg_w(gspca_dev, 0x07, &sn9c1xx[7], 1);
+	reg_w(gspca_dev, 0x06, &sn9c1xx[6], 1);
+	reg_w(gspca_dev, 0x14, &sn9c1xx[0x14], 1);
+	switch (sd->bridge) {
+	case BRIDGE_SN9C325:
+		reg_w(gspca_dev, 0x20, regsn20_sn9c325,
+				sizeof regsn20_sn9c325);
+		for (i = 0; i < 8; i++)
+			reg_w(gspca_dev, 0x84, reg84_sn9c325,
+					sizeof reg84_sn9c325);
+		data = 0x0a;
+		reg_w(gspca_dev, 0x9a, &data, 1);
+		data = 0x60;
+		reg_w(gspca_dev, 0x99, &data, 1);
+		break;
+	case BRIDGE_SN9C120:
+		reg_w(gspca_dev, 0x20, regsn20_sn9c120,
+				sizeof regsn20_sn9c120);
+		for (i = 0; i < 2; i++)
+			reg_w(gspca_dev, 0x84, reg84_sn9c120_1,
+					sizeof reg84_sn9c120_1);
+		for (i = 0; i < 6; i++)
+			reg_w(gspca_dev, 0x84, reg84_sn9c120_2,
+					sizeof reg84_sn9c120_2);
+		reg_w(gspca_dev, 0x84, reg84_sn9c120_3,
+				sizeof reg84_sn9c120_3);
+		data = 0x05;
+		reg_w(gspca_dev, 0x9a, &data, 1);
+		data = 0x5b;
+		reg_w(gspca_dev, 0x99, &data, 1);
+		break;
+	default:
+		reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
+		for (i = 0; i < 8; i++)
+			reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+		data = 0x08;
+		reg_w(gspca_dev, 0x9a, &data, 1);
+		data = 0x59;
+		reg_w(gspca_dev, 0x99, &data, 1);
+		break;
+	}
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	reg1 = 0x02;
+	reg17 = 0x61;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		hv7131R_InitSensor(gspca_dev);
+		if (mode)
+			reg1 = 0x46;	/* 320 clk 48Mhz */
+		else
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		break;
+	case SENSOR_MI0360:
+		mi0360_InitSensor(gspca_dev);
+		if (mode)
+			reg1 = 0x46;	/* 320 clk 48Mhz */
+		else
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		break;
+	case SENSOR_MO4000:
+		mo4000_InitSensor(gspca_dev);
+		if (mode) {
+/*			reg1 = 0x46;	 * 320 clk 48Mhz 60fp/s */
+			reg1 = 0x06;	/* clk 24Mz */
+		} else {
+			reg17 = 0x22;	/* 640 MCKSIZE */
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		}
+		break;
+	case SENSOR_OV7648:
+		reg17 = 0xa2;
+		reg1 = 0x44;
+		ov7648_InitSensor(gspca_dev);
+/*		if (mode)
+			;		 * 320x2...
+		else
+			;		 * 640x... */
+		break;
+	default:
+/*	case SENSOR_OV7660: */
+		ov7660_InitSensor(gspca_dev);
+		if (mode) {
+/*			reg17 = 0x21;	 * 320 */
+/*			reg1 = 0x44; */
+			reg1 = 0x46;
+		} else {
+			reg17 = 0xa2;	/* 640 */
+			reg1 = 0x40;
+		}
+		break;
+	}
+	reg_w(gspca_dev, 0xc0, C0, 6);
+	switch (sd->bridge) {
+	case BRIDGE_SN9C120:			/*jfm ?? */
+		reg_w(gspca_dev, 0xca, CA_sn9c120, 4);
+		break;
+	default:
+		reg_w(gspca_dev, 0xca, CA, 4);
+		break;
+	}
+	switch (sd->bridge) {
+	case BRIDGE_SN9C120:			/*jfm ?? */
+	case BRIDGE_SN9C325:
+		reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+		break;
+	default:
+		reg_w(gspca_dev, 0xce, CE, 4);
+					/* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
+		break;
+	}
+
+	/* here change size mode 0 -> VGA; 1 -> CIF */
+	data = 0x40 | sn9c1xx[0x18] | (mode << 4);
+	reg_w(gspca_dev, 0x18, &data, 1);
+
+	reg_w(gspca_dev, 0x100, qtable4, 0x40);
+	reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
+
+	data = sn9c1xx[0x18] | (mode << 4);
+	reg_w(gspca_dev, 0x18, &data, 1);
+
+	reg_w(gspca_dev, 0x17, &reg17, 1);
+	reg_w(gspca_dev, 0x01, &reg1, 1);
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static const __u8 stophv7131[] =
+		{ 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+	static const __u8 stopmi0360[] =
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+	__u8 regF1;
+	__u8 data;
+	const __u8 *sn9c1xx;
+
+	data = 0x0b;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		i2c_w8(gspca_dev, stophv7131);
+		data = 0x2b;
+		break;
+	case SENSOR_MI0360:
+		i2c_w8(gspca_dev, stopmi0360);
+		data = 0x29;
+		break;
+	case SENSOR_MO4000:
+		break;
+	case SENSOR_OV7648:
+		data = 0x29;
+		break;
+	default:
+/*	case SENSOR_OV7660: */
+		break;
+	}
+	sn9c1xx = sn_tb[(int) sd->sensor];
+	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
+	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 1);
+	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1);
+	reg_w(gspca_dev, 0x01, &data, 1);
+	regF1 = 0x01;
+	reg_w(gspca_dev, 0xf1, &regF1, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	/* Thanks S., without your advice, autobright should not work :) */
+	int delta;
+	int expotimes = 0;
+	__u8 luma_mean = 130;
+	__u8 luma_delta = 20;
+
+	delta = sd->avg_lum;
+	if (delta < luma_mean - luma_delta ||
+	    delta > luma_mean + luma_delta) {
+		switch (sd->sensor) {
+		case SENSOR_HV7131R:
+			expotimes = sd->exposure >> 8;
+			expotimes += (luma_mean - delta) >> 4;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+					(unsigned int) (expotimes << 8));
+			break;
+		case SENSOR_MO4000:
+		case SENSOR_MI0360:
+			expotimes = sd->exposure;
+			expotimes += (luma_mean - delta) >> 6;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+						   (unsigned int) expotimes);
+			setcolors(gspca_dev);
+			break;
+		}
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int sof, avg_lum;
+
+	sof = len - 64;
+	if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+
+		/* end of frame */
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				frame, data, sof + 2);
+		if (sd->ag_cnt < 0)
+			return;
+		if (--sd->ag_cnt >= 0)
+			return;
+		sd->ag_cnt = AG_CNT_START;
+/* w1 w2 w3 */
+/* w4 w5 w6 */
+/* w7 w8 */
+/* w4 */
+		avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+/* w6 */
+		avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+/* w2 */
+		avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+/* w8 */
+		avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+/* w5 */
+		avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+		avg_lum >>= 4;
+		sd->avg_lum = avg_lum;
+		PDEBUG(D_PACK, "mean lum %d", avg_lum);
+		setautogain(gspca_dev);
+		return;
+	}
+	if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+		/* put the JPEG 422 header */
+		jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static unsigned int getexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 hexpo, mexpo, lexpo;
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x25);
+		return (gspca_dev->usb_buf[0] << 16)
+			| (gspca_dev->usb_buf[1] << 8)
+			| gspca_dev->usb_buf[2];
+	case SENSOR_MI0360:
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x09);
+		return (gspca_dev->usb_buf[0] << 8)
+			| gspca_dev->usb_buf[1];
+	case SENSOR_MO4000:
+		i2c_r5(gspca_dev, 0x0e);
+		hexpo = 0;		/* gspca_dev->usb_buf[1] & 0x07; */
+		mexpo = 0x40;		/* gspca_dev->usb_buf[2] & 0xff; */
+		lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
+		PDEBUG(D_CONF, "exposure %d",
+			(hexpo << 10) | (mexpo << 2) | lexpo);
+		return (hexpo << 10) | (mexpo << 2) | lexpo;
+	default:
+/*	case SENSOR_OV7660: */
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x04);
+		hexpo = gspca_dev->usb_buf[3] & 0x2f;
+		lexpo = gspca_dev->usb_buf[0] & 0x02;
+		i2c_r5(gspca_dev, 0x08);
+		mexpo = gspca_dev->usb_buf[2];
+		return (hexpo << 10) | (mexpo << 2) | lexpo;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* hardcoded registers seem not readable */
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+/*		sd->brightness = 0x7fff; */
+		sd->brightness = getexposure(gspca_dev) >> 4;
+		break;
+	case SENSOR_MI0360:
+		sd->brightness = getexposure(gspca_dev) << 4;
+		break;
+	case SENSOR_MO4000:
+/*		sd->brightness = 0x1fff; */
+		sd->brightness = getexposure(gspca_dev) << 4;
+		break;
+	}
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+	{USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
+	{USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
+	{USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
+	{USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
+	{USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
+#endif
+	{USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
+	{USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
+	{USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
+	{USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
+	{USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
+	{USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
+	{USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
+	{USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
+	{USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
+#ifndef CONFIG_USB_SN9C102
+	{USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
+	{USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
+	{USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
+	{USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
+#endif
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	info("v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
new file mode 100644
index 0000000..1562061
--- /dev/null
+++ b/drivers/media/video/gspca/spca500.c
@@ -0,0 +1,1216 @@
+/*
+ * SPCA500 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ *
+ */
+
+#define MODULE_NAME "spca500"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	__u8 packet[ISO_MAX_SIZE + 128];
+				 /* !! no more than 128 ff in an ISO packet */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+
+	char qindex;
+	char subtype;
+#define AgfaCl20 0
+#define AiptekPocketDV 1
+#define BenqDC1016 2
+#define CreativePCCam300 3
+#define DLinkDSC350 4
+#define Gsmartmini 5
+#define IntelPocketPCCamera 6
+#define KodakEZ200 7
+#define LogitechClickSmart310 8
+#define LogitechClickSmart510 9
+#define LogitechTraveler 10
+#define MustekGsmart300 11
+#define Optimedia 12
+#define PalmPixDC85 13
+#define ToptroIndus 14
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 127
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 63,
+		.step    = 1,
+#define CONTRAST_DEF 31
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 63,
+		.step    = 1,
+#define COLOR_DEF 31
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* Frame packet header offsets for the spca500 */
+#define SPCA500_OFFSET_PADDINGLB 2
+#define SPCA500_OFFSET_PADDINGHB 3
+#define SPCA500_OFFSET_MODE      4
+#define SPCA500_OFFSET_IMGWIDTH  5
+#define SPCA500_OFFSET_IMGHEIGHT 6
+#define SPCA500_OFFSET_IMGMODE   7
+#define SPCA500_OFFSET_QTBLINDEX 8
+#define SPCA500_OFFSET_FRAMSEQ   9
+#define SPCA500_OFFSET_CDSPINFO  10
+#define SPCA500_OFFSET_GPIO      11
+#define SPCA500_OFFSET_AUGPIO    12
+#define SPCA500_OFFSET_DATA      16
+
+
+static const __u16 spca500_visual_defaults[][3] = {
+	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
+				 * hue (H byte) = 0,
+				 * saturation/hue enable,
+				 * brightness/contrast enable.
+				 */
+	{0x00, 0x0000, 0x8167},	/* brightness = 0 */
+	{0x00, 0x0020, 0x8168},	/* contrast = 0 */
+	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
+				 * hue (H byte) = 0, saturation/hue enable,
+				 * brightness/contrast enable.
+				 * was 0x0003, now 0x0000.
+				 */
+	{0x00, 0x0000, 0x816a},	/* hue (L byte) = 0 */
+	{0x00, 0x0020, 0x8169},	/* saturation = 0x20 */
+	{0x00, 0x0050, 0x8157},	/* edge gain high threshold */
+	{0x00, 0x0030, 0x8158},	/* edge gain low threshold */
+	{0x00, 0x0028, 0x8159},	/* edge bandwidth high threshold */
+	{0x00, 0x000a, 0x815a},	/* edge bandwidth low threshold */
+	{0x00, 0x0001, 0x8202},	/* clock rate compensation = 1/25 sec/frame */
+	{0x0c, 0x0004, 0x0000},
+	/* set interface */
+	{}
+};
+static const __u16 Clicksmart510_defaults[][3] = {
+	{0x00, 0x00, 0x8211},
+	{0x00, 0x01, 0x82c0},
+	{0x00, 0x10, 0x82cb},
+	{0x00, 0x0f, 0x800d},
+	{0x00, 0x82, 0x8225},
+	{0x00, 0x21, 0x8228},
+	{0x00, 0x00, 0x8203},
+	{0x00, 0x00, 0x8204},
+	{0x00, 0x08, 0x8205},
+	{0x00, 0xf8, 0x8206},
+	{0x00, 0x28, 0x8207},
+	{0x00, 0xa0, 0x8208},
+	{0x00, 0x08, 0x824a},
+	{0x00, 0x08, 0x8214},
+	{0x00, 0x80, 0x82c1},
+	{0x00, 0x00, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0x80, 0x82c1},
+	{0x00, 0x04, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0xfc, 0x8100},
+	{0x00, 0xfc, 0x8105},
+	{0x00, 0x30, 0x8101},
+	{0x00, 0x00, 0x8102},
+	{0x00, 0x00, 0x8103},
+	{0x00, 0x66, 0x8107},
+	{0x00, 0x00, 0x816b},
+	{0x00, 0x00, 0x8155},
+	{0x00, 0x01, 0x8156},
+	{0x00, 0x60, 0x8157},
+	{0x00, 0x40, 0x8158},
+	{0x00, 0x0a, 0x8159},
+	{0x00, 0x06, 0x815a},
+	{0x00, 0x00, 0x813f},
+	{0x00, 0x00, 0x8200},
+	{0x00, 0x19, 0x8201},
+	{0x00, 0x00, 0x82c1},
+	{0x00, 0xa0, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0x00, 0x8117},
+	{0x00, 0x00, 0x8118},
+	{0x00, 0x65, 0x8119},
+	{0x00, 0x00, 0x811a},
+	{0x00, 0x00, 0x811b},
+	{0x00, 0x55, 0x811c},
+	{0x00, 0x65, 0x811d},
+	{0x00, 0x55, 0x811e},
+	{0x00, 0x16, 0x811f},
+	{0x00, 0x19, 0x8120},
+	{0x00, 0x80, 0x8103},
+	{0x00, 0x83, 0x816b},
+	{0x00, 0x25, 0x8168},
+	{0x00, 0x01, 0x820f},
+	{0x00, 0xff, 0x8115},
+	{0x00, 0x48, 0x8116},
+	{0x00, 0x50, 0x8151},
+	{0x00, 0x40, 0x8152},
+	{0x00, 0x78, 0x8153},
+	{0x00, 0x40, 0x8154},
+	{0x00, 0x00, 0x8167},
+	{0x00, 0x20, 0x8168},
+	{0x00, 0x00, 0x816a},
+	{0x00, 0x03, 0x816b},
+	{0x00, 0x20, 0x8169},
+	{0x00, 0x60, 0x8157},
+	{0x00, 0x00, 0x8190},
+	{0x00, 0x00, 0x81a1},
+	{0x00, 0x00, 0x81b2},
+	{0x00, 0x27, 0x8191},
+	{0x00, 0x27, 0x81a2},
+	{0x00, 0x27, 0x81b3},
+	{0x00, 0x4b, 0x8192},
+	{0x00, 0x4b, 0x81a3},
+	{0x00, 0x4b, 0x81b4},
+	{0x00, 0x66, 0x8193},
+	{0x00, 0x66, 0x81a4},
+	{0x00, 0x66, 0x81b5},
+	{0x00, 0x79, 0x8194},
+	{0x00, 0x79, 0x81a5},
+	{0x00, 0x79, 0x81b6},
+	{0x00, 0x8a, 0x8195},
+	{0x00, 0x8a, 0x81a6},
+	{0x00, 0x8a, 0x81b7},
+	{0x00, 0x9b, 0x8196},
+	{0x00, 0x9b, 0x81a7},
+	{0x00, 0x9b, 0x81b8},
+	{0x00, 0xa6, 0x8197},
+	{0x00, 0xa6, 0x81a8},
+	{0x00, 0xa6, 0x81b9},
+	{0x00, 0xb2, 0x8198},
+	{0x00, 0xb2, 0x81a9},
+	{0x00, 0xb2, 0x81ba},
+	{0x00, 0xbe, 0x8199},
+	{0x00, 0xbe, 0x81aa},
+	{0x00, 0xbe, 0x81bb},
+	{0x00, 0xc8, 0x819a},
+	{0x00, 0xc8, 0x81ab},
+	{0x00, 0xc8, 0x81bc},
+	{0x00, 0xd2, 0x819b},
+	{0x00, 0xd2, 0x81ac},
+	{0x00, 0xd2, 0x81bd},
+	{0x00, 0xdb, 0x819c},
+	{0x00, 0xdb, 0x81ad},
+	{0x00, 0xdb, 0x81be},
+	{0x00, 0xe4, 0x819d},
+	{0x00, 0xe4, 0x81ae},
+	{0x00, 0xe4, 0x81bf},
+	{0x00, 0xed, 0x819e},
+	{0x00, 0xed, 0x81af},
+	{0x00, 0xed, 0x81c0},
+	{0x00, 0xf7, 0x819f},
+	{0x00, 0xf7, 0x81b0},
+	{0x00, 0xf7, 0x81c1},
+	{0x00, 0xff, 0x81a0},
+	{0x00, 0xff, 0x81b1},
+	{0x00, 0xff, 0x81c2},
+	{0x00, 0x03, 0x8156},
+	{0x00, 0x00, 0x8211},
+	{0x00, 0x20, 0x8168},
+	{0x00, 0x01, 0x8202},
+	{0x00, 0x30, 0x8101},
+	{0x00, 0x00, 0x8111},
+	{0x00, 0x00, 0x8112},
+	{0x00, 0x00, 0x8113},
+	{0x00, 0x00, 0x8114},
+	{}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static const __u8 qtable_kodak_ez200[2][64] = {
+	{				/* Q-table Y-components */
+	 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
+	 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
+	 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
+	 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
+	 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
+	 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
+	 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
+	 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
+	{				/* Q-table C-components */
+	 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
+};
+
+static const __u8 qtable_pocketdv[2][64] = {
+	{		/* Q-table Y-components start registers 0x8800 */
+	 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
+	 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
+	 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
+	 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
+	 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
+	 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
+	 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
+	 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
+	 },
+	{		/* Q-table C-components start registers 0x8840 */
+	 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
+	 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
+	 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
+};
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index,
+		  __u16 length)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, gspca_dev->usb_buf, length, 500);
+}
+
+static int reg_w(struct gspca_dev *gspca_dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value);
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_r_12(struct gspca_dev *gspca_dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+
+	gspca_dev->usb_buf[1] = 0;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			gspca_dev->usb_buf, length,
+			500);		/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r_12 err %d", ret);
+		return -1;
+	}
+	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+/*
+ * Simple function to wait for a given 8-bit value to be returned from
+ * a reg_read call.
+ * Returns: negative is error or timeout, zero is success.
+ */
+static int reg_r_wait(struct gspca_dev *gspca_dev,
+			__u16 reg, __u16 index, __u16 value)
+{
+	int ret, cnt = 20;
+
+	while (--cnt > 0) {
+		ret = reg_r_12(gspca_dev, reg, index, 1);
+		if (ret == value)
+			return 0;
+		msleep(50);
+	}
+	return -EIO;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][3])
+{
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+	return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+				unsigned int request,
+				unsigned int ybase,
+				unsigned int cbase,
+				const __u8 qtable[2][64])
+{
+	int i, err;
+
+	/* loop over y components */
+	for (i = 0; i < 64; i++) {
+		err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);
+		if (err < 0)
+			return err;
+	}
+
+	/* loop over c components */
+	for (i = 0; i < 64; i++) {
+		err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static void spca500_ping310(struct gspca_dev *gspca_dev)
+{
+	reg_r(gspca_dev, 0x0d04, 2);
+	PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
+		gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+}
+
+static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
+{
+	reg_r(gspca_dev, 0x0d05, 2);
+	PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x",
+		gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+	reg_w(gspca_dev, 0x00, 0x8167, 0x5a);
+	spca500_ping310(gspca_dev);
+
+	reg_w(gspca_dev, 0x00, 0x8168, 0x22);
+	reg_w(gspca_dev, 0x00, 0x816a, 0xc0);
+	reg_w(gspca_dev, 0x00, 0x816b, 0x0b);
+	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
+	reg_w(gspca_dev, 0x00, 0x8157, 0x5b);
+	reg_w(gspca_dev, 0x00, 0x8158, 0x5b);
+	reg_w(gspca_dev, 0x00, 0x813f, 0x03);
+	reg_w(gspca_dev, 0x00, 0x8151, 0x4a);
+	reg_w(gspca_dev, 0x00, 0x8153, 0x78);
+	reg_w(gspca_dev, 0x00, 0x0d01, 0x04);
+						/* 00 for adjust shutter */
+	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
+	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
+	reg_w(gspca_dev, 0x00, 0x0d01, 0x02);
+}
+
+static void spca500_setmode(struct gspca_dev *gspca_dev,
+			__u8 xmult, __u8 ymult)
+{
+	int mode;
+
+	/* set x multiplier */
+	reg_w(gspca_dev, 0, 0x8001, xmult);
+
+	/* set y multiplier */
+	reg_w(gspca_dev, 0, 0x8002, ymult);
+
+	/* use compressed mode, VGA, with mode specific subsample */
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	reg_w(gspca_dev, 0, 0x8003, mode << 4);
+}
+
+static int spca500_full_reset(struct gspca_dev *gspca_dev)
+{
+	int err;
+
+	/* send the reset command */
+	err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);
+	if (err < 0)
+		return err;
+
+	/* wait for the reset to complete */
+	err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);
+	if (err < 0)
+		return err;
+	err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);
+	if (err < 0)
+		return err;
+	err = reg_r_wait(gspca_dev, 0x06, 0, 0);
+	if (err < 0) {
+		PDEBUG(D_ERR, "reg_r_wait() failed");
+		return err;
+	}
+	/* all ok */
+	return 0;
+}
+
+/* Synchro the Bridge with sensor */
+/* Maybe that will work on all spca500 chip */
+/* because i only own a clicksmart310 try for that chip */
+/* using spca50x_set_packet_size() cause an Ooops here */
+/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
+/* up-port the same feature as in 2.4.x kernel */
+static int spca500_synch310(struct gspca_dev *gspca_dev)
+{
+	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
+		PDEBUG(D_ERR, "Set packet size: set interface error");
+		goto error;
+	}
+	spca500_ping310(gspca_dev);
+
+	reg_r(gspca_dev, 0x0d00, 1);
+
+	/* need alt setting here */
+	PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
+
+	/* Windoze use pipe with altsetting 6 why 7 here */
+	if (usb_set_interface(gspca_dev->dev,
+				gspca_dev->iface,
+				gspca_dev->alt) < 0) {
+		PDEBUG(D_ERR, "Set packet size: set interface error");
+		goto error;
+	}
+	return 0;
+error:
+	return -EBUSY;
+}
+
+static void spca500_reinit(struct gspca_dev *gspca_dev)
+{
+	int err;
+	__u8 Data;
+
+	/* some unknow command from Aiptek pocket dv and family300 */
+
+	reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
+	reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
+	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
+
+	/* enable drop packet */
+	reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+	err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
+				 qtable_pocketdv);
+	if (err < 0)
+		PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+
+	/* set qtable index */
+	reg_w(gspca_dev, 0x00, 0x8880, 2);
+	/* family cam Quicksmart stuff */
+	reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+	/* Set agc transfer: synced inbetween frames */
+	reg_w(gspca_dev, 0x00, 0x820f, 0x01);
+	/* Init SDRAM - needed for SDRAM access */
+	reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+	/*Start init sequence or stream */
+	reg_w(gspca_dev, 0, 0x8003, 0x00);
+	/* switch to video camera mode */
+	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+	msleep(2000);
+	if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x040a:		/* Kodak cameras */
+/*		switch (product) { */
+/*		case 0x0300: */
+			sd->subtype = KodakEZ200;
+/*			break; */
+/*		} */
+		break;
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x400a: */
+			sd->subtype = CreativePCCam300;
+/*			break; */
+/*		} */
+		break;
+	case 0x046d:		/* Logitech Labtec */
+		switch (product) {
+		case 0x0890:
+			sd->subtype = LogitechTraveler;
+			break;
+		case 0x0900:
+			sd->subtype = LogitechClickSmart310;
+			break;
+		case 0x0901:
+			sd->subtype = LogitechClickSmart510;
+			break;
+		}
+		break;
+	case 0x04a5:		/* Benq */
+/*		switch (product) { */
+/*		case 0x300c: */
+			sd->subtype = BenqDC1016;
+/*			break; */
+/*		} */
+		break;
+	case 0x04fc:		/* SunPlus */
+/*		switch (product) { */
+/*		case 0x7333: */
+			sd->subtype = PalmPixDC85;
+/*			break; */
+/*		} */
+		break;
+	case 0x055f:		/* Mustek cameras */
+		switch (product) {
+		case 0xc200:
+			sd->subtype = MustekGsmart300;
+			break;
+		case 0xc220:
+			sd->subtype = Gsmartmini;
+			break;
+		}
+		break;
+	case 0x06bd:		/* Agfa Cl20 */
+/*		switch (product) { */
+/*		case 0x0404: */
+			sd->subtype = AgfaCl20;
+/*			break; */
+/*		} */
+		break;
+	case 0x06be:		/* Optimedia */
+/*		switch (product) { */
+/*		case 0x0800: */
+			sd->subtype = Optimedia;
+/*			break; */
+/*		} */
+		break;
+	case 0x084d:		/* D-Link / Minton */
+/*		switch (product) { */
+/*		case 0x0003:	 * DSC-350 / S-Cam F5 */
+			sd->subtype = DLinkDSC350;
+/*			break; */
+/*		} */
+		break;
+	case 0x08ca:		/* Aiptek */
+/*		switch (product) { */
+/*		case 0x0103: */
+			sd->subtype = AiptekPocketDV;
+/*			break; */
+/*		} */
+		break;
+	case 0x2899:		/* ToptroIndustrial */
+/*		switch (product) { */
+/*		case 0x012c: */
+			sd->subtype = ToptroIndus;
+/*			break; */
+/*		} */
+		break;
+	case 0x8086:		/* Intel */
+/*		switch (product) { */
+/*		case 0x0630:	 * Pocket PC Camera */
+			sd->subtype = IntelPocketPCCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	if (sd->subtype != LogitechClickSmart310) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	}
+	sd->qindex = 5;
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* initialisation of spca500 based cameras is deferred */
+	PDEBUG(D_STREAM, "SPCA500 init");
+	if (sd->subtype == LogitechClickSmart310)
+		spca500_clksmart310_init(gspca_dev);
+/*	else
+		spca500_initialise(gspca_dev); */
+	PDEBUG(D_STREAM, "SPCA500 init done");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int err;
+	__u8 Data;
+	__u8 xmult, ymult;
+
+	if (sd->subtype == LogitechClickSmart310) {
+		xmult = 0x16;
+		ymult = 0x12;
+	} else {
+		xmult = 0x28;
+		ymult = 0x1e;
+	}
+
+	/* is there a sensor here ? */
+	reg_r(gspca_dev, 0x8a04, 1);
+	PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x",
+		gspca_dev->usb_buf[0]);
+	PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",
+		gspca_dev->curr_mode, xmult, ymult);
+
+	/* setup qtable */
+	switch (sd->subtype) {
+	case LogitechClickSmart310:
+		 spca500_setmode(gspca_dev, xmult, ymult);
+
+		/* enable drop packet */
+		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+		reg_w(gspca_dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		/* Init SDRAM - needed for SDRAM access */
+		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+		msleep(500);
+		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_r_wait() failed");
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+		spca500_synch310(gspca_dev);
+
+		write_vector(gspca_dev, spca500_visual_defaults);
+		spca500_setmode(gspca_dev, xmult, ymult);
+		/* enable drop packet */
+		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+			PDEBUG(D_ERR, "failed to enable drop packet");
+		reg_w(gspca_dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+		/* Init SDRAM - needed for SDRAM access */
+		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_r_wait() failed");
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+		break;
+	case CreativePCCam300:		/* Creative PC-CAM 300 640x480 CCD */
+	case IntelPocketPCCamera:	/* FIXME: Temporary fix for
+					 *	Intel Pocket PC Camera
+					 *	- NWG (Sat 29th March 2003) */
+
+		/* do a full reset */
+		err = spca500_full_reset(gspca_dev);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca500_full_reset failed");
+
+		/* enable drop packet */
+		err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+		if (err < 0)
+			PDEBUG(D_ERR, "failed to enable drop packet");
+		reg_w(gspca_dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+		spca500_setmode(gspca_dev, xmult, ymult);
+		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
+
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_r_wait() failed");
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+/*		write_vector(gspca_dev, spca500_visual_defaults); */
+		break;
+	case KodakEZ200:		/* Kodak EZ200 */
+
+		/* do a full reset */
+		err = spca500_full_reset(gspca_dev);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca500_full_reset failed");
+		/* enable drop packet */
+		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+		reg_w(gspca_dev, 0x00, 0x8880, 0);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_kodak_ez200);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		spca500_setmode(gspca_dev, xmult, ymult);
+
+		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
+
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_r_wait() failed");
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+
+/*		write_vector(gspca_dev, spca500_visual_defaults); */
+		break;
+
+	case BenqDC1016:
+	case DLinkDSC350:		/* FamilyCam 300 */
+	case AiptekPocketDV:		/* Aiptek PocketDV */
+	case Gsmartmini:		/*Mustek Gsmart Mini */
+	case MustekGsmart300:		/* Mustek Gsmart 300 */
+	case PalmPixDC85:
+	case Optimedia:
+	case ToptroIndus:
+	case AgfaCl20:
+		spca500_reinit(gspca_dev);
+		reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
+		/* enable drop packet */
+		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+		err = spca50x_setup_qtable(gspca_dev,
+				   0x00, 0x8800, 0x8840, qtable_pocketdv);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		reg_w(gspca_dev, 0x00, 0x8880, 2);
+
+		/* familycam Quicksmart pocketDV stuff */
+		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+		/* Set agc transfer: synced inbetween frames */
+		reg_w(gspca_dev, 0x00, 0x820f, 0x01);
+		/* Init SDRAM - needed for SDRAM access */
+		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+		spca500_setmode(gspca_dev, xmult, ymult);
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+
+		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+		break;
+	case LogitechTraveler:
+	case LogitechClickSmart510:
+		reg_w(gspca_dev, 0x02, 0x00, 0x00);
+		/* enable drop packet */
+		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
+
+		err = spca50x_setup_qtable(gspca_dev,
+					0x00, 0x8800,
+					0x8840, qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		reg_w(gspca_dev, 0x00, 0x8880, 3);
+		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
+		/* Init SDRAM - needed for SDRAM access */
+		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
+
+		spca500_setmode(gspca_dev, xmult, ymult);
+
+		/* switch to video camera mode */
+		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
+
+		reg_r(gspca_dev, 0x816b, 1);
+		Data = gspca_dev->usb_buf[0];
+		reg_w(gspca_dev, 0x00, 0x816b, Data);
+		write_vector(gspca_dev, Clicksmart510_defaults);
+		break;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0, 0x8003, 0x00);
+
+	/* switch to video camera mode */
+	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
+	reg_r(gspca_dev, 0x8000, 1);
+	PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x",
+		gspca_dev->usb_buf[0]);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 *s, *d;
+	static __u8 ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+	if (data[0] == 0xff) {
+		if (data[1] != 0x01) {	/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		}
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
+
+		data += SPCA500_OFFSET_DATA;
+		len -= SPCA500_OFFSET_DATA;
+	} else {
+		data += 1;
+		len -= 1;
+	}
+
+	/* add 0x00 after 0xff */
+	for (i = len; --i >= 0; )
+		if (data[i] == 0xff)
+			break;
+	if (i < 0) {			/* no 0xff */
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		return;
+	}
+	s = data;
+	d = sd->packet;
+	for (i = 0; i < len; i++) {
+		*d++ = *s++;
+		if (s[-1] == 0xff)
+			*d++ = 0x00;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0x00, 0x8167,
+			(__u8) (sd->brightness - 128));
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_r_12(gspca_dev, 0x00, 0x8167, 1);
+	if (ret >= 0)
+		sd->brightness = ret + 128;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_r_12(gspca_dev, 0x0, 0x8168, 1);
+	if (ret >= 0)
+		sd->contrast = ret;
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0x00, 0x8169, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	ret = reg_r_12(gspca_dev, 0x0, 0x8169, 1);
+	if (ret >= 0)
+		sd->colors = ret;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")},
+	{USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")},
+	{USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")},
+	{USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")},
+	{USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")},
+	{USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")},
+	{USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")},
+	{USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")},
+	{USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")},
+	{USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")},
+	{USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")},
+	{USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")},
+	{USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")},
+	{USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")},
+	{USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
new file mode 100644
index 0000000..50e929d
--- /dev/null
+++ b/drivers/media/video/gspca/spca501.c
@@ -0,0 +1,2229 @@
+/*
+ * SPCA501 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ *
+ */
+
+#define MODULE_NAME "spca501"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned short contrast;
+	__u8 brightness;
+	__u8 colors;
+
+	char subtype;
+#define Arowana300KCMOSCamera 0
+#define IntelCreateAndShare 1
+#define KodakDVC325 2
+#define MystFromOriUnknownCamera 3
+#define SmileIntlCamera 4
+#define ThreeComHomeConnectLite 5
+#define ViewQuestM318B 6
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define MY_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 127,
+		.step    = 1,
+		.default_value = 63,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define MY_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xffff,
+		.step    = 1,
+		.default_value = 0xaa00,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define MY_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 63,
+		.step    = 1,
+		.default_value = 31,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 3 / 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+#define SPCA50X_REG_USB 0x2	/* spca505 501 */
+/*
+ * Data to initialize a SPCA501. From a capture file provided by Bill Roehl
+ * With SPCA501 chip description
+ */
+#define CCDSP_SET		/* set CCDSP parameters */
+#define TG_SET			/* set time generator set */
+#undef DSPWIN_SET		/* set DSP windows parameters */
+#undef ALTER_GAMA	/* Set alternate set to YUV transform coeffs. */
+#define SPCA501_SNAPBIT 0x80
+#define SPCA501_SNAPCTRL 0x10
+/* Frame packet header offsets for the spca501 */
+#define SPCA501_OFFSET_GPIO   1
+#define SPCA501_OFFSET_TYPE   2
+#define SPCA501_OFFSET_TURN3A 3
+#define SPCA501_OFFSET_FRAMSEQ 4
+#define SPCA501_OFFSET_COMPRESS 5
+#define SPCA501_OFFSET_QUANT 6
+#define SPCA501_OFFSET_QUANT2 7
+#define SPCA501_OFFSET_DATA 8
+
+#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1)
+#define SPCA501_PROP_SNAP(d) ((d) & 0x40)
+#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10)
+#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1)
+#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4)
+
+/* SPCA501 CCDSP control */
+#define SPCA501_REG_CCDSP 0x01
+/* SPCA501 control/status registers */
+#define SPCA501_REG_CTLRL 0x02
+
+/* registers for color correction and YUV transformation */
+#define SPCA501_A11 0x08
+#define SPCA501_A12 0x09
+#define SPCA501_A13 0x0A
+#define SPCA501_A21 0x0B
+#define SPCA501_A22 0x0C
+#define SPCA501_A23 0x0D
+#define SPCA501_A31 0x0E
+#define SPCA501_A32 0x0F
+#define SPCA501_A33 0x10
+
+/* Data for video camera initialization before capturing */
+static const __u16 spca501_open_data[][3] = {
+	/* bmRequest,value,index */
+
+	{0x2, 0x50, 0x00},	/* C/S enable soft reset */
+	{0x2, 0x40, 0x00},	/* C/S disable soft reset */
+	{0x2, 0x02, 0x05},	/* C/S general purpose I/O data */
+	{0x2, 0x03, 0x05},	/* C/S general purpose I/O data */
+
+#ifdef CCDSP_SET
+	{0x1, 0x38, 0x01},	/* CCDSP options */
+	{0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */
+	{0x1, 0xC0, 0x03},	/* CCDSP Optical black settings */
+
+	{0x1, 0x67, 0x07},
+	{0x1, 0x63, 0x3f},	/* CCDSP CCD gamma enable */
+	{0x1, 0x03, 0x56},	/* Add gamma correction */
+
+	{0x1, 0xFF, 0x15},	/* CCDSP High luminance for white balance */
+	{0x1, 0x01, 0x16},	/* CCDSP Low luminance for white balance */
+
+/* Color correction and RGB-to-YUV transformation coefficients changing */
+#ifdef ALTER_GAMA
+	{0x0, 0x00, 0x08},	/* A11 */
+	{0x0, 0x00, 0x09},	/* A12 */
+	{0x0, 0x90, 0x0A},	/* A13 */
+	{0x0, 0x12, 0x0B},	/* A21 */
+	{0x0, 0x00, 0x0C},	/* A22 */
+	{0x0, 0x00, 0x0D},	/* A23 */
+	{0x0, 0x00, 0x0E},	/* A31 */
+	{0x0, 0x02, 0x0F},	/* A32 */
+	{0x0, 0x00, 0x10},	/* A33 */
+#else
+	{0x1, 0x2a, 0x08},	/* A11 0x31 */
+	{0x1, 0xf8, 0x09},	/* A12 f8 */
+	{0x1, 0xf8, 0x0A},	/* A13 f8 */
+	{0x1, 0xf8, 0x0B},	/* A21 f8 */
+	{0x1, 0x14, 0x0C},	/* A22 0x14 */
+	{0x1, 0xf8, 0x0D},	/* A23 f8 */
+	{0x1, 0xf8, 0x0E},	/* A31 f8 */
+	{0x1, 0xf8, 0x0F},	/* A32 f8 */
+	{0x1, 0x20, 0x10},	/* A33 0x20 */
+#endif
+	{0x1, 0x00, 0x11},	/* R offset */
+	{0x1, 0x00, 0x12},	/* G offset */
+	{0x1, 0x00, 0x13},	/* B offset */
+	{0x1, 0x00, 0x14},	/* GB offset */
+
+#endif
+
+#ifdef TG_SET
+	/* Time generator manipulations */
+	{0x0, 0xfc, 0x0},	/* Set up high bits of shutter speed */
+	{0x0, 0x01, 0x1},	/* Set up low bits of shutter speed */
+
+	{0x0, 0xe4, 0x04},	/* DCLK*2 clock phase adjustment */
+	{0x0, 0x08, 0x05},	/* ADCK phase adjustment, inv. ext. VB */
+	{0x0, 0x03, 0x06},	/* FR phase adjustment */
+	{0x0, 0x01, 0x07},	/* FCDS phase adjustment */
+	{0x0, 0x39, 0x08},	/* FS phase adjustment */
+	{0x0, 0x88, 0x0a},	/* FH1 phase and delay adjustment */
+	{0x0, 0x03, 0x0f},	/* pixel identification */
+	{0x0, 0x00, 0x11},	/* clock source selection (default) */
+
+	/*VERY strange manipulations with
+	 * select DMCLP or OBPX to be ADCLP output (0x0C)
+	 * OPB always toggle or not (0x0D) but they allow
+	 * us to set up brightness
+	 */
+	{0x0, 0x01, 0x0c},
+	{0x0, 0xe0, 0x0d},
+	/* Done */
+#endif
+
+#ifdef DSPWIN_SET
+	{0x1, 0xa0, 0x01},	/* Setting image processing parameters */
+	{0x1, 0x1c, 0x17},	/* Changing Windows positions X1 */
+	{0x1, 0xe2, 0x19},	/* X2 */
+	{0x1, 0x1c, 0x1b},	/* X3 */
+	{0x1, 0xe2, 0x1d},	/* X4 */
+	{0x1, 0x5f, 0x1f},	/* X5 */
+	{0x1, 0x32, 0x20},	/* Y5 */
+	{0x1, 0x01, 0x10},	/* Changing A33 */
+#endif
+
+	{0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */
+	{0x2, 0x94, 0x06},	/* Setting video no compression */
+	{}
+};
+
+/*
+   The SPCAxxx docs from Sunplus document these values
+   in tables, one table per register number.  In the data
+   below, dmRequest is the register number, index is the Addr,
+   and value is a combination of Bit values.
+   Bit  Value (hex)
+   0    01
+   1    02
+   2    04
+   3    08
+   4    10
+   5    20
+   6    40
+   7    80
+ */
+
+/* Data for chip initialization (set default values) */
+static const __u16 spca501_init_data[][3] = {
+	/* Set all the values to powerup defaults */
+	/* bmRequest,value,index */
+	{0x0, 0xAA, 0x00},
+	{0x0, 0x02, 0x01},
+	{0x0, 0x01, 0x02},
+	{0x0, 0x02, 0x03},
+	{0x0, 0xCE, 0x04},
+	{0x0, 0x00, 0x05},
+	{0x0, 0x00, 0x06},
+	{0x0, 0x00, 0x07},
+	{0x0, 0x00, 0x08},
+	{0x0, 0x00, 0x09},
+	{0x0, 0x90, 0x0A},
+	{0x0, 0x12, 0x0B},
+	{0x0, 0x00, 0x0C},
+	{0x0, 0x00, 0x0D},
+	{0x0, 0x00, 0x0E},
+	{0x0, 0x02, 0x0F},
+	{0x0, 0x00, 0x10},
+	{0x0, 0x00, 0x11},
+	{0x0, 0x00, 0x12},
+	{0x0, 0x00, 0x13},
+	{0x0, 0x00, 0x14},
+	{0x0, 0x00, 0x15},
+	{0x0, 0x00, 0x16},
+	{0x0, 0x00, 0x17},
+	{0x0, 0x00, 0x18},
+	{0x0, 0x00, 0x19},
+	{0x0, 0x00, 0x1A},
+	{0x0, 0x00, 0x1B},
+	{0x0, 0x00, 0x1C},
+	{0x0, 0x00, 0x1D},
+	{0x0, 0x00, 0x1E},
+	{0x0, 0x00, 0x1F},
+	{0x0, 0x00, 0x20},
+	{0x0, 0x00, 0x21},
+	{0x0, 0x00, 0x22},
+	{0x0, 0x00, 0x23},
+	{0x0, 0x00, 0x24},
+	{0x0, 0x00, 0x25},
+	{0x0, 0x00, 0x26},
+	{0x0, 0x00, 0x27},
+	{0x0, 0x00, 0x28},
+	{0x0, 0x00, 0x29},
+	{0x0, 0x00, 0x2A},
+	{0x0, 0x00, 0x2B},
+	{0x0, 0x00, 0x2C},
+	{0x0, 0x00, 0x2D},
+	{0x0, 0x00, 0x2E},
+	{0x0, 0x00, 0x2F},
+	{0x0, 0x00, 0x30},
+	{0x0, 0x00, 0x31},
+	{0x0, 0x00, 0x32},
+	{0x0, 0x00, 0x33},
+	{0x0, 0x00, 0x34},
+	{0x0, 0x00, 0x35},
+	{0x0, 0x00, 0x36},
+	{0x0, 0x00, 0x37},
+	{0x0, 0x00, 0x38},
+	{0x0, 0x00, 0x39},
+	{0x0, 0x00, 0x3A},
+	{0x0, 0x00, 0x3B},
+	{0x0, 0x00, 0x3C},
+	{0x0, 0x00, 0x3D},
+	{0x0, 0x00, 0x3E},
+	{0x0, 0x00, 0x3F},
+	{0x0, 0x00, 0x40},
+	{0x0, 0x00, 0x41},
+	{0x0, 0x00, 0x42},
+	{0x0, 0x00, 0x43},
+	{0x0, 0x00, 0x44},
+	{0x0, 0x00, 0x45},
+	{0x0, 0x00, 0x46},
+	{0x0, 0x00, 0x47},
+	{0x0, 0x00, 0x48},
+	{0x0, 0x00, 0x49},
+	{0x0, 0x00, 0x4A},
+	{0x0, 0x00, 0x4B},
+	{0x0, 0x00, 0x4C},
+	{0x0, 0x00, 0x4D},
+	{0x0, 0x00, 0x4E},
+	{0x0, 0x00, 0x4F},
+	{0x0, 0x00, 0x50},
+	{0x0, 0x00, 0x51},
+	{0x0, 0x00, 0x52},
+	{0x0, 0x00, 0x53},
+	{0x0, 0x00, 0x54},
+	{0x0, 0x00, 0x55},
+	{0x0, 0x00, 0x56},
+	{0x0, 0x00, 0x57},
+	{0x0, 0x00, 0x58},
+	{0x0, 0x00, 0x59},
+	{0x0, 0x00, 0x5A},
+	{0x0, 0x00, 0x5B},
+	{0x0, 0x00, 0x5C},
+	{0x0, 0x00, 0x5D},
+	{0x0, 0x00, 0x5E},
+	{0x0, 0x00, 0x5F},
+	{0x0, 0x00, 0x60},
+	{0x0, 0x00, 0x61},
+	{0x0, 0x00, 0x62},
+	{0x0, 0x00, 0x63},
+	{0x0, 0x00, 0x64},
+	{0x0, 0x00, 0x65},
+	{0x0, 0x00, 0x66},
+	{0x0, 0x00, 0x67},
+	{0x0, 0x00, 0x68},
+	{0x0, 0x00, 0x69},
+	{0x0, 0x00, 0x6A},
+	{0x0, 0x00, 0x6B},
+	{0x0, 0x00, 0x6C},
+	{0x0, 0x00, 0x6D},
+	{0x0, 0x00, 0x6E},
+	{0x0, 0x00, 0x6F},
+	{0x0, 0x00, 0x70},
+	{0x0, 0x00, 0x71},
+	{0x0, 0x00, 0x72},
+	{0x0, 0x00, 0x73},
+	{0x0, 0x00, 0x74},
+	{0x0, 0x00, 0x75},
+	{0x0, 0x00, 0x76},
+	{0x0, 0x00, 0x77},
+	{0x0, 0x00, 0x78},
+	{0x0, 0x00, 0x79},
+	{0x0, 0x00, 0x7A},
+	{0x0, 0x00, 0x7B},
+	{0x0, 0x00, 0x7C},
+	{0x0, 0x00, 0x7D},
+	{0x0, 0x00, 0x7E},
+	{0x0, 0x00, 0x7F},
+	{0x0, 0x00, 0x80},
+	{0x0, 0x00, 0x81},
+	{0x0, 0x00, 0x82},
+	{0x0, 0x00, 0x83},
+	{0x0, 0x00, 0x84},
+	{0x0, 0x00, 0x85},
+	{0x0, 0x00, 0x86},
+	{0x0, 0x00, 0x87},
+	{0x0, 0x00, 0x88},
+	{0x0, 0x00, 0x89},
+	{0x0, 0x00, 0x8A},
+	{0x0, 0x00, 0x8B},
+	{0x0, 0x00, 0x8C},
+	{0x0, 0x00, 0x8D},
+	{0x0, 0x00, 0x8E},
+	{0x0, 0x00, 0x8F},
+	{0x0, 0x00, 0x90},
+	{0x0, 0x00, 0x91},
+	{0x0, 0x00, 0x92},
+	{0x0, 0x00, 0x93},
+	{0x0, 0x00, 0x94},
+	{0x0, 0x00, 0x95},
+	{0x0, 0x00, 0x96},
+	{0x0, 0x00, 0x97},
+	{0x0, 0x00, 0x98},
+	{0x0, 0x00, 0x99},
+	{0x0, 0x00, 0x9A},
+	{0x0, 0x00, 0x9B},
+	{0x0, 0x00, 0x9C},
+	{0x0, 0x00, 0x9D},
+	{0x0, 0x00, 0x9E},
+	{0x0, 0x00, 0x9F},
+	{0x0, 0x00, 0xA0},
+	{0x0, 0x00, 0xA1},
+	{0x0, 0x00, 0xA2},
+	{0x0, 0x00, 0xA3},
+	{0x0, 0x00, 0xA4},
+	{0x0, 0x00, 0xA5},
+	{0x0, 0x00, 0xA6},
+	{0x0, 0x00, 0xA7},
+	{0x0, 0x00, 0xA8},
+	{0x0, 0x00, 0xA9},
+	{0x0, 0x00, 0xAA},
+	{0x0, 0x00, 0xAB},
+	{0x0, 0x00, 0xAC},
+	{0x0, 0x00, 0xAD},
+	{0x0, 0x00, 0xAE},
+	{0x0, 0x00, 0xAF},
+	{0x0, 0x00, 0xB0},
+	{0x0, 0x00, 0xB1},
+	{0x0, 0x00, 0xB2},
+	{0x0, 0x00, 0xB3},
+	{0x0, 0x00, 0xB4},
+	{0x0, 0x00, 0xB5},
+	{0x0, 0x00, 0xB6},
+	{0x0, 0x00, 0xB7},
+	{0x0, 0x00, 0xB8},
+	{0x0, 0x00, 0xB9},
+	{0x0, 0x00, 0xBA},
+	{0x0, 0x00, 0xBB},
+	{0x0, 0x00, 0xBC},
+	{0x0, 0x00, 0xBD},
+	{0x0, 0x00, 0xBE},
+	{0x0, 0x00, 0xBF},
+	{0x0, 0x00, 0xC0},
+	{0x0, 0x00, 0xC1},
+	{0x0, 0x00, 0xC2},
+	{0x0, 0x00, 0xC3},
+	{0x0, 0x00, 0xC4},
+	{0x0, 0x00, 0xC5},
+	{0x0, 0x00, 0xC6},
+	{0x0, 0x00, 0xC7},
+	{0x0, 0x00, 0xC8},
+	{0x0, 0x00, 0xC9},
+	{0x0, 0x00, 0xCA},
+	{0x0, 0x00, 0xCB},
+	{0x0, 0x00, 0xCC},
+	{0x1, 0xF4, 0x00},
+	{0x1, 0x38, 0x01},
+	{0x1, 0x40, 0x02},
+	{0x1, 0x0A, 0x03},
+	{0x1, 0x40, 0x04},
+	{0x1, 0x40, 0x05},
+	{0x1, 0x40, 0x06},
+	{0x1, 0x67, 0x07},
+	{0x1, 0x31, 0x08},
+	{0x1, 0x00, 0x09},
+	{0x1, 0x00, 0x0A},
+	{0x1, 0x00, 0x0B},
+	{0x1, 0x14, 0x0C},
+	{0x1, 0x00, 0x0D},
+	{0x1, 0x00, 0x0E},
+	{0x1, 0x00, 0x0F},
+	{0x1, 0x1E, 0x10},
+	{0x1, 0x00, 0x11},
+	{0x1, 0x00, 0x12},
+	{0x1, 0x00, 0x13},
+	{0x1, 0x00, 0x14},
+	{0x1, 0xFF, 0x15},
+	{0x1, 0x01, 0x16},
+	{0x1, 0x32, 0x17},
+	{0x1, 0x23, 0x18},
+	{0x1, 0xCE, 0x19},
+	{0x1, 0x23, 0x1A},
+	{0x1, 0x32, 0x1B},
+	{0x1, 0x8D, 0x1C},
+	{0x1, 0xCE, 0x1D},
+	{0x1, 0x8D, 0x1E},
+	{0x1, 0x00, 0x1F},
+	{0x1, 0x00, 0x20},
+	{0x1, 0xFF, 0x3E},
+	{0x1, 0x02, 0x3F},
+	{0x1, 0x00, 0x40},
+	{0x1, 0x00, 0x41},
+	{0x1, 0x00, 0x42},
+	{0x1, 0x00, 0x43},
+	{0x1, 0x00, 0x44},
+	{0x1, 0x00, 0x45},
+	{0x1, 0x00, 0x46},
+	{0x1, 0x00, 0x47},
+	{0x1, 0x00, 0x48},
+	{0x1, 0x00, 0x49},
+	{0x1, 0x00, 0x4A},
+	{0x1, 0x00, 0x4B},
+	{0x1, 0x00, 0x4C},
+	{0x1, 0x00, 0x4D},
+	{0x1, 0x00, 0x4E},
+	{0x1, 0x00, 0x4F},
+	{0x1, 0x00, 0x50},
+	{0x1, 0x00, 0x51},
+	{0x1, 0x00, 0x52},
+	{0x1, 0x00, 0x53},
+	{0x1, 0x00, 0x54},
+	{0x1, 0x00, 0x55},
+	{0x1, 0x00, 0x56},
+	{0x1, 0x00, 0x57},
+	{0x1, 0x00, 0x58},
+	{0x1, 0x00, 0x59},
+	{0x1, 0x00, 0x5A},
+	{0x2, 0x03, 0x00},
+	{0x2, 0x00, 0x01},
+	{0x2, 0x00, 0x05},
+	{0x2, 0x00, 0x06},
+	{0x2, 0x00, 0x07},
+	{0x2, 0x00, 0x10},
+	{0x2, 0x00, 0x11},
+	/* Strange - looks like the 501 driver doesn't do anything
+	 * at insert time except read the EEPROM
+	 */
+	{}
+};
+
+/* Data for video camera init before capture.
+ * Capture and decoding by Colin Peart.
+ * This is is for the 3com HomeConnect Lite which is spca501a based.
+ */
+static const __u16 spca501_3com_open_data[][3] = {
+	/* bmRequest,value,index */
+	{0x2, 0x0050, 0x0000},	/* C/S Enable TG soft reset, timing mode=010 */
+	{0x2, 0x0043, 0x0000},	/* C/S Disable TG soft reset, timing mode=010 */
+	{0x2, 0x0002, 0x0005},	/* C/S GPIO */
+	{0x2, 0x0003, 0x0005},	/* C/S GPIO */
+
+#ifdef CCDSP_SET
+	{0x1, 0x0020, 0x0001},	/* CCDSP Options */
+
+	{0x1, 0x0020, 0x0002},	/* CCDSP Black Level */
+	{0x1, 0x006e, 0x0007},	/* CCDSP Gamma options */
+	{0x1, 0x0090, 0x0015},	/* CCDSP Luminance Low */
+	{0x1, 0x00ff, 0x0016},	/* CCDSP Luminance High */
+	{0x1, 0x0003, 0x003F},	/* CCDSP Gamma correction toggle */
+
+#ifdef ALTER_GAMMA
+	{0x1, 0x0010, 0x0008},	/* CCDSP YUV A11 */
+	{0x1, 0x0000, 0x0009},	/* CCDSP YUV A12 */
+	{0x1, 0x0000, 0x000a},	/* CCDSP YUV A13 */
+	{0x1, 0x0000, 0x000b},	/* CCDSP YUV A21 */
+	{0x1, 0x0010, 0x000c},	/* CCDSP YUV A22 */
+	{0x1, 0x0000, 0x000d},	/* CCDSP YUV A23 */
+	{0x1, 0x0000, 0x000e},	/* CCDSP YUV A31 */
+	{0x1, 0x0000, 0x000f},	/* CCDSP YUV A32 */
+	{0x1, 0x0010, 0x0010},	/* CCDSP YUV A33 */
+	{0x1, 0x0000, 0x0011},	/* CCDSP R Offset */
+	{0x1, 0x0000, 0x0012},	/* CCDSP G Offset */
+	{0x1, 0x0001, 0x0013},	/* CCDSP B Offset */
+	{0x1, 0x0001, 0x0014},	/* CCDSP BG Offset */
+	{0x1, 0x003f, 0x00C1},	/* CCDSP Gamma Correction Enable */
+#endif
+#endif
+
+#ifdef TG_SET
+	{0x0, 0x00fc, 0x0000},	/* TG Shutter Speed High Bits */
+	{0x0, 0x0000, 0x0001},	/* TG Shutter Speed Low Bits */
+	{0x0, 0x00e4, 0x0004},	/* TG DCLK*2 Adjust */
+	{0x0, 0x0008, 0x0005},	/* TG ADCK Adjust */
+	{0x0, 0x0003, 0x0006},	/* TG FR Phase Adjust */
+	{0x0, 0x0001, 0x0007},	/* TG FCDS Phase Adjust */
+	{0x0, 0x0039, 0x0008},	/* TG FS Phase Adjust */
+	{0x0, 0x0088, 0x000a},	/* TG MH1 */
+	{0x0, 0x0003, 0x000f},	/* TG Pixel ID */
+
+	/* Like below, unexplained toglleing */
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0004, 0x000d},
+	{0x0, 0x0000, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0040, 0x000c},
+	{0x0, 0x0017, 0x000d},
+	{0x0, 0x00c0, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0006, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0004, 0x000d},
+	{0x0, 0x0002, 0x0003},
+#endif
+
+#ifdef DSPWIN_SET
+	{0x1, 0x001c, 0x0017},	/* CCDSP W1 Start X */
+	{0x1, 0x00e2, 0x0019},	/* CCDSP W2 Start X */
+	{0x1, 0x001c, 0x001b},	/* CCDSP W3 Start X */
+	{0x1, 0x00e2, 0x001d},	/* CCDSP W4 Start X */
+	{0x1, 0x00aa, 0x001f},	/* CCDSP W5 Start X */
+	{0x1, 0x0070, 0x0020},	/* CCDSP W5 Start Y */
+#endif
+	{0x0, 0x0001, 0x0010},	/* TG Start Clock */
+
+/*	{0x2, 0x006a, 0x0001},	 * C/S Enable ISOSYNCH Packet Engine */
+	{0x2, 0x0068, 0x0001},	/* C/S Diable ISOSYNCH Packet Engine */
+	{0x2, 0x0000, 0x0005},
+	{0x2, 0x0043, 0x0000},	/* C/S Set Timing Mode, Disable TG soft reset */
+	{0x2, 0x0043, 0x0000},	/* C/S Set Timing Mode, Disable TG soft reset */
+	{0x2, 0x0002, 0x0005},	/* C/S GPIO */
+	{0x2, 0x0003, 0x0005},	/* C/S GPIO */
+
+	{0x2, 0x006a, 0x0001},	/* C/S Enable ISOSYNCH Packet Engine */
+	{}
+};
+
+/*
+ * Data used to initialize a SPCA501C with HV7131B sensor.
+ * From a capture file taken with USBSnoop v 1.5
+ * I have a "SPCA501C pc camera chipset" manual by sunplus, but some
+ * of the value meanings are obscure or simply "reserved".
+ * to do list:
+ * 1) Understand what every value means
+ * 2) Understand why some values seem to appear more than once
+ * 3) Write a small comment for each line of the following arrays.
+ */
+static const __u16 spca501c_arowana_open_data[][3] = {
+	/* bmRequest,value,index */
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x01, 0x0006, 0x0011},
+	{0x01, 0x00ff, 0x0012},
+	{0x01, 0x0014, 0x0013},
+	{0x01, 0x0000, 0x0014},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x01, 0x0000, 0x0055},
+	{0x00, 0x0025, 0x0000},
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{}
+};
+
+static const __u16 spca501c_arowana_init_data[][3] = {
+	/* bmRequest,value,index */
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x01, 0x0006, 0x0011},
+	{0x01, 0x00ff, 0x0012},
+	{0x01, 0x0014, 0x0013},
+	{0x01, 0x0000, 0x0014},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x01, 0x0000, 0x0055},
+	{0x00, 0x0025, 0x0000},
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x00c8, 0x0015},
+	{0x01, 0x0032, 0x0016},
+	{0x01, 0x0000, 0x0011},
+	{0x01, 0x0000, 0x0012},
+	{0x01, 0x0000, 0x0013},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x000f, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x001e, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x002d, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{}
+};
+
+/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_open_data[][3] = {
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+/* DSP Registers */
+	{0x01, 0x0016, 0x0011},	/* RGB offset */
+	{0x01, 0x0000, 0x0012},
+	{0x01, 0x0006, 0x0013},
+	{0x01, 0x0078, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0046, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x00, 0x0025, 0x0000},
+/*	{0x00, 0x0000, 0x0000 }, */
+/* Part 2 */
+/* TG Registers */
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{}
+};
+
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_init_data[][3] = {
+/* Part 3 */
+/* TG registers */
+/*	{0x00, 0x0000, 0x0000}, */
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x0006, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0001, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},	/* 640 */
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},	/* 480 */
+	{0x00, 0x0000, 0x0024},	/* Offset H hight */
+	{0x00, 0x00d3, 0x0025},	/* low */
+	{0x00, 0x0000, 0x0026},	/* Offset V */
+	{0x00, 0x000d, 0x0027},	/* low */
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+/* DSP Registers	 */
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},	/* Level Calc bit7 ->1 Auto */
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x000f, 0x0008},	/* A11 Color correction coeff */
+	{0x01, 0x002d, 0x0009},	/* A12 */
+	{0x01, 0x0005, 0x000a},	/* A13 */
+	{0x01, 0x0023, 0x000b},	/* A21 */
+	{0x01, 0x00e0, 0x000c},	/* A22 */
+	{0x01, 0x00fd, 0x000d},	/* A23 */
+	{0x01, 0x00f4, 0x000e},	/* A31 */
+	{0x01, 0x00e4, 0x000f},	/* A32 */
+	{0x01, 0x0028, 0x0010},	/* A33 */
+	{0x01, 0x00ff, 0x0015},	/* Reserved */
+	{0x01, 0x0001, 0x0016},	/* Reserved */
+	{0x01, 0x0032, 0x0017},	/* Win1 Start begin */
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},	/* Win1 Start end */
+	{0x01, 0x00ff, 0x003e},	/* Reserved begin */
+	{0x01, 0x0002, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0003, 0x0056},	/* Reserved end */
+	{0x01, 0x0060, 0x0057},	/* Edge Gain */
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},	/* Edge Bandwidth */
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x200a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+/* Part 4             */
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0000, 0x0005},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x004e, 0x0000},
+/* Part 5        	 */
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x000f, 0x0008},
+	{0x01, 0x002d, 0x0009},
+	{0x01, 0x0005, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffe0, 0x000c},
+	{0x01, 0xfffd, 0x000d},
+	{0x01, 0xfff4, 0x000e},
+	{0x01, 0xffe4, 0x000f},
+	{0x01, 0x0028, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x00c8, 0x0015},	/* c8 Poids fort Luma */
+	{0x01, 0x0032, 0x0016},	/* 32 */
+	{0x01, 0x0016, 0x0011},	/* R 00 */
+	{0x01, 0x0016, 0x0012},	/* G 00 */
+	{0x01, 0x0016, 0x0013},	/* B 00 */
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
+		req, index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+
+	gspca_dev->usb_buf[1] = 0;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			gspca_dev->usb_buf, length,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Reg write failed for 0x%02x,0x%02x,0x%02x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 brightness;
+
+	brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2);
+	sd->brightness = brightness << 1;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, 0x00, 0x00,
+				  (sd->contrast >> 8) & 0xff);
+	reg_write(gspca_dev->dev, 0x00, 0x01,
+				  sd->contrast & 0xff);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+/*	spca50x->contrast = 0xaa01; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2);
+/*	sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */
+/*			2) & 0xFF) << 8; */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x0000:		/* Unknow Camera */
+/*		switch (product) { */
+/*		case 0x0000: */
+			sd->subtype = MystFromOriUnknownCamera;
+/*			break; */
+/*		} */
+		break;
+	case 0x040a:		/* Kodak cameras */
+/*		switch (product) { */
+/*		case 0x0002: */
+			sd->subtype = KodakDVC325;
+/*			break; */
+/*		} */
+		break;
+	case 0x0497:		/* Smile International */
+/*		switch (product) { */
+/*		case 0xc001: */
+			sd->subtype = SmileIntlCamera;
+/*			break; */
+/*		} */
+		break;
+	case 0x0506:		/* 3COM cameras */
+/*		switch (product) { */
+/*		case 0x00df: */
+			sd->subtype = ThreeComHomeConnectLite;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+		switch (product) {
+		case 0x0401:
+			sd->subtype = IntelCreateAndShare;
+			break;
+		case 0x0402:
+			sd->subtype = ViewQuestM318B;
+			break;
+		}
+		break;
+	case 0x1776:		/* Arowana */
+/*		switch (product) { */
+/*		case 0x501c: */
+			sd->subtype = Arowana300KCMOSCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
+
+	switch (sd->subtype) {
+	case Arowana300KCMOSCamera:
+	case SmileIntlCamera:
+		/* Arowana 300k CMOS Camera data */
+		if (write_vector(gspca_dev, spca501c_arowana_init_data))
+			goto error;
+		break;
+	case MystFromOriUnknownCamera:
+		/* UnKnow Ori CMOS Camera data */
+		if (write_vector(gspca_dev, spca501c_mysterious_open_data))
+			goto error;
+		break;
+	default:
+		/* generic spca501 init data */
+		if (write_vector(gspca_dev, spca501_init_data))
+			goto error;
+		break;
+	}
+	return 0;
+error:
+	return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->subtype) {
+	case ThreeComHomeConnectLite:
+		/* Special handling for 3com data */
+		write_vector(gspca_dev, spca501_3com_open_data);
+		break;
+	case Arowana300KCMOSCamera:
+	case SmileIntlCamera:
+		/* Arowana 300k CMOS Camera data */
+		write_vector(gspca_dev, spca501c_arowana_open_data);
+		break;
+	case MystFromOriUnknownCamera:
+		/* UnKnow  CMOS Camera data */
+		write_vector(gspca_dev, spca501c_mysterious_init_data);
+		break;
+	default:
+		/* Generic 501 open data */
+		write_vector(gspca_dev, spca501_open_data);
+	}
+	PDEBUG(D_STREAM, "Initializing SPCA501 finished");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int mode;
+
+	/* memorize the wanted pixel format */
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+
+	/* Enable ISO packet machine CTRL reg=2,
+	 * index=1 bitmask=0x2 (bit ordinal 1) */
+	reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+	switch (mode) {
+	case 0: /* 640x480 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+		break;
+	case 1: /* 320x240 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+		break;
+	default:
+/*	case 2:  * 160x120 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+		break;
+	}
+	reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+
+	/* HDG atleast the Intel CreateAndShare needs to have one of its
+	 * brightness / contrast / color set otherwise it assumes what seems
+	 * max contrast. Note that strange enough setting any of these is
+	 * enough to fix the max contrast problem, to be sure we set all 3 */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Disable ISO packet
+	 * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
+	reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		frame = gspca_frame_add(gspca_dev,
+					LAST_PACKET,
+					frame,
+					data, 0);
+		data += SPCA501_OFFSET_DATA;
+		len -= SPCA501_OFFSET_DATA;
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, len);
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data++;
+	len--;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")},
+	{USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")},
+	{USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")},
+	{USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")},
+	{USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")},
+	{USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")},
+	{USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
new file mode 100644
index 0000000..ddea6e1
--- /dev/null
+++ b/drivers/media/video/gspca/spca505.c
@@ -0,0 +1,951 @@
+/*
+ * SPCA505 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ *
+ */
+
+#define MODULE_NAME "spca505"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int buflen;
+	unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */
+	unsigned char tmpbuf2[640 * 480 * 2];	/* YUYV */
+
+	unsigned char brightness;
+
+	char subtype;
+#define IntelPCCameraPro 0
+#define Nxultra 1
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 160 * 2,
+		.sizeimage = 160 * 120 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 5},
+	{176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 176 * 2,
+		.sizeimage = 176 * 144 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 4},
+	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 320 * 2,
+		.sizeimage = 320 * 240 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 352 * 2,
+		.sizeimage = 352 * 288 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 640 * 2,
+		.sizeimage = 640 * 480 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SPCA50X_REG_USB 0x02	/* spca505 501 */
+
+#define SPCA50X_USB_CTRL 0x00	/* spca505 */
+#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+#define SPCA50X_REG_GLOBAL 0x03	/* spca505 */
+#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+
+#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
+#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+#define SPCA50X_GMISC3_SAA7113RST 0x20	/* Not sure about this one spca505 */
+
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505_init_data[][3] = {
+	/* line	   bmRequest,value,index */
+	/* 1819 */
+	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+	/* Sensor reset */
+	/* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+	/* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+	/* Block USB reset */
+	/* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+		SPCA50X_GLOBAL_MISC0},
+
+	/* 1831 */ {0x5, 0x01, 0x10},
+					/* Maybe power down some stuff */
+	/* 1834 */ {0x5, 0x0f, 0x11},
+
+	/* Setup internal CCD  ? */
+	/* 1837 */ {0x6, 0x10, 0x08},
+	/* 1840 */ {0x6, 0x00, 0x09},
+	/* 1843 */ {0x6, 0x00, 0x0a},
+	/* 1846 */ {0x6, 0x00, 0x0b},
+	/* 1849 */ {0x6, 0x10, 0x0c},
+	/* 1852 */ {0x6, 0x00, 0x0d},
+	/* 1855 */ {0x6, 0x00, 0x0e},
+	/* 1858 */ {0x6, 0x00, 0x0f},
+	/* 1861 */ {0x6, 0x10, 0x10},
+	/* 1864 */ {0x6, 0x02, 0x11},
+	/* 1867 */ {0x6, 0x00, 0x12},
+	/* 1870 */ {0x6, 0x04, 0x13},
+	/* 1873 */ {0x6, 0x02, 0x14},
+	/* 1876 */ {0x6, 0x8a, 0x51},
+	/* 1879 */ {0x6, 0x40, 0x52},
+	/* 1882 */ {0x6, 0xb6, 0x53},
+	/* 1885 */ {0x6, 0x3d, 0x54},
+	{}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505_open_data_ccd[][3] = {
+	/* line	   bmRequest,value,index */
+	/* Internal CCD data set */
+	/* 1891 */ {0x3, 0x04, 0x01},
+	/* This could be a reset */
+	/* 1894 */ {0x3, 0x00, 0x01},
+
+	/* Setup compression and image registers. 0x6 and 0x7 seem to be
+	   related to H&V hold, and are resolution mode specific */
+		/* 1897 */ {0x4, 0x10, 0x01},
+		/* DIFF(0x50), was (0x10) */
+	/* 1900 */ {0x4, 0x00, 0x04},
+	/* 1903 */ {0x4, 0x00, 0x05},
+	/* 1906 */ {0x4, 0x20, 0x06},
+	/* 1909 */ {0x4, 0x20, 0x07},
+
+	/* 1912 */ {0x8, 0x0a, 0x00},
+	/* DIFF (0x4a), was (0xa) */
+
+	/* 1915 */ {0x5, 0x00, 0x10},
+	/* 1918 */ {0x5, 0x00, 0x11},
+	/* 1921 */ {0x5, 0x00, 0x00},
+	/* DIFF not written */
+	/* 1924 */ {0x5, 0x00, 0x01},
+	/* DIFF not written */
+	/* 1927 */ {0x5, 0x00, 0x02},
+	/* DIFF not written */
+	/* 1930 */ {0x5, 0x00, 0x03},
+	/* DIFF not written */
+	/* 1933 */ {0x5, 0x00, 0x04},
+	/* DIFF not written */
+		/* 1936 */ {0x5, 0x80, 0x05},
+		/* DIFF not written */
+		/* 1939 */ {0x5, 0xe0, 0x06},
+		/* DIFF not written */
+		/* 1942 */ {0x5, 0x20, 0x07},
+		/* DIFF not written */
+		/* 1945 */ {0x5, 0xa0, 0x08},
+		/* DIFF not written */
+		/* 1948 */ {0x5, 0x0, 0x12},
+		/* DIFF not written */
+	/* 1951 */ {0x5, 0x02, 0x0f},
+	/* DIFF not written */
+		/* 1954 */ {0x5, 0x10, 0x46},
+		/* DIFF not written */
+		/* 1957 */ {0x5, 0x8, 0x4a},
+		/* DIFF not written */
+
+	/* 1960 */ {0x3, 0x08, 0x03},
+	/* DIFF (0x3,0x28,0x3) */
+	/* 1963 */ {0x3, 0x08, 0x01},
+	/* 1966 */ {0x3, 0x0c, 0x03},
+	/* DIFF not written */
+		/* 1969 */ {0x3, 0x21, 0x00},
+		/* DIFF (0x39) */
+
+/* Extra block copied from init to hopefully ensure CCD is in a sane state */
+	/* 1837 */ {0x6, 0x10, 0x08},
+	/* 1840 */ {0x6, 0x00, 0x09},
+	/* 1843 */ {0x6, 0x00, 0x0a},
+	/* 1846 */ {0x6, 0x00, 0x0b},
+	/* 1849 */ {0x6, 0x10, 0x0c},
+	/* 1852 */ {0x6, 0x00, 0x0d},
+	/* 1855 */ {0x6, 0x00, 0x0e},
+	/* 1858 */ {0x6, 0x00, 0x0f},
+	/* 1861 */ {0x6, 0x10, 0x10},
+	/* 1864 */ {0x6, 0x02, 0x11},
+	/* 1867 */ {0x6, 0x00, 0x12},
+	/* 1870 */ {0x6, 0x04, 0x13},
+	/* 1873 */ {0x6, 0x02, 0x14},
+	/* 1876 */ {0x6, 0x8a, 0x51},
+	/* 1879 */ {0x6, 0x40, 0x52},
+	/* 1882 */ {0x6, 0xb6, 0x53},
+	/* 1885 */ {0x6, 0x3d, 0x54},
+	/* End of extra block */
+
+		/* 1972 */ {0x6, 0x3f, 0x1},
+		/* Block skipped */
+	/* 1975 */ {0x6, 0x10, 0x02},
+	/* 1978 */ {0x6, 0x64, 0x07},
+	/* 1981 */ {0x6, 0x10, 0x08},
+	/* 1984 */ {0x6, 0x00, 0x09},
+	/* 1987 */ {0x6, 0x00, 0x0a},
+	/* 1990 */ {0x6, 0x00, 0x0b},
+	/* 1993 */ {0x6, 0x10, 0x0c},
+	/* 1996 */ {0x6, 0x00, 0x0d},
+	/* 1999 */ {0x6, 0x00, 0x0e},
+	/* 2002 */ {0x6, 0x00, 0x0f},
+	/* 2005 */ {0x6, 0x10, 0x10},
+	/* 2008 */ {0x6, 0x02, 0x11},
+	/* 2011 */ {0x6, 0x00, 0x12},
+	/* 2014 */ {0x6, 0x04, 0x13},
+	/* 2017 */ {0x6, 0x02, 0x14},
+	/* 2020 */ {0x6, 0x8a, 0x51},
+	/* 2023 */ {0x6, 0x40, 0x52},
+	/* 2026 */ {0x6, 0xb6, 0x53},
+	/* 2029 */ {0x6, 0x3d, 0x54},
+	/* 2032 */ {0x6, 0x60, 0x57},
+	/* 2035 */ {0x6, 0x20, 0x58},
+	/* 2038 */ {0x6, 0x15, 0x59},
+	/* 2041 */ {0x6, 0x05, 0x5a},
+
+	/* 2044 */ {0x5, 0x01, 0xc0},
+	/* 2047 */ {0x5, 0x10, 0xcb},
+		/* 2050 */ {0x5, 0x80, 0xc1},
+		/* */
+		/* 2053 */ {0x5, 0x0, 0xc2},
+		/* 4 was 0 */
+	/* 2056 */ {0x5, 0x00, 0xca},
+		/* 2059 */ {0x5, 0x80, 0xc1},
+		/*  */
+	/* 2062 */ {0x5, 0x04, 0xc2},
+	/* 2065 */ {0x5, 0x00, 0xca},
+		/* 2068 */ {0x5, 0x0, 0xc1},
+		/*  */
+	/* 2071 */ {0x5, 0x00, 0xc2},
+	/* 2074 */ {0x5, 0x00, 0xca},
+		/* 2077 */ {0x5, 0x40, 0xc1},
+		/* */
+	/* 2080 */ {0x5, 0x17, 0xc2},
+	/* 2083 */ {0x5, 0x00, 0xca},
+		/* 2086 */ {0x5, 0x80, 0xc1},
+		/* */
+	/* 2089 */ {0x5, 0x06, 0xc2},
+	/* 2092 */ {0x5, 0x00, 0xca},
+		/* 2095 */ {0x5, 0x80, 0xc1},
+		/* */
+	/* 2098 */ {0x5, 0x04, 0xc2},
+	/* 2101 */ {0x5, 0x00, 0xca},
+
+	/* 2104 */ {0x3, 0x4c, 0x3},
+	/* 2107 */ {0x3, 0x18, 0x1},
+
+	/* 2110 */ {0x6, 0x70, 0x51},
+	/* 2113 */ {0x6, 0xbe, 0x53},
+	/* 2116 */ {0x6, 0x71, 0x57},
+	/* 2119 */ {0x6, 0x20, 0x58},
+	/* 2122 */ {0x6, 0x05, 0x59},
+	/* 2125 */ {0x6, 0x15, 0x5a},
+
+	/* 2128 */ {0x4, 0x00, 0x08},
+	/* Compress = OFF (0x1 to turn on) */
+	/* 2131 */ {0x4, 0x12, 0x09},
+	/* 2134 */ {0x4, 0x21, 0x0a},
+	/* 2137 */ {0x4, 0x10, 0x0b},
+	/* 2140 */ {0x4, 0x21, 0x0c},
+	/* 2143 */ {0x4, 0x05, 0x00},
+	/* was 5 (Image Type ? ) */
+	/* 2146 */ {0x4, 0x00, 0x01},
+
+	/* 2149 */ {0x6, 0x3f, 0x01},
+
+	/* 2152 */ {0x4, 0x00, 0x04},
+	/* 2155 */ {0x4, 0x00, 0x05},
+	/* 2158 */ {0x4, 0x40, 0x06},
+	/* 2161 */ {0x4, 0x40, 0x07},
+
+	/* 2164 */ {0x6, 0x1c, 0x17},
+	/* 2167 */ {0x6, 0xe2, 0x19},
+	/* 2170 */ {0x6, 0x1c, 0x1b},
+	/* 2173 */ {0x6, 0xe2, 0x1d},
+	/* 2176 */ {0x6, 0xaa, 0x1f},
+	/* 2179 */ {0x6, 0x70, 0x20},
+
+	/* 2182 */ {0x5, 0x01, 0x10},
+	/* 2185 */ {0x5, 0x00, 0x11},
+	/* 2188 */ {0x5, 0x01, 0x00},
+	/* 2191 */ {0x5, 0x05, 0x01},
+		/* 2194 */ {0x5, 0x00, 0xc1},
+		/* */
+	/* 2197 */ {0x5, 0x00, 0xc2},
+	/* 2200 */ {0x5, 0x00, 0xca},
+
+	/* 2203 */ {0x6, 0x70, 0x51},
+	/* 2206 */ {0x6, 0xbe, 0x53},
+	{}
+};
+
+/*
+   Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+ *
+ */
+/* jfm */
+#define initial_brightness 0x7f	/* 0x0(white)-0xff(black) */
+/* #define initial_brightness 0x0	//0x0(white)-0xff(black) */
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505b_init_data[][3] = {
+/* start */
+	{0x02, 0x00, 0x00},		/* init */
+	{0x02, 0x00, 0x01},
+	{0x02, 0x00, 0x02},
+	{0x02, 0x00, 0x03},
+	{0x02, 0x00, 0x04},
+	{0x02, 0x00, 0x05},
+	{0x02, 0x00, 0x06},
+	{0x02, 0x00, 0x07},
+	{0x02, 0x00, 0x08},
+	{0x02, 0x00, 0x09},
+	{0x03, 0x00, 0x00},
+	{0x03, 0x00, 0x01},
+	{0x03, 0x00, 0x02},
+	{0x03, 0x00, 0x03},
+	{0x03, 0x00, 0x04},
+	{0x03, 0x00, 0x05},
+	{0x03, 0x00, 0x06},
+	{0x04, 0x00, 0x00},
+	{0x04, 0x00, 0x02},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x00, 0x06},
+	{0x04, 0x00, 0x07},
+	{0x04, 0x00, 0x08},
+	{0x04, 0x00, 0x09},
+	{0x04, 0x00, 0x0a},
+	{0x04, 0x00, 0x0b},
+	{0x04, 0x00, 0x0c},
+	{0x07, 0x00, 0x00},
+	{0x07, 0x00, 0x03},
+	{0x08, 0x00, 0x00},
+	{0x08, 0x00, 0x01},
+	{0x08, 0x00, 0x02},
+	{0x00, 0x01, 0x00},
+	{0x00, 0x01, 0x01},
+	{0x00, 0x01, 0x34},
+	{0x00, 0x01, 0x35},
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x06, 0x18, 0x0c},
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x18, 0x10},
+	{0x06, 0xfe, 0x12},
+	{0x06, 0x00, 0x11},
+	{0x06, 0x00, 0x14},
+	{0x06, 0x00, 0x13},
+	{0x06, 0x28, 0x51},
+	{0x06, 0xff, 0x53},
+	{0x02, 0x00, 0x08},
+
+	{0x03, 0x00, 0x03},
+	{0x03, 0x10, 0x03},
+	{}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505b_open_data_ccd[][3] = {
+
+/* {0x02,0x00,0x00}, */
+	{0x03, 0x04, 0x01},		/* rst */
+	{0x03, 0x00, 0x01},
+	{0x03, 0x00, 0x00},
+	{0x03, 0x21, 0x00},
+	{0x03, 0x00, 0x04},
+	{0x03, 0x00, 0x03},
+	{0x03, 0x18, 0x03},
+	{0x03, 0x08, 0x01},
+	{0x03, 0x1c, 0x03},
+	{0x03, 0x5c, 0x03},
+	{0x03, 0x5c, 0x03},
+	{0x03, 0x18, 0x01},
+
+/* same as 505 */
+	{0x04, 0x10, 0x01},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x20, 0x06},
+	{0x04, 0x20, 0x07},
+
+	{0x08, 0x0a, 0x00},
+
+	{0x05, 0x00, 0x10},
+	{0x05, 0x00, 0x11},
+	{0x05, 0x00, 0x12},
+	{0x05, 0x6f, 0x00},
+	{0x05, initial_brightness >> 6, 0x00},
+	{0x05, initial_brightness << 2, 0x01},
+	{0x05, 0x00, 0x02},
+	{0x05, 0x01, 0x03},
+	{0x05, 0x00, 0x04},
+	{0x05, 0x03, 0x05},
+	{0x05, 0xe0, 0x06},
+	{0x05, 0x20, 0x07},
+	{0x05, 0xa0, 0x08},
+	{0x05, 0x00, 0x12},
+	{0x05, 0x02, 0x0f},
+	{0x05, 128, 0x14},		/* max exposure off (0=on) */
+	{0x05, 0x01, 0xb0},
+	{0x05, 0x01, 0xbf},
+	{0x03, 0x02, 0x06},
+	{0x05, 0x10, 0x46},
+	{0x05, 0x08, 0x4a},
+
+	{0x06, 0x00, 0x01},
+	{0x06, 0x10, 0x02},
+	{0x06, 0x64, 0x07},
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x04, 0x00, 0x01},
+	{0x06, 0x18, 0x0c},
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x11, 0x10},		/* contrast */
+	{0x06, 0x00, 0x11},
+	{0x06, 0xfe, 0x12},
+	{0x06, 0x00, 0x13},
+	{0x06, 0x00, 0x14},
+	{0x06, 0x9d, 0x51},
+	{0x06, 0x40, 0x52},
+	{0x06, 0x7c, 0x53},
+	{0x06, 0x40, 0x54},
+	{0x06, 0x02, 0x57},
+	{0x06, 0x03, 0x58},
+	{0x06, 0x15, 0x59},
+	{0x06, 0x05, 0x5a},
+	{0x06, 0x03, 0x56},
+	{0x06, 0x02, 0x3f},
+	{0x06, 0x00, 0x40},
+	{0x06, 0x39, 0x41},
+	{0x06, 0x69, 0x42},
+	{0x06, 0x87, 0x43},
+	{0x06, 0x9e, 0x44},
+	{0x06, 0xb1, 0x45},
+	{0x06, 0xbf, 0x46},
+	{0x06, 0xcc, 0x47},
+	{0x06, 0xd5, 0x48},
+	{0x06, 0xdd, 0x49},
+	{0x06, 0xe3, 0x4a},
+	{0x06, 0xe8, 0x4b},
+	{0x06, 0xed, 0x4c},
+	{0x06, 0xf2, 0x4d},
+	{0x06, 0xf7, 0x4e},
+	{0x06, 0xfc, 0x4f},
+	{0x06, 0xff, 0x50},
+
+	{0x05, 0x01, 0xc0},
+	{0x05, 0x10, 0xcb},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x04, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x09, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0xc0, 0xc1},
+	{0x05, 0x09, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x59, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x04, 0x00, 0x01},
+	{0x05, 0x80, 0xc1},
+	{0x05, 0xec, 0xc2},
+	{0x05, 0x0, 0xca},
+
+	{0x06, 0x02, 0x57},
+	{0x06, 0x01, 0x58},
+	{0x06, 0x15, 0x59},
+	{0x06, 0x0a, 0x5a},
+	{0x06, 0x01, 0x57},
+	{0x06, 0x8a, 0x03},
+	{0x06, 0x0a, 0x6c},
+	{0x06, 0x30, 0x01},
+	{0x06, 0x20, 0x02},
+	{0x06, 0x00, 0x03},
+
+	{0x05, 0x8c, 0x25},
+
+	{0x06, 0x4d, 0x51},		/* maybe saturation (4d) */
+	{0x06, 0x84, 0x53},		/* making green (84) */
+	{0x06, 0x00, 0x57},		/* sharpness (1) */
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x06, 0x18, 0x0c},		/* maybe hue (18) */
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x18, 0x10},		/* maybe contrast (18) */
+
+	{0x05, 0x01, 0x02},
+
+	{0x04, 0x00, 0x08},		/* compression */
+	{0x04, 0x12, 0x09},
+	{0x04, 0x21, 0x0a},
+	{0x04, 0x10, 0x0b},
+	{0x04, 0x21, 0x0c},
+	{0x04, 0x1d, 0x00},		/* imagetype (1d) */
+	{0x04, 0x41, 0x01},		/* hardware snapcontrol */
+
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x10, 0x06},
+	{0x04, 0x10, 0x07},
+	{0x04, 0x40, 0x06},
+	{0x04, 0x40, 0x07},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+
+	{0x06, 0x1c, 0x17},
+	{0x06, 0xe2, 0x19},
+	{0x06, 0x1c, 0x1b},
+	{0x06, 0xe2, 0x1d},
+	{0x06, 0x5f, 0x1f},
+	{0x06, 0x32, 0x20},
+
+	{0x05, initial_brightness >> 6, 0x00},
+	{0x05, initial_brightness << 2, 0x01},
+	{0x05, 0x06, 0xc1},
+	{0x05, 0x58, 0xc2},
+	{0x05, 0x0, 0xca},
+	{0x05, 0x0, 0x11},
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+		     __u16 reg, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			reg,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+		reg, index, value, ret);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+			__u16 reg,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+
+	gspca_dev->usb_buf[1] = 0;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			reg,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			(__u16) 0,		/* value */
+			(__u16) index,
+			gspca_dev->usb_buf, length,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Register write failed for 0x%x,0x%x,0x%x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x401d:	 * here505b */
+			sd->subtype = Nxultra;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*		switch (product) { */
+/*		case 0x0430: */
+/*		fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
+			sd->subtype = IntelPCCameraPro;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	if (sd->subtype != IntelPCCameraPro)
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	else			/* no 640x480 for IntelPCCameraPro */
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+	if (sd->subtype == Nxultra) {
+		if (write_vector(gspca_dev, spca505b_init_data))
+			return -EIO;
+	} else {
+		if (write_vector(gspca_dev, spca505_init_data))
+			return -EIO;
+	}
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	PDEBUG(D_STREAM, "Initializing SPCA505");
+	if (sd->subtype == Nxultra)
+		write_vector(gspca_dev, spca505b_open_data_ccd);
+	else
+		write_vector(gspca_dev, spca505_open_data_ccd);
+	ret = reg_read(gspca_dev, 6, 0x16, 2);
+
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_STREAM,
+		       "register read failed for after vector read err = %d",
+		       ret);
+		return -EIO;
+	}
+	PDEBUG(D_STREAM,
+		"After vector read returns : 0x%x should be 0x0101",
+		ret & 0xffff);
+
+	ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+		       ret);
+		return -EIO;
+	}
+	reg_write(gspca_dev->dev, 5, 0xc2, 18);
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	/* necessary because without it we can see stream
+	 * only once after loading module */
+	/* stopping usb registers Tomasz change */
+	reg_write(dev, 0x02, 0x0, 0x0);
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		reg_write(dev, 0x04, 0x00, 0x00);
+		reg_write(dev, 0x04, 0x06, 0x10);
+		reg_write(dev, 0x04, 0x07, 0x10);
+		break;
+	case 1:
+		reg_write(dev, 0x04, 0x00, 0x01);
+		reg_write(dev, 0x04, 0x06, 0x1a);
+		reg_write(dev, 0x04, 0x07, 0x1a);
+		break;
+	case 2:
+		reg_write(dev, 0x04, 0x00, 0x02);
+		reg_write(dev, 0x04, 0x06, 0x1c);
+		reg_write(dev, 0x04, 0x07, 0x1d);
+		break;
+	case 4:
+		reg_write(dev, 0x04, 0x00, 0x04);
+		reg_write(dev, 0x04, 0x06, 0x34);
+		reg_write(dev, 0x04, 0x07, 0x34);
+		break;
+	default:
+/*	case 5: */
+		reg_write(dev, 0x04, 0x00, 0x05);
+		reg_write(dev, 0x04, 0x06, 0x40);
+		reg_write(dev, 0x04, 0x07, 0x40);
+		break;
+	}
+/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+	ret = reg_write(dev, SPCA50X_REG_USB,
+			 SPCA50X_USB_CTRL,
+			 SPCA50X_CUSB_ENABLE);
+
+/*	reg_write(dev, 0x5, 0x0, 0x0); */
+/*	reg_write(dev, 0x5, 0x0, 0x1); */
+/*	reg_write(dev, 0x5, 0x11, 0x2); */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Disable ISO packet machine */
+	reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	/* This maybe reset or power control */
+	reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+	reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+	reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+	reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+	reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		yi1 = yi + width;
+		Ui = yi1 + width;
+		Vi = Ui + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA50X_OFFSET_DATA;
+		len -= SPCA50X_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	__u8 brightness = sd->brightness;
+	reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+	reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+
+}
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = 255
+		- ((reg_read(gspca_dev, 5, 0x01, 1) >> 2)
+			+ (reg_read(gspca_dev, 5, 0x0, 1) << 6));
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")},
+	{USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
new file mode 100644
index 0000000..143203c
--- /dev/null
+++ b/drivers/media/video/gspca/spca506.c
@@ -0,0 +1,847 @@
+/*
+ * SPCA506 chip based cameras function
+ * M Xhaard 15/04/2004 based on different work Mark Taylor and others
+ * and my own snoopy file on a pv-321c donate by a german compagny
+ *                "Firma Frank Gmbh" from  Saarbruecken
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "spca506"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	int buflen;
+	__u8 tmpbuf[640 * 480 * 3];	/* YYUV per line */
+	__u8 tmpbuf2[640 * 480 * 2];	/* YUYV */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char hue;
+	char norme;
+	char channel;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x80,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x47,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x40,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+#define SD_HUE 3
+	{
+	    {
+		.id      = V4L2_CID_HUE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Hue",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0,
+	    },
+	    .set = sd_sethue,
+	    .get = sd_gethue,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 160 * 2,
+		.sizeimage = 160 * 120 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 5},
+	{176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 176 * 2,
+		.sizeimage = 176 * 144 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 4},
+	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 320 * 2,
+		.sizeimage = 320 * 240 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 352 * 2,
+		.sizeimage = 352 * 288 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 640 * 2,
+		.sizeimage = 640 * 480 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SAA7113_bright 0x0a	/* defaults 0x80 */
+#define SAA7113_contrast 0x0b	/* defaults 0x47 */
+#define SAA7113_saturation 0x0c	/* defaults 0x40 */
+#define SAA7113_hue 0x0d	/* defaults 0x00 */
+#define SAA7113_I2C_BASE_WRITE 0x4a
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 req,
+		  __u16 index,
+		  __u16 length)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, gspca_dev->usb_buf, length,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+		  __u16 req,
+		  __u16 value,
+		  __u16 index)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index,
+			NULL, 0, 500);
+}
+
+static void spca506_Initi2c(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+}
+
+static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+			     __u16 reg)
+{
+	int retry = 60;
+
+	reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+	reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);
+	while (retry--) {
+		reg_r(gspca_dev, 0x07, 0x0003, 2);
+		if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
+			break;
+	}
+}
+
+static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+{
+	int retry = 60;
+
+	reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+	reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+	reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+	while (--retry) {
+		reg_r(gspca_dev, 0x07, 0x0003, 2);
+		if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)
+			break;
+	}
+	if (retry == 0)
+		return -1;
+	reg_r(gspca_dev, 0x07, 0x0000, 1);
+	return gspca_dev->usb_buf[0];
+}
+
+static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+				 __u16 norme,
+				 __u16 channel)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/* fixme: check if channel == 0..3 and 6..9 (8 values) */
+	__u8 setbit0 = 0x00;
+	__u8 setbit1 = 0x00;
+	__u8 videomask = 0x00;
+
+	PDEBUG(D_STREAM, "** Open Set Norme **");
+	spca506_Initi2c(gspca_dev);
+	/* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */
+	/* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
+	/* and exclude SAA7113 reserved channel set default 0 otherwise */
+	if (norme & V4L2_STD_NTSC)
+		setbit0 = 0x01;
+	if (channel == 4 || channel == 5 || channel > 9)
+		channel = 0;
+	if (channel < 4)
+		setbit1 = 0x02;
+	videomask = (0x48 | setbit0 | setbit1);
+	reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);
+	spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);
+
+	if (norme & V4L2_STD_NTSC)
+		spca506_WriteI2c(gspca_dev, 0x33, 0x0e);
+					/* Chrominance Control NTSC N */
+	else if (norme & V4L2_STD_SECAM)
+		spca506_WriteI2c(gspca_dev, 0x53, 0x0e);
+					/* Chrominance Control SECAM */
+	else
+		spca506_WriteI2c(gspca_dev, 0x03, 0x0e);
+					/* Chrominance Control PAL BGHIV */
+
+	sd->norme = norme;
+	sd->channel = channel;
+	PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask);
+	PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel);
+}
+
+static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,
+				  __u16 *norme, __u16 *channel)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Read the register is not so good value change so
+	   we use your own copy in spca50x struct */
+	*norme = sd->norme;
+	*channel = sd->channel;
+	PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel);
+}
+
+static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,
+			    __u16 xmult, __u16 ymult)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	PDEBUG(D_STREAM, "** SetSize **");
+	reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);
+	/* Soft snap 0x40 Hard 0x41 */
+	reg_w(dev, 0x04, 0x41, 0x0001);
+	reg_w(dev, 0x04, 0x00, 0x0002);
+	/* reserved */
+	reg_w(dev, 0x04, 0x00, 0x0003);
+
+	/* reserved */
+	reg_w(dev, 0x04, 0x00, 0x0004);
+	/* reserved */
+	reg_w(dev, 0x04, 0x01, 0x0005);
+	/* reserced */
+	reg_w(dev, 0x04, xmult, 0x0006);
+	/* reserved */
+	reg_w(dev, 0x04, ymult, 0x0007);
+	/* compression 1 */
+	reg_w(dev, 0x04, 0x00, 0x0008);
+	/* T=64 -> 2 */
+	reg_w(dev, 0x04, 0x00, 0x0009);
+	/* threshold2D */
+	reg_w(dev, 0x04, 0x21, 0x000a);
+	/* quantization */
+	reg_w(dev, 0x04, 0x00, 0x000b);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->hue = sd_ctrls[SD_HUE].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x1c, 0x0001);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	/* Init on PAL and composite input0 */
+	spca506_SetNormeInput(gspca_dev, 0, 0);
+	reg_w(dev, 0x03, 0x1c, 0x0001);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	reg_w(dev, 0x05, 0x00, 0x0000);
+	reg_w(dev, 0x05, 0xef, 0x0001);
+	reg_w(dev, 0x05, 0x00, 0x00c1);
+	reg_w(dev, 0x05, 0x00, 0x00c2);
+	reg_w(dev, 0x06, 0x18, 0x0002);
+	reg_w(dev, 0x06, 0xf5, 0x0011);
+	reg_w(dev, 0x06, 0x02, 0x0012);
+	reg_w(dev, 0x06, 0xfb, 0x0013);
+	reg_w(dev, 0x06, 0x00, 0x0014);
+	reg_w(dev, 0x06, 0xa4, 0x0051);
+	reg_w(dev, 0x06, 0x40, 0x0052);
+	reg_w(dev, 0x06, 0x71, 0x0053);
+	reg_w(dev, 0x06, 0x40, 0x0054);
+	/************************************************/
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x60, 0x0000);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	/* for a better reading mx :)	  */
+	/*sdca506_WriteI2c(value,register) */
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, 0x08, 0x01);
+	spca506_WriteI2c(gspca_dev, 0xc0, 0x02);
+						/* input composite video */
+	spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+	spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+	spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+	spca506_WriteI2c(gspca_dev, 0x98, 0x08);
+	spca506_WriteI2c(gspca_dev, 0x03, 0x09);
+	spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+	spca506_WriteI2c(gspca_dev, 0x47, 0x0b);
+	spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+	spca506_WriteI2c(gspca_dev, 0x03, 0x0e);	/* Chroma Pal adjust */
+	spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+	spca506_WriteI2c(gspca_dev, 0x0c, 0x11);
+	spca506_WriteI2c(gspca_dev, 0xb8, 0x12);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x13);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x14);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x15);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x16);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x17);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+	spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+	spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+	spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+	spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+	spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+	spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+	spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+	PDEBUG(D_STREAM, "** Close Init *");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u16 norme;
+	__u16 channel;
+
+	/**************************************/
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x60, 0x0000);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+
+	/*sdca506_WriteI2c(value,register) */
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, 0x08, 0x01);	/* Increment Delay */
+/*	spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */
+	spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+						/* Analog Input Control 2 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+						/* Analog Input Control 3 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+						/* Analog Input Control 4 */
+	spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+					/* Horizontal Sync Start 0xe9-0x0d */
+	spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+					/* Horizontal Sync Stop  0x0d-0xf0 */
+
+	spca506_WriteI2c(gspca_dev, 0x98, 0x08);	/* Sync Control */
+/*		Defaults value			*/
+	spca506_WriteI2c(gspca_dev, 0x03, 0x09);	/* Luminance Control */
+	spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+						/* Luminance Brightness */
+	spca506_WriteI2c(gspca_dev, 0x47, 0x0b);	/* Luminance Contrast */
+	spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+						/* Chrominance Saturation */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+						/* Chrominance Hue Control */
+	spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+						/* Chrominance Gain Control */
+	/**************************************/
+	spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+						/* Format/Delay Control */
+	spca506_WriteI2c(gspca_dev, 0x0c, 0x11);	/* Output Control 1 */
+	spca506_WriteI2c(gspca_dev, 0xb8, 0x12);	/* Output Control 2 */
+	spca506_WriteI2c(gspca_dev, 0x01, 0x13);	/* Output Control 3 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x14);	/* reserved */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x15);	/* VGATE START */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x16);	/* VGATE STOP */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x17);    /* VGATE Control (MSB) */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+	spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+	spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+	spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+	spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+	spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+	spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+	spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+	/**************************************/
+	reg_w(dev, 0x05, 0x00, 0x0003);
+	reg_w(dev, 0x05, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x10, 0x0001);
+	reg_w(dev, 0x03, 0x78, 0x0000);
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+	case 0:
+		spca506_Setsize(gspca_dev, 0, 0x10, 0x10);
+		break;
+	case 1:
+		spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);
+		break;
+	case 2:
+		spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);
+		break;
+	case 4:
+		spca506_Setsize(gspca_dev, 4, 0x34, 0x34);
+		break;
+	default:
+/*	case 5: */
+		spca506_Setsize(gspca_dev, 5, 0x40, 0x40);
+		break;
+	}
+
+	/* compress setting and size */
+	/* set i2c luma */
+	reg_w(dev, 0x02, 0x01, 0x0000);
+	reg_w(dev, 0x03, 0x12, 0x0000);
+	reg_r(gspca_dev, 0x04, 0x0001, 2);
+	PDEBUG(D_STREAM, "webcam started");
+	spca506_GetNormeInput(gspca_dev, &norme, &channel);
+	spca506_SetNormeInput(gspca_dev, norme, channel);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		yi1 = yi + width;
+		Ui = yi1 + width;
+		Vi = Ui + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA50X_OFFSET_DATA;
+		len -= SPCA50X_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void gethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	gethue(gspca_dev);
+	*val = sd->hue;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")},
+/*	{USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */
+	{USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")},
+	{USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
new file mode 100644
index 0000000..d8cd938
--- /dev/null
+++ b/drivers/media/video/gspca/spca508.c
@@ -0,0 +1,1791 @@
+/*
+ * SPCA508 chip based cameras subdriver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "spca508"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int buflen;
+	unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */
+	unsigned char tmpbuf2[352 * 288 * 2];	/* YUYV */
+
+	unsigned char brightness;
+
+	char subtype;
+#define CreativeVista 0
+#define HamaUSBSightcam 1
+#define HamaUSBSightcam2 2
+#define IntelEasyPCCamera 3
+#define MicroInnovationIC200 4
+#define ViewQuestVQ110 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 128
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 160 * 2,
+		.sizeimage = 160 * 120 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3},
+	{176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 176 * 2,
+		.sizeimage = 176 * 144 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 320 * 2,
+		.sizeimage = 320 * 240 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+		.bytesperline = 352 * 2,
+		.sizeimage = 352 * 288 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+/* Frame packet header offsets for the spca508 */
+#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_OFFSET_COMPRESS 2
+#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_DATA 37
+
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
+/*************** I2c ****************/
+#define SPCA508_INDEX_I2C_BASE 0x8800
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+static const __u16 spca508_init_data[][3] =
+#define IGN(x)			/* nothing */
+{
+	/*  line   URB      value, index */
+	/* 44274  1804 */ {0x0000, 0x870b},
+
+	/* 44299  1805 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+	/* 44324  1806 */ {0x0003, 0x8111},
+	/* Reset compression & memory */
+	/* 44349  1807 */ {0x0000, 0x8110},
+	/* Disable all outputs */
+	/* 44372  1808 */ /* READ {0x0000, 0x8114} -> 0000: 00  */
+	/* 44398  1809 */ {0x0000, 0x8114},
+	/* SW GPIO data */
+	/* 44423  1810 */ {0x0008, 0x8110},
+	/* Enable charge pump output */
+	/* 44527  1811 */ {0x0002, 0x8116},
+	/* 200 kHz pump clock */
+	/* 44555  1812 */
+		/* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+	/* 44590  1813 */ {0x0003, 0x8111},
+	/* Reset compression & memory */
+	/* 44615  1814 */ {0x0000, 0x8111},
+	/* Normal mode (not reset) */
+	/* 44640  1815 */ {0x0098, 0x8110},
+	/* Enable charge pump output, sync.serial,external 2x clock */
+	/* 44665  1816 */ {0x000d, 0x8114},
+	/* SW GPIO data */
+	/* 44690  1817 */ {0x0002, 0x8116},
+	/* 200 kHz pump clock */
+	/* 44715  1818 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+/* --------------------------------------- */
+	/* 44740  1819 */ {0x000f, 0x8402},
+	/* memory bank */
+	/* 44765  1820 */ {0x0000, 0x8403},
+	/* ... address */
+/* --------------------------------------- */
+/* 0x88__ is Synchronous Serial Interface. */
+/* TBD: This table could be expressed more compactly */
+/* using spca508_write_i2c_vector(). */
+/* TBD: Should see if the values in spca50x_i2c_data */
+/* would work with the VQ110 instead of the values */
+/* below. */
+	/* 44790  1821 */ {0x00c0, 0x8804},
+	/* SSI slave addr */
+	/* 44815  1822 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 44838  1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 44862  1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 44888  1825 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 44913  1826 */ {0x0012, 0x8801},
+	/* SSI reg addr */
+	/* 44938  1827 */ {0x0080, 0x8800},
+	/* SSI data to write */
+	/* 44961  1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 44985  1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45009  1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45035  1831 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 45060  1832 */ {0x0012, 0x8801},
+	/* SSI reg addr */
+	/* 45085  1833 */ {0x0000, 0x8800},
+	/* SSI data to write */
+	/* 45108  1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45132  1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45156  1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45182  1837 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 45207  1838 */ {0x0011, 0x8801},
+	/* SSI reg addr */
+	/* 45232  1839 */ {0x0040, 0x8800},
+	/* SSI data to write */
+	/* 45255  1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45279  1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45303  1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45329  1843 */ {0x0008, 0x8802},
+	/* 45354  1844 */ {0x0013, 0x8801},
+	/* 45379  1845 */ {0x0000, 0x8800},
+	/* 45402  1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45426  1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45450  1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45476  1849 */ {0x0008, 0x8802},
+	/* 45501  1850 */ {0x0014, 0x8801},
+	/* 45526  1851 */ {0x0000, 0x8800},
+	/* 45549  1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45573  1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45597  1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45623  1855 */ {0x0008, 0x8802},
+	/* 45648  1856 */ {0x0015, 0x8801},
+	/* 45673  1857 */ {0x0001, 0x8800},
+	/* 45696  1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45720  1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45744  1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45770  1861 */ {0x0008, 0x8802},
+	/* 45795  1862 */ {0x0016, 0x8801},
+	/* 45820  1863 */ {0x0003, 0x8800},
+	/* 45843  1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45867  1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45891  1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45917  1867 */ {0x0008, 0x8802},
+	/* 45942  1868 */ {0x0017, 0x8801},
+	/* 45967  1869 */ {0x0036, 0x8800},
+	/* 45990  1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46014  1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46038  1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46064  1873 */ {0x0008, 0x8802},
+	/* 46089  1874 */ {0x0018, 0x8801},
+	/* 46114  1875 */ {0x00ec, 0x8800},
+	/* 46137  1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46161  1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46185  1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46211  1879 */ {0x0008, 0x8802},
+	/* 46236  1880 */ {0x001a, 0x8801},
+	/* 46261  1881 */ {0x0094, 0x8800},
+	/* 46284  1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46308  1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46332  1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46358  1885 */ {0x0008, 0x8802},
+	/* 46383  1886 */ {0x001b, 0x8801},
+	/* 46408  1887 */ {0x0000, 0x8800},
+	/* 46431  1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46455  1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46479  1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46505  1891 */ {0x0008, 0x8802},
+	/* 46530  1892 */ {0x0027, 0x8801},
+	/* 46555  1893 */ {0x00a2, 0x8800},
+	/* 46578  1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46602  1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46626  1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46652  1897 */ {0x0008, 0x8802},
+	/* 46677  1898 */ {0x0028, 0x8801},
+	/* 46702  1899 */ {0x0040, 0x8800},
+	/* 46725  1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46749  1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46773  1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46799  1903 */ {0x0008, 0x8802},
+	/* 46824  1904 */ {0x002a, 0x8801},
+	/* 46849  1905 */ {0x0084, 0x8800},
+	/* 46872  1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46896  1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+	/* 46920  1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46946  1909 */ {0x0008, 0x8802},
+	/* 46971  1910 */ {0x002b, 0x8801},
+	/* 46996  1911 */ {0x00a8, 0x8800},
+	/* 47019  1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47043  1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47067  1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47093  1915 */ {0x0008, 0x8802},
+	/* 47118  1916 */ {0x002c, 0x8801},
+	/* 47143  1917 */ {0x00fe, 0x8800},
+	/* 47166  1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47190  1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47214  1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47240  1921 */ {0x0008, 0x8802},
+	/* 47265  1922 */ {0x002d, 0x8801},
+	/* 47290  1923 */ {0x0003, 0x8800},
+	/* 47313  1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47337  1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47361  1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47387  1927 */ {0x0008, 0x8802},
+	/* 47412  1928 */ {0x0038, 0x8801},
+	/* 47437  1929 */ {0x0083, 0x8800},
+	/* 47460  1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47484  1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47508  1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47534  1933 */ {0x0008, 0x8802},
+	/* 47559  1934 */ {0x0033, 0x8801},
+	/* 47584  1935 */ {0x0081, 0x8800},
+	/* 47607  1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47631  1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47655  1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47681  1939 */ {0x0008, 0x8802},
+	/* 47706  1940 */ {0x0034, 0x8801},
+	/* 47731  1941 */ {0x004a, 0x8800},
+	/* 47754  1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47778  1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47802  1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47828  1945 */ {0x0008, 0x8802},
+	/* 47853  1946 */ {0x0039, 0x8801},
+	/* 47878  1947 */ {0x0000, 0x8800},
+	/* 47901  1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47925  1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47949  1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47975  1951 */ {0x0008, 0x8802},
+	/* 48000  1952 */ {0x0010, 0x8801},
+	/* 48025  1953 */ {0x00a8, 0x8800},
+	/* 48048  1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48072  1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48096  1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48122  1957 */ {0x0008, 0x8802},
+	/* 48147  1958 */ {0x0006, 0x8801},
+	/* 48172  1959 */ {0x0058, 0x8800},
+	/* 48195  1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48219  1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+	/* 48243  1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48269  1963 */ {0x0008, 0x8802},
+	/* 48294  1964 */ {0x0000, 0x8801},
+	/* 48319  1965 */ {0x0004, 0x8800},
+	/* 48342  1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48366  1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48390  1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48416  1969 */ {0x0008, 0x8802},
+	/* 48441  1970 */ {0x0040, 0x8801},
+	/* 48466  1971 */ {0x0080, 0x8800},
+	/* 48489  1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48513  1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48537  1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48563  1975 */ {0x0008, 0x8802},
+	/* 48588  1976 */ {0x0041, 0x8801},
+	/* 48613  1977 */ {0x000c, 0x8800},
+	/* 48636  1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48660  1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48684  1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48710  1981 */ {0x0008, 0x8802},
+	/* 48735  1982 */ {0x0042, 0x8801},
+	/* 48760  1983 */ {0x000c, 0x8800},
+	/* 48783  1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48807  1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48831  1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48857  1987 */ {0x0008, 0x8802},
+	/* 48882  1988 */ {0x0043, 0x8801},
+	/* 48907  1989 */ {0x0028, 0x8800},
+	/* 48930  1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48954  1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48978  1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49004  1993 */ {0x0008, 0x8802},
+	/* 49029  1994 */ {0x0044, 0x8801},
+	/* 49054  1995 */ {0x0080, 0x8800},
+	/* 49077  1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49101  1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49125  1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49151  1999 */ {0x0008, 0x8802},
+	/* 49176  2000 */ {0x0045, 0x8801},
+	/* 49201  2001 */ {0x0020, 0x8800},
+	/* 49224  2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49248  2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49272  2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49298  2005 */ {0x0008, 0x8802},
+	/* 49323  2006 */ {0x0046, 0x8801},
+	/* 49348  2007 */ {0x0020, 0x8800},
+	/* 49371  2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49395  2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49419  2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49445  2011 */ {0x0008, 0x8802},
+	/* 49470  2012 */ {0x0047, 0x8801},
+	/* 49495  2013 */ {0x0080, 0x8800},
+	/* 49518  2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49542  2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49566  2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49592  2017 */ {0x0008, 0x8802},
+	/* 49617  2018 */ {0x0048, 0x8801},
+	/* 49642  2019 */ {0x004c, 0x8800},
+	/* 49665  2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49689  2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49713  2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49739  2023 */ {0x0008, 0x8802},
+	/* 49764  2024 */ {0x0049, 0x8801},
+	/* 49789  2025 */ {0x0084, 0x8800},
+	/* 49812  2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49836  2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49860  2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49886  2029 */ {0x0008, 0x8802},
+	/* 49911  2030 */ {0x004a, 0x8801},
+	/* 49936  2031 */ {0x0084, 0x8800},
+	/* 49959  2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49983  2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 50007  2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 50033  2035 */ {0x0008, 0x8802},
+	/* 50058  2036 */ {0x004b, 0x8801},
+	/* 50083  2037 */ {0x0084, 0x8800},
+	/* 50106  2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* --------------------------------------- */
+	/* 50132  2039 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 50157  2040 */ {0x0000, 0x8701},
+	/* CKx1 clock delay adj */
+	/* 50182  2041 */ {0x0000, 0x8701},
+	/* CKx1 clock delay adj */
+	/* 50207  2042 */ {0x0001, 0x870c},
+	/* CKOx2 output */
+	/* --------------------------------------- */
+	/* 50232  2043 */ {0x0080, 0x8600},
+	/* Line memory read counter (L) */
+	/* 50257  2044 */ {0x0001, 0x8606},
+	/* reserved */
+	/* 50282  2045 */ {0x0064, 0x8607},
+	/* Line memory read counter (H) 0x6480=25,728 */
+	/* 50307  2046 */ {0x002a, 0x8601},
+	/* CDSP sharp interpolation mode,
+	 *			line sel for color sep, edge enhance enab */
+	/* 50332  2047 */ {0x0000, 0x8602},
+	/* optical black level for user settng = 0 */
+	/* 50357  2048 */ {0x0080, 0x8600},
+	/* Line memory read counter (L) */
+	/* 50382  2049 */ {0x000a, 0x8603},
+	/* optical black level calc mode: auto; optical black offset = 10 */
+	/* 50407  2050 */ {0x00df, 0x865b},
+	/* Horiz offset for valid pixels (L)=0xdf */
+	/* 50432  2051 */ {0x0012, 0x865c},
+	/* Vert offset for valid lines (L)=0x12 */
+
+/* The following two lines seem to be the "wrong" resolution. */
+/* But perhaps these indicate the actual size of the sensor */
+/* rather than the size of the current video mode. */
+	/* 50457  2052 */ {0x0058, 0x865d},
+	/* Horiz valid pixels (*4) (L) = 352 */
+	/* 50482  2053 */ {0x0048, 0x865e},
+	/* Vert valid lines (*4) (L) = 288 */
+
+	/* 50507  2054 */ {0x0015, 0x8608},
+	/* A11 Coef ... */
+	/* 50532  2055 */ {0x0030, 0x8609},
+	/* 50557  2056 */ {0x00fb, 0x860a},
+	/* 50582  2057 */ {0x003e, 0x860b},
+	/* 50607  2058 */ {0x00ce, 0x860c},
+	/* 50632  2059 */ {0x00f4, 0x860d},
+	/* 50657  2060 */ {0x00eb, 0x860e},
+	/* 50682  2061 */ {0x00dc, 0x860f},
+	/* 50707  2062 */ {0x0039, 0x8610},
+	/* 50732  2063 */ {0x0001, 0x8611},
+	/* R offset for white balance ... */
+	/* 50757  2064 */ {0x0000, 0x8612},
+	/* 50782  2065 */ {0x0001, 0x8613},
+	/* 50807  2066 */ {0x0000, 0x8614},
+	/* 50832  2067 */ {0x005b, 0x8651},
+	/* R gain for white balance ... */
+	/* 50857  2068 */ {0x0040, 0x8652},
+	/* 50882  2069 */ {0x0060, 0x8653},
+	/* 50907  2070 */ {0x0040, 0x8654},
+	/* 50932  2071 */ {0x0000, 0x8655},
+	/* 50957  2072 */ {0x0001, 0x863f},
+	/* Fixed gamma correction enable, USB control,
+	 *			 lum filter disable, lum noise clip disable */
+	/* 50982  2073 */ {0x00a1, 0x8656},
+	/* Window1 size 256x256, Windows2 size 64x64,
+	 *		 gamma look-up disable, new edge enhancement enable */
+	/* 51007  2074 */ {0x0018, 0x8657},
+	/* Edge gain high thresh */
+	/* 51032  2075 */ {0x0020, 0x8658},
+	/* Edge gain low thresh */
+	/* 51057  2076 */ {0x000a, 0x8659},
+	/* Edge bandwidth high threshold */
+	/* 51082  2077 */ {0x0005, 0x865a},
+	/* Edge bandwidth low threshold */
+	/* -------------------------------- */
+	/* 51107  2078 */ {0x0030, 0x8112},
+	/* Video drop enable, ISO streaming enable */
+	/* 51130  2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51154  2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51180  2081 */ {0xa908, 0x8802},
+	/* 51205  2082 */ {0x0034, 0x8801},
+	/* SSI reg addr */
+	/* 51230  2083 */ {0x00ca, 0x8800},
+	/* SSI data to write */
+	/* 51253  2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51277  2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51301  2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51327  2087 */ {0x1f08, 0x8802},
+	/* 51352  2088 */ {0x0006, 0x8801},
+	/* 51377  2089 */ {0x0080, 0x8800},
+	/* 51400  2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+/* ----- Read back coefs we wrote earlier. */
+	/* 51424  2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15  */
+	/* 51448  2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30  */
+	/* 51472  2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb  */
+	/* 51496  2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e  */
+	/* 51520  2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce  */
+	/* 51544  2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4  */
+	/* 51568  2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb  */
+	/* 51592  2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc  */
+	/* 51616  2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39  */
+	/* 51640  2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51664  2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51690  2102 */ {0xb008, 0x8802},
+	/* 51715  2103 */ {0x0006, 0x8801},
+	/* 51740  2104 */ {0x007d, 0x8800},
+	/* 51763  2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+
+	/* This chunk is seemingly redundant with */
+	/* earlier commands (A11 Coef...), but if I disable it, */
+	/* the image appears too dark.  Maybe there was some kind of */
+	/* reset since the earlier commands, so this is necessary again. */
+	/* 51789  2106 */ {0x0015, 0x8608},
+	/* 51814  2107 */ {0x0030, 0x8609},
+	/* 51839  2108 */ {0xfffb, 0x860a},
+	/* 51864  2109 */ {0x003e, 0x860b},
+	/* 51889  2110 */ {0xffce, 0x860c},
+	/* 51914  2111 */ {0xfff4, 0x860d},
+	/* 51939  2112 */ {0xffeb, 0x860e},
+	/* 51964  2113 */ {0xffdc, 0x860f},
+	/* 51989  2114 */ {0x0039, 0x8610},
+	/* 52014  2115 */ {0x0018, 0x8657},
+
+	/* 52039  2116 */ {0x0000, 0x8508},
+	/* Disable compression. */
+	/* Previous line was:
+	 * 52039  2116 *  { 0, 0x0021, 0x8508 },  * Enable compression. */
+	/* 52064  2117 */ {0x0032, 0x850b},
+	/* compression stuff */
+	/* 52089  2118 */ {0x0003, 0x8509},
+	/* compression stuff */
+	/* 52114  2119 */ {0x0011, 0x850a},
+	/* compression stuff */
+	/* 52139  2120 */ {0x0021, 0x850d},
+	/* compression stuff */
+	/* 52164  2121 */ {0x0010, 0x850c},
+	/* compression stuff */
+	/* 52189  2122 */ {0x0003, 0x8500},
+	/* *** Video mode: 160x120 */
+	/* 52214  2123 */ {0x0001, 0x8501},
+	/* Hardware-dominated snap control */
+	/* 52239  2124 */ {0x0061, 0x8656},
+	/* Window1 size 128x128, Windows2 size 128x128,
+	 *		gamma look-up disable, new edge enhancement enable */
+	/* 52264  2125 */ {0x0018, 0x8617},
+	/* Window1 start X (*2) */
+	/* 52289  2126 */ {0x0008, 0x8618},
+	/* Window1 start Y (*2) */
+	/* 52314  2127 */ {0x0061, 0x8656},
+	/* Window1 size 128x128, Windows2 size 128x128,
+	 *		gamma look-up disable, new edge enhancement enable */
+	/* 52339  2128 */ {0x0058, 0x8619},
+	/* Window2 start X (*2) */
+	/* 52364  2129 */ {0x0008, 0x861a},
+	/* Window2 start Y (*2) */
+	/* 52389  2130 */ {0x00ff, 0x8615},
+	/* High lum thresh for white balance */
+	/* 52414  2131 */ {0x0000, 0x8616},
+	/* Low lum thresh for white balance */
+	/* 52439  2132 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 52464  2133 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 52487  2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61  */
+	/* 52513  2135 */ {0x0028, 0x8802},
+	/* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+	/* 52536  2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52560  2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 52586  2138 */ {0x1f28, 0x8802},
+	/* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+	/* 52611  2139 */ {0x0010, 0x8801},
+	/* SSI reg addr */
+	/* 52636  2140 */ {0x003e, 0x8800},
+	/* SSI data to write */
+	/* 52659  2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52685  2142 */ {0x0028, 0x8802},
+	/* 52708  2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52732  2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 52758  2145 */ {0x1f28, 0x8802},
+	/* 52783  2146 */ {0x0000, 0x8801},
+	/* 52808  2147 */ {0x001f, 0x8800},
+	/* 52831  2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52857  2149 */ {0x0001, 0x8602},
+	/* optical black level for user settning = 1 */
+
+	/* Original: */
+	/* 52882  2150 */ {0x0023, 0x8700},
+	/* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+	/* 52907  2151 */ {0x000f, 0x8602},
+	/* optical black level for user settning = 15 */
+
+	/* 52932  2152 */ {0x0028, 0x8802},
+	/* 52955  2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52979  2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 53005  2155 */ {0x1f28, 0x8802},
+	/* 53030  2156 */ {0x0010, 0x8801},
+	/* 53055  2157 */ {0x007b, 0x8800},
+	/* 53078  2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 53104  2159 */ {0x002f, 0x8651},
+	/* R gain for white balance ... */
+	/* 53129  2160 */ {0x0080, 0x8653},
+	/* 53152  2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00  */
+	/* 53178  2162 */ {0x0000, 0x8655},
+
+	/* 53203  2163 */ {0x0030, 0x8112},
+	/* Video drop enable, ISO streaming enable */
+	/* 53228  2164 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+	/* 53252  2165 */
+	     /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+	{}
+};
+
+
+/*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+static const __u16 spca508cs110_init_data[][3] = {
+	{0x0000, 0x870b}, /* Reset CTL3 */
+	{0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+	{0x0000, 0x8111}, /* Normal operation on reset */
+	{0x0090, 0x8110},
+		 /* External Clock 2x & Synchronous Serial Interface Output */
+	{0x0020, 0x8112}, /* Video Drop packet enable */
+	{0x0000, 0x8114}, /* Software GPIO output data */
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0003, 0x8114},
+
+	/* Initial sequence Synchronous Serial Interface */
+	{0x000f, 0x8402}, /* Memory bank Address */
+	{0x0000, 0x8403}, /* Memory bank Address */
+	{0x00ba, 0x8804}, /* SSI Slave address */
+	{0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+	{0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+
+	{0x0001, 0x8801},
+	{0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0002, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0003, 0x8801},
+	{0x0027, 0x8805},
+	{0x0001, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0004, 0x8801},
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0005, 0x8801},
+	{0x0003, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0006, 0x8801},
+	{0x001c, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0007, 0x8801},
+	{0x002a, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0002, 0x8704}, /* External input CKIx1 */
+	{0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+	{0x009a, 0x8600}, /* Line memory Read Counter (L) */
+	{0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+	{0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+	{0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+
+	{0x0006, 0x8660}, /* Nibble data + input order */
+
+	{0x000a, 0x8602}, /* Optical black level set to 0x0a */
+/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+
+/* 1962 *  {0, 0x0000, 0x8611},  * 0 R  Offset for white Balance */
+/* 1963 *  {0, 0x0000, 0x8612},  * 1 Gr Offset for white Balance */
+/* 1964 *  {0, 0x0000, 0x8613},  * 1f B  Offset for white Balance */
+/* 1965 *  {0, 0x0000, 0x8614},  * f0 Gb Offset for white Balance */
+
+	{0x0040, 0x8651}, /* 2b BLUE gain for white balance  good at all 60 */
+	{0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+	{0x0035, 0x8653}, /* 26 RED gain for white balance */
+	{0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+	{0x0041, 0x863f},
+	      /* Fixed Gamma correction enabled (makes colours look better) */
+
+/* 2422 */ {0x0000, 0x8655},
+	/* High bits for white balance*****brightness control*** */
+	{}
+};
+
+static const __u16 spca508_sightcam_init_data[][3] = {
+/* This line seems to setup the frame/canvas */
+	/*368  */ {0x000f, 0x8402},
+
+/* Theese 6 lines are needed to startup the webcam */
+	/*398  */ {0x0090, 0x8110},
+	/*399  */ {0x0001, 0x8114},
+	/*400  */ {0x0001, 0x8114},
+	/*401  */ {0x0001, 0x8114},
+	/*402  */ {0x0003, 0x8114},
+	/*403  */ {0x0080, 0x8804},
+
+/* This part seems to make the pictures darker? (autobrightness?) */
+	/*436  */ {0x0001, 0x8801},
+	/*437  */ {0x0004, 0x8800},
+	/*439  */ {0x0003, 0x8801},
+	/*440  */ {0x00e0, 0x8800},
+	/*442  */ {0x0004, 0x8801},
+	/*443  */ {0x00b4, 0x8800},
+	/*445  */ {0x0005, 0x8801},
+	/*446  */ {0x0000, 0x8800},
+
+	/*448  */ {0x0006, 0x8801},
+	/*449  */ {0x00e0, 0x8800},
+	/*451  */ {0x0007, 0x8801},
+	/*452  */ {0x000c, 0x8800},
+
+/* This section is just needed, it probably
+ * does something like the previous section,
+ * but the cam won't start if it's not included.
+ */
+	/*484  */ {0x0014, 0x8801},
+	/*485  */ {0x0008, 0x8800},
+	/*487  */ {0x0015, 0x8801},
+	/*488  */ {0x0067, 0x8800},
+	/*490  */ {0x0016, 0x8801},
+	/*491  */ {0x0000, 0x8800},
+	/*493  */ {0x0017, 0x8801},
+	/*494  */ {0x0020, 0x8800},
+	/*496  */ {0x0018, 0x8801},
+	/*497  */ {0x0044, 0x8800},
+
+/* Makes the picture darker - and the
+ * cam won't start if not included
+ */
+	/*505  */ {0x001e, 0x8801},
+	/*506  */ {0x00ea, 0x8800},
+	/*508  */ {0x001f, 0x8801},
+	/*509  */ {0x0001, 0x8800},
+	/*511  */ {0x0003, 0x8801},
+	/*512  */ {0x00e0, 0x8800},
+
+/* seems to place the colors ontop of each other #1 */
+	/*517  */ {0x0006, 0x8704},
+	/*518  */ {0x0001, 0x870c},
+	/*519  */ {0x0016, 0x8600},
+	/*520  */ {0x0002, 0x8606},
+
+/* if not included the pictures becomes _very_ dark */
+	/*521  */ {0x0064, 0x8607},
+	/*522  */ {0x003a, 0x8601},
+	/*523  */ {0x0000, 0x8602},
+
+/* seems to place the colors ontop of each other #2 */
+	/*524  */ {0x0016, 0x8600},
+	/*525  */ {0x0018, 0x8617},
+	/*526  */ {0x0008, 0x8618},
+	/*527  */ {0x00a1, 0x8656},
+
+/* webcam won't start if not included */
+	/*528  */ {0x0007, 0x865b},
+	/*529  */ {0x0001, 0x865c},
+	/*530  */ {0x0058, 0x865d},
+	/*531  */ {0x0048, 0x865e},
+
+/* adjusts the colors */
+	/*541  */ {0x0049, 0x8651},
+	/*542  */ {0x0040, 0x8652},
+	/*543  */ {0x004c, 0x8653},
+	/*544  */ {0x0040, 0x8654},
+	{}
+};
+
+static const __u16 spca508_sightcam2_init_data[][3] = {
+/* 35 */ {0x0020, 0x8112},
+
+/* 36 */ {0x000f, 0x8402},
+/* 37 */ {0x0000, 0x8403},
+
+/* 38 */ {0x0008, 0x8201},
+/* 39 */ {0x0008, 0x8200},
+/* 40 */ {0x0001, 0x8200},
+/* 43 */ {0x0009, 0x8201},
+/* 44 */ {0x0008, 0x8200},
+/* 45 */ {0x0001, 0x8200},
+/* 48 */ {0x000a, 0x8201},
+/* 49 */ {0x0008, 0x8200},
+/* 50 */ {0x0001, 0x8200},
+/* 53 */ {0x000b, 0x8201},
+/* 54 */ {0x0008, 0x8200},
+/* 55 */ {0x0001, 0x8200},
+/* 58 */ {0x000c, 0x8201},
+/* 59 */ {0x0008, 0x8200},
+/* 60 */ {0x0001, 0x8200},
+/* 63 */ {0x000d, 0x8201},
+/* 64 */ {0x0008, 0x8200},
+/* 65 */ {0x0001, 0x8200},
+/* 68 */ {0x000e, 0x8201},
+/* 69 */ {0x0008, 0x8200},
+/* 70 */ {0x0001, 0x8200},
+/* 73 */ {0x0007, 0x8201},
+/* 74 */ {0x0008, 0x8200},
+/* 75 */ {0x0001, 0x8200},
+/* 78 */ {0x000f, 0x8201},
+/* 79 */ {0x0008, 0x8200},
+/* 80 */ {0x0001, 0x8200},
+
+/* 84 */ {0x0018, 0x8660},
+/* 85 */ {0x0010, 0x8201},
+
+/* 86 */ {0x0008, 0x8200},
+/* 87 */ {0x0001, 0x8200},
+/* 90 */ {0x0011, 0x8201},
+/* 91 */ {0x0008, 0x8200},
+/* 92 */ {0x0001, 0x8200},
+
+/* 95 */ {0x0000, 0x86b0},
+/* 96 */ {0x0034, 0x86b1},
+/* 97 */ {0x0000, 0x86b2},
+/* 98 */ {0x0049, 0x86b3},
+/* 99 */ {0x0000, 0x86b4},
+/* 100 */ {0x0000, 0x86b4},
+
+/* 101 */ {0x0012, 0x8201},
+/* 102 */ {0x0008, 0x8200},
+/* 103 */ {0x0001, 0x8200},
+/* 106 */ {0x0013, 0x8201},
+/* 107 */ {0x0008, 0x8200},
+/* 108 */ {0x0001, 0x8200},
+
+/* 111 */ {0x0001, 0x86b0},
+/* 112 */ {0x00aa, 0x86b1},
+/* 113 */ {0x0000, 0x86b2},
+/* 114 */ {0x00e4, 0x86b3},
+/* 115 */ {0x0000, 0x86b4},
+/* 116 */ {0x0000, 0x86b4},
+
+/* 118 */ {0x0018, 0x8660},
+
+/* 119 */ {0x0090, 0x8110},
+/* 120 */ {0x0001, 0x8114},
+/* 121 */ {0x0001, 0x8114},
+/* 122 */ {0x0001, 0x8114},
+/* 123 */ {0x0003, 0x8114},
+
+/* 124 */ {0x0080, 0x8804},
+/* 157 */ {0x0003, 0x8801},
+/* 158 */ {0x0012, 0x8800},
+/* 160 */ {0x0004, 0x8801},
+/* 161 */ {0x0005, 0x8800},
+/* 163 */ {0x0005, 0x8801},
+/* 164 */ {0x0000, 0x8800},
+/* 166 */ {0x0006, 0x8801},
+/* 167 */ {0x0000, 0x8800},
+/* 169 */ {0x0007, 0x8801},
+/* 170 */ {0x0000, 0x8800},
+/* 172 */ {0x0008, 0x8801},
+/* 173 */ {0x0005, 0x8800},
+/* 175 */ {0x000a, 0x8700},
+/* 176 */ {0x000e, 0x8801},
+/* 177 */ {0x0004, 0x8800},
+/* 179 */ {0x0005, 0x8801},
+/* 180 */ {0x0047, 0x8800},
+/* 182 */ {0x0006, 0x8801},
+/* 183 */ {0x0000, 0x8800},
+/* 185 */ {0x0007, 0x8801},
+/* 186 */ {0x00c0, 0x8800},
+/* 188 */ {0x0008, 0x8801},
+/* 189 */ {0x0003, 0x8800},
+/* 191 */ {0x0013, 0x8801},
+/* 192 */ {0x0001, 0x8800},
+/* 194 */ {0x0009, 0x8801},
+/* 195 */ {0x0000, 0x8800},
+/* 197 */ {0x000a, 0x8801},
+/* 198 */ {0x0000, 0x8800},
+/* 200 */ {0x000b, 0x8801},
+/* 201 */ {0x0000, 0x8800},
+/* 203 */ {0x000c, 0x8801},
+/* 204 */ {0x0000, 0x8800},
+/* 206 */ {0x000e, 0x8801},
+/* 207 */ {0x0004, 0x8800},
+/* 209 */ {0x000f, 0x8801},
+/* 210 */ {0x0000, 0x8800},
+/* 212 */ {0x0010, 0x8801},
+/* 213 */ {0x0006, 0x8800},
+/* 215 */ {0x0011, 0x8801},
+/* 216 */ {0x0006, 0x8800},
+/* 218 */ {0x0012, 0x8801},
+/* 219 */ {0x0000, 0x8800},
+/* 221 */ {0x0013, 0x8801},
+/* 222 */ {0x0001, 0x8800},
+
+/* 224 */ {0x000a, 0x8700},
+/* 225 */ {0x0000, 0x8702},
+/* 226 */ {0x0000, 0x8703},
+/* 227 */ {0x00c2, 0x8704},
+/* 228 */ {0x0001, 0x870c},
+
+/* 229 */ {0x0044, 0x8600},
+/* 230 */ {0x0002, 0x8606},
+/* 231 */ {0x0064, 0x8607},
+/* 232 */ {0x003a, 0x8601},
+/* 233 */ {0x0008, 0x8602},
+/* 234 */ {0x0044, 0x8600},
+/* 235 */ {0x0018, 0x8617},
+/* 236 */ {0x0008, 0x8618},
+/* 237 */ {0x00a1, 0x8656},
+/* 238 */ {0x0004, 0x865b},
+/* 239 */ {0x0002, 0x865c},
+/* 240 */ {0x0058, 0x865d},
+/* 241 */ {0x0048, 0x865e},
+/* 242 */ {0x0012, 0x8608},
+/* 243 */ {0x002c, 0x8609},
+/* 244 */ {0x0002, 0x860a},
+/* 245 */ {0x002c, 0x860b},
+/* 246 */ {0x00db, 0x860c},
+/* 247 */ {0x00f9, 0x860d},
+/* 248 */ {0x00f1, 0x860e},
+/* 249 */ {0x00e3, 0x860f},
+/* 250 */ {0x002c, 0x8610},
+/* 251 */ {0x006c, 0x8651},
+/* 252 */ {0x0041, 0x8652},
+/* 253 */ {0x0059, 0x8653},
+/* 254 */ {0x0040, 0x8654},
+/* 255 */ {0x00fa, 0x8611},
+/* 256 */ {0x00ff, 0x8612},
+/* 257 */ {0x00f8, 0x8613},
+/* 258 */ {0x0000, 0x8614},
+/* 259 */ {0x0001, 0x863f},
+/* 260 */ {0x0000, 0x8640},
+/* 261 */ {0x0026, 0x8641},
+/* 262 */ {0x0045, 0x8642},
+/* 263 */ {0x0060, 0x8643},
+/* 264 */ {0x0075, 0x8644},
+/* 265 */ {0x0088, 0x8645},
+/* 266 */ {0x009b, 0x8646},
+/* 267 */ {0x00b0, 0x8647},
+/* 268 */ {0x00c5, 0x8648},
+/* 269 */ {0x00d2, 0x8649},
+/* 270 */ {0x00dc, 0x864a},
+/* 271 */ {0x00e5, 0x864b},
+/* 272 */ {0x00eb, 0x864c},
+/* 273 */ {0x00f0, 0x864d},
+/* 274 */ {0x00f6, 0x864e},
+/* 275 */ {0x00fa, 0x864f},
+/* 276 */ {0x00ff, 0x8650},
+/* 277 */ {0x0060, 0x8657},
+/* 278 */ {0x0010, 0x8658},
+/* 279 */ {0x0018, 0x8659},
+/* 280 */ {0x0005, 0x865a},
+/* 281 */ {0x0018, 0x8660},
+/* 282 */ {0x0003, 0x8509},
+/* 283 */ {0x0011, 0x850a},
+/* 284 */ {0x0032, 0x850b},
+/* 285 */ {0x0010, 0x850c},
+/* 286 */ {0x0021, 0x850d},
+/* 287 */ {0x0001, 0x8500},
+/* 288 */ {0x0000, 0x8508},
+/* 289 */ {0x0012, 0x8608},
+/* 290 */ {0x002c, 0x8609},
+/* 291 */ {0x0002, 0x860a},
+/* 292 */ {0x0039, 0x860b},
+/* 293 */ {0x00d0, 0x860c},
+/* 294 */ {0x00f7, 0x860d},
+/* 295 */ {0x00ed, 0x860e},
+/* 296 */ {0x00db, 0x860f},
+/* 297 */ {0x0039, 0x8610},
+/* 298 */ {0x0012, 0x8657},
+/* 299 */ {0x000c, 0x8619},
+/* 300 */ {0x0004, 0x861a},
+/* 301 */ {0x00a1, 0x8656},
+/* 302 */ {0x00c8, 0x8615},
+/* 303 */ {0x0032, 0x8616},
+
+/* 306 */ {0x0030, 0x8112},
+/* 313 */ {0x0020, 0x8112},
+/* 314 */ {0x0020, 0x8112},
+/* 315 */ {0x000f, 0x8402},
+/* 316 */ {0x0000, 0x8403},
+
+/* 317 */ {0x0090, 0x8110},
+/* 318 */ {0x0001, 0x8114},
+/* 319 */ {0x0001, 0x8114},
+/* 320 */ {0x0001, 0x8114},
+/* 321 */ {0x0003, 0x8114},
+/* 322 */ {0x0080, 0x8804},
+
+/* 355 */ {0x0003, 0x8801},
+/* 356 */ {0x0012, 0x8800},
+/* 358 */ {0x0004, 0x8801},
+/* 359 */ {0x0005, 0x8800},
+/* 361 */ {0x0005, 0x8801},
+/* 362 */ {0x0047, 0x8800},
+/* 364 */ {0x0006, 0x8801},
+/* 365 */ {0x0000, 0x8800},
+/* 367 */ {0x0007, 0x8801},
+/* 368 */ {0x00c0, 0x8800},
+/* 370 */ {0x0008, 0x8801},
+/* 371 */ {0x0003, 0x8800},
+/* 373 */ {0x000a, 0x8700},
+/* 374 */ {0x000e, 0x8801},
+/* 375 */ {0x0004, 0x8800},
+/* 377 */ {0x0005, 0x8801},
+/* 378 */ {0x0047, 0x8800},
+/* 380 */ {0x0006, 0x8801},
+/* 381 */ {0x0000, 0x8800},
+/* 383 */ {0x0007, 0x8801},
+/* 384 */ {0x00c0, 0x8800},
+/* 386 */ {0x0008, 0x8801},
+/* 387 */ {0x0003, 0x8800},
+/* 389 */ {0x0013, 0x8801},
+/* 390 */ {0x0001, 0x8800},
+/* 392 */ {0x0009, 0x8801},
+/* 393 */ {0x0000, 0x8800},
+/* 395 */ {0x000a, 0x8801},
+/* 396 */ {0x0000, 0x8800},
+/* 398 */ {0x000b, 0x8801},
+/* 399 */ {0x0000, 0x8800},
+/* 401 */ {0x000c, 0x8801},
+/* 402 */ {0x0000, 0x8800},
+/* 404 */ {0x000e, 0x8801},
+/* 405 */ {0x0004, 0x8800},
+/* 407 */ {0x000f, 0x8801},
+/* 408 */ {0x0000, 0x8800},
+/* 410 */ {0x0010, 0x8801},
+/* 411 */ {0x0006, 0x8800},
+/* 413 */ {0x0011, 0x8801},
+/* 414 */ {0x0006, 0x8800},
+/* 416 */ {0x0012, 0x8801},
+/* 417 */ {0x0000, 0x8800},
+/* 419 */ {0x0013, 0x8801},
+/* 420 */ {0x0001, 0x8800},
+/* 422 */ {0x000a, 0x8700},
+/* 423 */ {0x0000, 0x8702},
+/* 424 */ {0x0000, 0x8703},
+/* 425 */ {0x00c2, 0x8704},
+/* 426 */ {0x0001, 0x870c},
+/* 427 */ {0x0044, 0x8600},
+/* 428 */ {0x0002, 0x8606},
+/* 429 */ {0x0064, 0x8607},
+/* 430 */ {0x003a, 0x8601},
+/* 431 */ {0x0008, 0x8602},
+/* 432 */ {0x0044, 0x8600},
+/* 433 */ {0x0018, 0x8617},
+/* 434 */ {0x0008, 0x8618},
+/* 435 */ {0x00a1, 0x8656},
+/* 436 */ {0x0004, 0x865b},
+/* 437 */ {0x0002, 0x865c},
+/* 438 */ {0x0058, 0x865d},
+/* 439 */ {0x0048, 0x865e},
+/* 440 */ {0x0012, 0x8608},
+/* 441 */ {0x002c, 0x8609},
+/* 442 */ {0x0002, 0x860a},
+/* 443 */ {0x002c, 0x860b},
+/* 444 */ {0x00db, 0x860c},
+/* 445 */ {0x00f9, 0x860d},
+/* 446 */ {0x00f1, 0x860e},
+/* 447 */ {0x00e3, 0x860f},
+/* 448 */ {0x002c, 0x8610},
+/* 449 */ {0x006c, 0x8651},
+/* 450 */ {0x0041, 0x8652},
+/* 451 */ {0x0059, 0x8653},
+/* 452 */ {0x0040, 0x8654},
+/* 453 */ {0x00fa, 0x8611},
+/* 454 */ {0x00ff, 0x8612},
+/* 455 */ {0x00f8, 0x8613},
+/* 456 */ {0x0000, 0x8614},
+/* 457 */ {0x0001, 0x863f},
+/* 458 */ {0x0000, 0x8640},
+/* 459 */ {0x0026, 0x8641},
+/* 460 */ {0x0045, 0x8642},
+/* 461 */ {0x0060, 0x8643},
+/* 462 */ {0x0075, 0x8644},
+/* 463 */ {0x0088, 0x8645},
+/* 464 */ {0x009b, 0x8646},
+/* 465 */ {0x00b0, 0x8647},
+/* 466 */ {0x00c5, 0x8648},
+/* 467 */ {0x00d2, 0x8649},
+/* 468 */ {0x00dc, 0x864a},
+/* 469 */ {0x00e5, 0x864b},
+/* 470 */ {0x00eb, 0x864c},
+/* 471 */ {0x00f0, 0x864d},
+/* 472 */ {0x00f6, 0x864e},
+/* 473 */ {0x00fa, 0x864f},
+/* 474 */ {0x00ff, 0x8650},
+/* 475 */ {0x0060, 0x8657},
+/* 476 */ {0x0010, 0x8658},
+/* 477 */ {0x0018, 0x8659},
+/* 478 */ {0x0005, 0x865a},
+/* 479 */ {0x0018, 0x8660},
+/* 480 */ {0x0003, 0x8509},
+/* 481 */ {0x0011, 0x850a},
+/* 482 */ {0x0032, 0x850b},
+/* 483 */ {0x0010, 0x850c},
+/* 484 */ {0x0021, 0x850d},
+/* 485 */ {0x0001, 0x8500},
+/* 486 */ {0x0000, 0x8508},
+
+/* 487 */ {0x0012, 0x8608},
+/* 488 */ {0x002c, 0x8609},
+/* 489 */ {0x0002, 0x860a},
+/* 490 */ {0x0039, 0x860b},
+/* 491 */ {0x00d0, 0x860c},
+/* 492 */ {0x00f7, 0x860d},
+/* 493 */ {0x00ed, 0x860e},
+/* 494 */ {0x00db, 0x860f},
+/* 495 */ {0x0039, 0x8610},
+/* 496 */ {0x0012, 0x8657},
+/* 497 */ {0x0064, 0x8619},
+
+/* This line starts it all, it is not needed here */
+/* since it has been build into the driver */
+/* jfm: don't start now */
+/* 590  *  {0x0030, 0x8112}, */
+	{}
+};
+
+/*
+ * Initialization data for Creative Webcam Vista
+ */
+static const __u16 spca508_vista_init_data[][3] = {
+	{0x0008, 0x8200},	/* Clear register */
+	{0x0000, 0x870b},	/* Reset CTL3 */
+	{0x0020, 0x8112},	/* Video Drop packet enable */
+	{0x0003, 0x8111},  /* Soft Reset compression, memory, TG & CDSP */
+	{0x0000, 0x8110},	/* Disable everything */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8114},
+
+	{0x0003, 0x8111},
+	{0x0000, 0x8111},
+	{0x0090, 0x8110},  /* Enable: SSI output, External 2X clock output */
+	{0x0020, 0x8112},
+	{0x0000, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0003, 0x8114},
+
+	{0x000f, 0x8402},	/* Memory bank Address */
+	{0x0000, 0x8403},	/* Memory bank Address */
+	{0x00ba, 0x8804},	/* SSI Slave address */
+	{0x0010, 0x8802},	/* 93.75kHz SSI Clock Two DataByte */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},	/* Will write 2 bytes (DATA1+DATA2) */
+	{0x0020, 0x8801},	/* Register address for SSI read/write */
+	{0x0044, 0x8805},	/* DATA2 */
+	{0x0004, 0x8800},	/* DATA1 -> write triggered */
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0009, 0x8801},
+	{0x0042, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x003c, 0x8801},
+	{0x0001, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0001, 0x8801},
+	{0x000a, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0002, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0003, 0x8801},
+	{0x0027, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0004, 0x8801},
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0005, 0x8801},
+	{0x0003, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0006, 0x8801},
+	{0x001c, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0007, 0x8801},
+	{0x002a, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x000e, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0028, 0x8801},
+	{0x002e, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0039, 0x8801},
+	{0x0013, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x003b, 0x8801},
+	{0x000c, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0035, 0x8801},
+	{0x0028, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0009, 0x8801},
+	{0x0042, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	{0x0050, 0x8703},
+	{0x0002, 0x8704},	/* External input CKIx1 */
+	{0x0001, 0x870C},	/* Select CKOx2 output */
+	{0x009A, 0x8600},	/* Line memory Read Counter (L) */
+	{0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
+	{0x0023, 0x8601},
+	{0x0010, 0x8602},
+	{0x000A, 0x8603},
+	{0x009A, 0x8600},
+	{0x0001, 0x865B},	/* 1 Horizontal Offset for Valid Pixel(L) */
+	{0x0003, 0x865C},	/* Vertical offset for valid lines (L) */
+	{0x0058, 0x865D},	/* Horizontal valid pixels window (L) */
+	{0x0048, 0x865E},	/* Vertical valid lines window (L) */
+	{0x0000, 0x865F},
+
+	{0x0006, 0x8660},
+		    /* Enable nibble data input, select nibble input order */
+
+	{0x0013, 0x8608},	/* A11 Coeficients for color correction */
+	{0x0028, 0x8609},
+		    /* Note: these values are confirmed at the end of array */
+	{0x0005, 0x860A},	/* ... */
+	{0x0025, 0x860B},
+	{0x00E1, 0x860C},
+	{0x00FA, 0x860D},
+	{0x00F4, 0x860E},
+	{0x00E8, 0x860F},
+	{0x0025, 0x8610},	/* A33 Coef. */
+	{0x00FC, 0x8611},	/* White balance offset: R */
+	{0x0001, 0x8612},	/* White balance offset: Gr */
+	{0x00FE, 0x8613},	/* White balance offset: B */
+	{0x0000, 0x8614},	/* White balance offset: Gb */
+
+	{0x0064, 0x8651},	/* R gain for white balance (L) */
+	{0x0040, 0x8652},	/* Gr gain for white balance (L) */
+	{0x0066, 0x8653},	/* B gain for white balance (L) */
+	{0x0040, 0x8654},	/* Gb gain for white balance (L) */
+	{0x0001, 0x863F},	/* Enable fixed gamma correction */
+
+	{0x00A1, 0x8656},	/* Size - Window1: 256x256, Window2: 128x128 */
+	/* UV division: UV no change, Enable New edge enhancement */
+	{0x0018, 0x8657},	/* Edge gain high threshold */
+	{0x0020, 0x8658},	/* Edge gain low threshold */
+	{0x000A, 0x8659},	/* Edge bandwidth high threshold */
+	{0x0005, 0x865A},	/* Edge bandwidth low threshold */
+	{0x0064, 0x8607},	/* UV filter enable */
+
+	{0x0016, 0x8660},
+	{0x0000, 0x86B0},	/* Bad pixels compensation address */
+	{0x00DC, 0x86B1},	/* X coord for bad pixels compensation (L) */
+	{0x0000, 0x86B2},
+	{0x0009, 0x86B3},	/* Y coord for bad pixels compensation (L) */
+	{0x0000, 0x86B4},
+
+	{0x0001, 0x86B0},
+	{0x00F5, 0x86B1},
+	{0x0000, 0x86B2},
+	{0x00C6, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0002, 0x86B0},
+	{0x001C, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D7, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0003, 0x86B0},
+	{0x001C, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D8, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0004, 0x86B0},
+	{0x001D, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D8, 0x86B3},
+	{0x0000, 0x86B4},
+	{0x001E, 0x8660},
+
+	/* READ { 0, 0x0000, 0x8608 } ->
+		0000: 13  */
+	/* READ { 0, 0x0000, 0x8609 } ->
+		0000: 28  */
+	/* READ { 0, 0x0000, 0x8610 } ->
+		0000: 05  */
+	/* READ { 0, 0x0000, 0x8611 } ->
+		0000: 25  */
+	/* READ { 0, 0x0000, 0x8612 } ->
+		0000: e1  */
+	/* READ { 0, 0x0000, 0x8613 } ->
+		0000: fa  */
+	/* READ { 0, 0x0000, 0x8614 } ->
+		0000: f4  */
+	/* READ { 0, 0x0000, 0x8615 } ->
+		0000: e8  */
+	/* READ { 0, 0x0000, 0x8616 } ->
+		0000: 25  */
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+			__u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,		/* request */
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
+		index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+	return ret;
+}
+
+/* read 1 byte */
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct gspca_dev *gspca_dev,
+			__u16 index)	/* wIndex */
+{
+	int ret;
+
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,			/* register */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			gspca_dev->usb_buf, 1,
+			500);			/* timeout */
+	PDEBUG(D_USBI, "reg read i:%04x --> %02x",
+		index, gspca_dev->usb_buf[0]);
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+		return ret;
+	}
+	return gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][1] != 0) {
+		ret = reg_write(dev, data[i][1], data[i][0]);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+	return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 product;
+	int data1, data2;
+
+	product = id->idProduct;
+	switch (id->idVendor) {
+	case 0x0130:		/* Clone webcam */
+/*		switch (product) { */
+/*		case 0x0130: */
+			sd->subtype = HamaUSBSightcam;	/* same as Hama 0010 */
+/*			break; */
+/*		} */
+		break;
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x4018: */
+			sd->subtype = CreativeVista;
+/*			break; */
+/*		} */
+		break;
+	case 0x0461:		/* MicroInnovation */
+/*		switch (product) { */
+/*		case 0x0815: */
+			sd->subtype = MicroInnovationIC200;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*		switch (product) { */
+/*		case 0x110: */
+			sd->subtype = ViewQuestVQ110;
+/*			break; */
+/*		} */
+		break;
+	case 0x0af9:		/* Hama cameras */
+		switch (product) {
+		case 0x0010:
+			sd->subtype = HamaUSBSightcam;
+			break;
+		case 0x0011:
+			sd->subtype = HamaUSBSightcam2;
+			break;
+		}
+		break;
+	case 0x8086:		/* Intel */
+/*		switch (product) { */
+/*		case 0x0110: */
+			sd->subtype = IntelEasyPCCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	/* Read from global register the USB product and vendor IDs, just to
+	 * prove that we can communicate with the device.  This works, which
+	 * confirms at we are communicating properly and that the device
+	 * is a 508. */
+	data1 = reg_read(gspca_dev, 0x8104);
+	data2 = reg_read(gspca_dev, 0x8105);
+	PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1);
+
+	data1 = reg_read(gspca_dev, 0x8106);
+	data2 = reg_read(gspca_dev, 0x8107);
+	PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1);
+
+	data1 = reg_read(gspca_dev, 0x8621);
+	PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = ARRAY_SIZE(sif_mode);
+	sd->brightness = BRIGHTNESS_DEF;
+
+	switch (sd->subtype) {
+	case ViewQuestVQ110:
+		if (write_vector(gspca_dev, spca508_init_data))
+			return -1;
+		break;
+	default:
+/*	case MicroInnovationIC200: */
+/*	case IntelEasyPCCamera: */
+		if (write_vector(gspca_dev, spca508cs110_init_data))
+			return -1;
+		break;
+	case HamaUSBSightcam:
+		if (write_vector(gspca_dev, spca508_sightcam_init_data))
+			return -1;
+		break;
+	case HamaUSBSightcam2:
+		if (write_vector(gspca_dev, spca508_sightcam2_init_data))
+			return -1;
+		break;
+	case CreativeVista:
+		if (write_vector(gspca_dev, spca508_vista_init_data))
+			return -1;
+		break;
+	}
+	return 0;			/* success */
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+/*	write_vector(gspca_dev, spca508_open_data); */
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	int mode;
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	reg_write(gspca_dev->dev, 0x8500, mode);
+	switch (mode) {
+	case 0:
+	case 1:
+		reg_write(gspca_dev->dev, 0x8700, 0x28);	/* clock */
+		break;
+	default:
+/*	case 2: */
+/*	case 3: */
+		reg_write(gspca_dev->dev, 0x8700, 0x23);	/* clock */
+		break;
+	}
+	reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Video ISO disable, Video Drop Packet enable: */
+	reg_write(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YUVY per line to YUYV (YUV 4:2:2) */
+static void yuvy_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		Ui = yi + width;
+		Vi = Ui + width / 2;
+		yi1 = Vi + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yuvy_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA508_OFFSET_DATA;
+		len -= SPCA508_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 brightness = sd->brightness;
+
+	/* MX seem contrast */
+	reg_write(gspca_dev->dev, 0x8651, brightness);
+	reg_write(gspca_dev->dev, 0x8652, brightness);
+	reg_write(gspca_dev->dev, 0x8653, brightness);
+	reg_write(gspca_dev->dev, 0x8654, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = reg_read(gspca_dev, 0x8651);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")},
+	{USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")},
+	{USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")},
+	{USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")},
+	{USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")},
+	{USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")},
+	{USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
new file mode 100644
index 0000000..b659bd0
--- /dev/null
+++ b/drivers/media/video/gspca/spca561.c
@@ -0,0 +1,1052 @@
+/*
+ * Sunplus spca561 subdriver
+ *
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "spca561"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned short contrast;
+	__u8 brightness;
+	__u8 autogain;
+
+	__u8 chip_revision;
+	signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 0,
+	  .maximum = 63,
+	  .step = 1,
+	  .default_value = 32,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0x3fff,
+	  .step = 1,
+	  .default_value = 0x2000,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+#define SD_AUTOGAIN 2
+	{
+	 {
+	  .id = V4L2_CID_AUTOGAIN,
+	  .type = V4L2_CTRL_TYPE_BOOLEAN,
+	  .name = "Auto Gain",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setautogain,
+	 .get = sd_getautogain,
+	 },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3},
+	{176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 4 / 8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 4 / 8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+/*
+ * Initialization data
+ * I'm not very sure how to split initialization from open data
+ * chunks. For now, we'll consider everything as initialization
+ */
+/* Frame packet header offsets for the spca561 */
+#define SPCA561_OFFSET_SNAP 1
+#define SPCA561_OFFSET_TYPE 2
+#define SPCA561_OFFSET_COMPRESS 3
+#define SPCA561_OFFSET_FRAMSEQ   4
+#define SPCA561_OFFSET_GPIO 5
+#define SPCA561_OFFSET_USBBUFF 6
+#define SPCA561_OFFSET_WIN2GRAVE 7
+#define SPCA561_OFFSET_WIN2RAVE 8
+#define SPCA561_OFFSET_WIN2BAVE 9
+#define SPCA561_OFFSET_WIN2GBAVE 10
+#define SPCA561_OFFSET_WIN1GRAVE 11
+#define SPCA561_OFFSET_WIN1RAVE 12
+#define SPCA561_OFFSET_WIN1BAVE 13
+#define SPCA561_OFFSET_WIN1GBAVE 14
+#define SPCA561_OFFSET_FREQ 15
+#define SPCA561_OFFSET_VSYNC 16
+#define SPCA561_OFFSET_DATA 1
+#define SPCA561_INDEX_I2C_BASE 0x8800
+#define SPCA561_SNAPBIT 0x20
+#define SPCA561_SNAPCTRL 0x40
+enum {
+	Rev072A = 0,
+	Rev012A,
+};
+
+static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			      0,		/* request */
+			      USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][2])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+
+	i = 0;
+	while (data[i][1] != 0) {
+		reg_w_val(dev, data[i][1], data[i][0]);
+		i++;
+	}
+}
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 index, __u16 length)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,			/* value */
+			index, gspca_dev->usb_buf, length, 500);
+}
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+		      __u16 index, const __u8 *buffer, __u16 len)
+{
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,			/* value */
+			index, gspca_dev->usb_buf, len, 500);
+}
+
+static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
+{
+	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+	reg_w_val(gspca_dev->dev, mode, 0x8802);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
+{
+	int retry = 60;
+	__u8 DataLow;
+	__u8 DataHight;
+
+	DataLow = valeur;
+	DataHight = valeur >> 8;
+	reg_w_val(gspca_dev->dev, reg, 0x8801);
+	reg_w_val(gspca_dev->dev, DataLow, 0x8805);
+	reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+	while (retry--) {
+		reg_r(gspca_dev, 0x8803, 1);
+		if (!gspca_dev->usb_buf[0])
+			break;
+	}
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+	int retry = 60;
+	__u8 value;
+	__u8 vallsb;
+
+	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+	reg_w_val(gspca_dev->dev, reg, 0x8801);
+	reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+	while (retry--) {
+		reg_r(gspca_dev, 0x8803, 1);
+		if (!gspca_dev->usb_buf)
+			break;
+	}
+	if (retry == 0)
+		return -1;
+	reg_r(gspca_dev, 0x8800, 1);
+	value = gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8805, 1);
+	vallsb = gspca_dev->usb_buf[0];
+	return ((int) value << 8) | vallsb;
+}
+
+static const __u16 spca561_init_data[][2] = {
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0001, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8112},	/* Some kind of reset */
+	{0x0003, 0x8701},	/* PCLK clock delay adjustment */
+	{0x0001, 0x8703},	/* HSYNC from cmos inverted */
+	{0x0011, 0x8118},	/* Enable and conf sensor */
+	{0x0001, 0x8118},	/* Conf sensor */
+	{0x0092, 0x8804},	/* I know nothing about these */
+	{0x0010, 0x8802},	/* 0x88xx registers, so I won't */
+	/***************/
+	{0x000d, 0x8805},	/* sensor default setting */
+	{0x0001, 0x8801},	/* 1 <- 0x0d */
+	{0x0000, 0x8800},
+	{0x0018, 0x8805},
+	{0x0002, 0x8801},	/* 2 <- 0x18 */
+	{0x0000, 0x8800},
+	{0x0065, 0x8805},
+	{0x0004, 0x8801},	/* 4 <- 0x01 0x65 */
+	{0x0001, 0x8800},
+	{0x0021, 0x8805},
+	{0x0005, 0x8801},	/* 5 <- 0x21 */
+	{0x0000, 0x8800},
+	{0x00aa, 0x8805},
+	{0x0007, 0x8801},	/* 7 <- 0xaa */
+	{0x0000, 0x8800},
+	{0x0004, 0x8805},
+	{0x0020, 0x8801},	/* 0x20 <- 0x15 0x04 */
+	{0x0015, 0x8800},
+	{0x0002, 0x8805},
+	{0x0039, 0x8801},	/* 0x39 <- 0x02 */
+	{0x0000, 0x8800},
+	{0x0010, 0x8805},
+	{0x0035, 0x8801},	/* 0x35 <- 0x10 */
+	{0x0000, 0x8800},
+	{0x0049, 0x8805},
+	{0x0009, 0x8801},	/* 0x09 <- 0x10 0x49 */
+	{0x0010, 0x8800},
+	{0x000b, 0x8805},
+	{0x0028, 0x8801},	/* 0x28 <- 0x0b */
+	{0x0000, 0x8800},
+	{0x000f, 0x8805},
+	{0x003b, 0x8801},	/* 0x3b <- 0x0f */
+	{0x0000, 0x8800},
+	{0x0000, 0x8805},
+	{0x003c, 0x8801},	/* 0x3c <- 0x00 */
+	{0x0000, 0x8800},
+	/***************/
+	{0x0018, 0x8601},	/* Pixel/line selection for color separation */
+	{0x0000, 0x8602},	/* Optical black level for user setting */
+	{0x0060, 0x8604},	/* Optical black horizontal offset */
+	{0x0002, 0x8605},	/* Optical black vertical offset */
+	{0x0000, 0x8603},	/* Non-automatic optical black level */
+	{0x0002, 0x865b},	/* Horizontal offset for valid pixels */
+	{0x0000, 0x865f},	/* Vertical valid pixels window (x2) */
+	{0x00b0, 0x865d},	/* Horizontal valid pixels window (x2) */
+	{0x0090, 0x865e},	/* Vertical valid lines window (x2) */
+	{0x00e0, 0x8406},	/* Memory buffer threshold */
+	{0x0000, 0x8660},	/* Compensation memory stuff */
+	{0x0002, 0x8201},	/* Output address for r/w serial EEPROM */
+	{0x0008, 0x8200},	/* Clear valid bit for serial EEPROM */
+	{0x0001, 0x8200},	/* OprMode to be executed by hardware */
+	{0x0007, 0x8201},	/* Output address for r/w serial EEPROM */
+	{0x0008, 0x8200},	/* Clear valid bit for serial EEPROM */
+	{0x0001, 0x8200},	/* OprMode to be executed by hardware */
+	{0x0010, 0x8660},	/* Compensation memory stuff */
+	{0x0018, 0x8660},	/* Compensation memory stuff */
+
+	{0x0004, 0x8611},	/* R offset for white balance */
+	{0x0004, 0x8612},	/* Gr offset for white balance */
+	{0x0007, 0x8613},	/* B offset for white balance */
+	{0x0000, 0x8614},	/* Gb offset for white balance */
+	{0x008c, 0x8651},	/* R gain for white balance */
+	{0x008c, 0x8652},	/* Gr gain for white balance */
+	{0x00b5, 0x8653},	/* B gain for white balance */
+	{0x008c, 0x8654},	/* Gb gain for white balance */
+	{0x0002, 0x8502},	/* Maximum average bit rate stuff */
+
+	{0x0011, 0x8802},
+	{0x0087, 0x8700},	/* Set master clock (96Mhz????) */
+	{0x0081, 0x8702},	/* Master clock output enable */
+
+	{0x0000, 0x8500},	/* Set image type (352x288 no compression) */
+	/* Originally was 0x0010 (352x288 compression) */
+
+	{0x0002, 0x865b},	/* Horizontal offset for valid pixels */
+	{0x0003, 0x865c},	/* Vertical offset for valid lines */
+	/***************//* sensor active */
+	{0x0003, 0x8801},	/* 0x03 <- 0x01 0x21 //289 */
+	{0x0021, 0x8805},
+	{0x0001, 0x8800},
+	{0x0004, 0x8801},	/* 0x04 <- 0x01 0x65 //357 */
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0005, 0x8801},	/* 0x05 <- 0x2f */
+	{0x002f, 0x8805},
+	{0x0000, 0x8800},
+	{0x0006, 0x8801},	/* 0x06 <- 0 */
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x000a, 0x8801},	/* 0x0a <- 2 */
+	{0x0002, 0x8805},
+	{0x0000, 0x8800},
+	{0x0009, 0x8801},	/* 0x09 <- 0x1061 */
+	{0x0061, 0x8805},
+	{0x0010, 0x8800},
+	{0x0035, 0x8801},	/* 0x35 <-0x14 */
+	{0x0014, 0x8805},
+	{0x0000, 0x8800},
+	{0x0030, 0x8112},	/* ISO and drop packet enable */
+	{0x0000, 0x8112},	/* Some kind of reset ???? */
+	{0x0009, 0x8118},	/* Enable sensor and set standby */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0001, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8112},	/* Some kind of reset ??? */
+	{0x0003, 0x8701},
+	{0x0001, 0x8703},
+	{0x0011, 0x8118},
+	{0x0001, 0x8118},
+	/***************/
+	{0x0092, 0x8804},
+	{0x0010, 0x8802},
+	{0x000d, 0x8805},
+	{0x0001, 0x8801},
+	{0x0000, 0x8800},
+	{0x0018, 0x8805},
+	{0x0002, 0x8801},
+	{0x0000, 0x8800},
+	{0x0065, 0x8805},
+	{0x0004, 0x8801},
+	{0x0001, 0x8800},
+	{0x0021, 0x8805},
+	{0x0005, 0x8801},
+	{0x0000, 0x8800},
+	{0x00aa, 0x8805},
+	{0x0007, 0x8801},	/* mode 0xaa */
+	{0x0000, 0x8800},
+	{0x0004, 0x8805},
+	{0x0020, 0x8801},
+	{0x0015, 0x8800},	/* mode 0x0415 */
+	{0x0002, 0x8805},
+	{0x0039, 0x8801},
+	{0x0000, 0x8800},
+	{0x0010, 0x8805},
+	{0x0035, 0x8801},
+	{0x0000, 0x8800},
+	{0x0049, 0x8805},
+	{0x0009, 0x8801},
+	{0x0010, 0x8800},
+	{0x000b, 0x8805},
+	{0x0028, 0x8801},
+	{0x0000, 0x8800},
+	{0x000f, 0x8805},
+	{0x003b, 0x8801},
+	{0x0000, 0x8800},
+	{0x0000, 0x8805},
+	{0x003c, 0x8801},
+	{0x0000, 0x8800},
+	{0x0002, 0x8502},
+	{0x0039, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+
+	{0x0087, 0x8700},	/* overwrite by start */
+	{0x0081, 0x8702},
+	{0x0000, 0x8500},
+/*	{0x0010, 0x8500},  -- Previous line was this */
+	{0x0002, 0x865b},
+	{0x0003, 0x865c},
+	/***************/
+	{0x0003, 0x8801},	/* 0x121-> 289 */
+	{0x0021, 0x8805},
+	{0x0001, 0x8800},
+	{0x0004, 0x8801},	/* 0x165 -> 357 */
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0005, 0x8801},	/* 0x2f //blanking control colonne */
+	{0x002f, 0x8805},
+	{0x0000, 0x8800},
+	{0x0006, 0x8801},	/* 0x00 //blanking mode row */
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x000a, 0x8801},	/* 0x01 //0x02 */
+	{0x0001, 0x8805},
+	{0x0000, 0x8800},
+	{0x0009, 0x8801},	/* 0x1061 - setexposure times && pixel clock
+				 * 0001 0 | 000 0110 0001 */
+	{0x0061, 0x8805},	/* 61 31 */
+	{0x0008, 0x8800},	/* 08 */
+	{0x0035, 0x8801},	/* 0x14 - set gain general */
+	{0x001f, 0x8805},	/* 0x14 */
+	{0x0000, 0x8800},
+	{0x0030, 0x8112},
+	{}
+};
+
+static void sensor_reset(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
+	reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
+	reg_w_val(gspca_dev->dev, 0x8112, 0x00);
+	reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+	reg_w_val(gspca_dev->dev, 0x8118, 0x21);
+	i2c_init(gspca_dev, 0x14);
+	i2c_write(gspca_dev, 1, 0x0d);
+	i2c_write(gspca_dev, 0, 0x0d);
+}
+
+/******************** QC Express etch2 stuff ********************/
+static const __u16 Pb100_1map8300[][2] = {
+	/* reg, value */
+	{0x8320, 0x3304},
+
+	{0x8303, 0x0125},	/* image area */
+	{0x8304, 0x0169},
+	{0x8328, 0x000b},
+	{0x833c, 0x0001},
+
+	{0x832f, 0x0419},
+	{0x8307, 0x00aa},
+	{0x8301, 0x0003},
+	{0x8302, 0x000e},
+	{}
+};
+static const __u16 Pb100_2map8300[][2] = {
+	/* reg, value */
+	{0x8339, 0x0000},
+	{0x8307, 0x00aa},
+	{}
+};
+
+static const __u16 spca561_161rev12A_data1[][2] = {
+	{0x21, 0x8118},
+	{0x01, 0x8114},
+	{0x00, 0x8112},
+	{0x92, 0x8804},
+	{0x04, 0x8802},		/* windows uses 08 */
+	{}
+};
+static const __u16 spca561_161rev12A_data2[][2] = {
+	{0x21, 0x8118},
+	{0x10, 0x8500},
+	{0x07, 0x8601},
+	{0x07, 0x8602},
+	{0x04, 0x8501},
+	{0x21, 0x8118},
+
+	{0x07, 0x8201},		/* windows uses 02 */
+	{0x08, 0x8200},
+	{0x01, 0x8200},
+
+	{0x00, 0x8114},
+	{0x01, 0x8114},		/* windows uses 00 */
+
+	{0x90, 0x8604},
+	{0x00, 0x8605},
+	{0xb0, 0x8603},
+
+	/* sensor gains */
+	{0x00, 0x8610},		/* *red */
+	{0x00, 0x8611},		/* 3f   *green */
+	{0x00, 0x8612},		/* green *blue */
+	{0x00, 0x8613},		/* blue *green */
+	{0x35, 0x8614},		/* green *red */
+	{0x35, 0x8615},		/* 40   *green */
+	{0x35, 0x8616},		/* 7a   *blue */
+	{0x35, 0x8617},		/* 40   *green */
+
+	{0x0c, 0x8620},		/* 0c */
+	{0xc8, 0x8631},		/* c8 */
+	{0xc8, 0x8634},		/* c8 */
+	{0x23, 0x8635},		/* 23 */
+	{0x1f, 0x8636},		/* 1f */
+	{0xdd, 0x8637},		/* dd */
+	{0xe1, 0x8638},		/* e1 */
+	{0x1d, 0x8639},		/* 1d */
+	{0x21, 0x863a},		/* 21 */
+	{0xe3, 0x863b},		/* e3 */
+	{0xdf, 0x863c},		/* df */
+	{0xf0, 0x8505},
+	{0x32, 0x850a},
+	{}
+};
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+			    const __u16 sensormap[][2])
+{
+	int i = 0;
+	__u8 usbval[2];
+
+	while (sensormap[i][0]) {
+		usbval[0] = sensormap[i][1];
+		usbval[1] = sensormap[i][1] >> 8;
+		reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2);
+		i++;
+	}
+}
+static void init_161rev12A(struct gspca_dev *gspca_dev)
+{
+	sensor_reset(gspca_dev);
+	write_vector(gspca_dev, spca561_161rev12A_data1);
+	sensor_mapwrite(gspca_dev, Pb100_1map8300);
+	write_vector(gspca_dev, spca561_161rev12A_data2);
+	sensor_mapwrite(gspca_dev, Pb100_2map8300);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor, product;
+	__u8 data1, data2;
+
+	/* Read frm global register the USB product and vendor IDs, just to
+	 * prove that we can communicate with the device.  This works, which
+	 * confirms at we are communicating properly and that the device
+	 * is a 561. */
+	reg_r(gspca_dev, 0x8104, 1);
+	data1 = gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8105, 1);
+	data2 = gspca_dev->usb_buf[0];
+	vendor = (data2 << 8) | data1;
+	reg_r(gspca_dev, 0x8106, 1);
+	data1 = gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8107, 1);
+	data2 = gspca_dev->usb_buf[0];
+	product = (data2 << 8) | data1;
+	if (vendor != id->idVendor || product != id->idProduct) {
+		PDEBUG(D_PROBE, "Bad vendor / product from device");
+		return -EINVAL;
+	}
+	switch (product) {
+	case 0x0928:
+	case 0x0929:
+	case 0x092a:
+	case 0x092b:
+	case 0x092c:
+	case 0x092d:
+	case 0x092e:
+	case 0x092f:
+	case 0x403b:
+		sd->chip_revision = Rev012A;
+		break;
+	default:
+/*	case 0x0561:
+	case 0x0815:			* ?? in spca508.c
+	case 0x401a:
+	case 0x7004:
+	case 0x7e50:
+	case 0xa001:
+	case 0xcdee: */
+		sd->chip_revision = Rev072A;
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	gspca_dev->nbalt = 7 + 1;	/* choose alternate 7 first */
+	cam->cam_mode = sif_mode;
+	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		PDEBUG(D_STREAM, "Chip revision id: 072a");
+		write_vector(gspca_dev, spca561_init_data);
+		break;
+	default:
+/*	case Rev012A: */
+		PDEBUG(D_STREAM, "Chip revision id: 012a");
+		init_161rev12A(gspca_dev);
+		break;
+	}
+	return 0;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 lowb;
+	int expotimes;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		lowb = sd->contrast >> 8;
+		reg_w_val(dev, lowb, 0x8651);
+		reg_w_val(dev, lowb, 0x8652);
+		reg_w_val(dev, lowb, 0x8653);
+		reg_w_val(dev, lowb, 0x8654);
+		break;
+	case Rev012A: {
+		__u8 Reg8391[] =
+			{ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
+		/* Write camera sensor settings */
+		expotimes = (sd->contrast >> 5) & 0x07ff;
+		Reg8391[0] = expotimes & 0xff;	/* exposure */
+		Reg8391[1] = 0x18 | (expotimes >> 8);
+		Reg8391[2] = sd->brightness;	/* gain */
+		reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
+		reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
+		break;
+	    }
+	}
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int Clck;
+	__u8 Reg8307[] = { 0xaa, 0x00 };
+	int mode;
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	switch (sd->chip_revision) {
+	case Rev072A:
+		switch (mode) {
+		default:
+/*		case 0:
+		case 1: */
+			Clck = 0x25;
+			break;
+		case 2:
+			Clck = 0x22;
+			break;
+		case 3:
+			Clck = 0x21;
+			break;
+		}
+		reg_w_val(dev, 0x8500, mode);	/* mode */
+		reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
+		reg_w_val(dev, 0x8112, 0x10 | 0x20);
+		break;
+	default:
+/*	case Rev012A: */
+		switch (mode) {
+		case 0:
+		case 1:
+			Clck = 0x8a;
+			break;
+		case 2:
+			Clck = 0x85;
+			break;
+		default:
+			Clck = 0x83;
+			break;
+		}
+		if (mode <= 1) {
+			/* Use compression on 320x240 and above */
+			reg_w_val(dev, 0x8500, 0x10 | mode);
+		} else {
+			/* I couldn't get the compression to work below 320x240
+			 * Fortunately at these resolutions the bandwidth
+			 * is sufficient to push raw frames at ~20fps */
+			reg_w_val(dev, 0x8500, mode);
+		}		/* -- qq@kuku.eu.org */
+		reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+		reg_w_val(gspca_dev->dev, 0x8700, Clck);
+						/* 0x8f 0x85 0x27 clock */
+		reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+		reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+		setcontrast(gspca_dev);
+		break;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8114, 0);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int expotimes = 0;
+	int pixelclk = 0;
+	int gainG = 0;
+	__u8 R, Gr, Gb, B;
+	int y;
+	__u8 luma_mean = 110;
+	__u8 luma_delta = 20;
+	__u8 spring = 4;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		reg_r(gspca_dev, 0x8621, 1);
+		Gr = gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8622, 1);
+		R = gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8623, 1);
+		B = gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8624, 1);
+		Gb = gspca_dev->usb_buf[0];
+		y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
+		/* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
+		/* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
+		/* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
+
+		if (y < luma_mean - luma_delta ||
+		    y > luma_mean + luma_delta) {
+			expotimes = i2c_read(gspca_dev, 0x09, 0x10);
+			pixelclk = 0x0800;
+			expotimes = expotimes & 0x07ff;
+			/* PDEBUG(D_PACK,
+				"Exposition Times 0x%03X Clock 0x%04X ",
+				expotimes,pixelclk); */
+			gainG = i2c_read(gspca_dev, 0x35, 0x10);
+			/* PDEBUG(D_PACK,
+				"reading Gain register %d", gainG); */
+
+			expotimes += (luma_mean - y) >> spring;
+			gainG += (luma_mean - y) / 50;
+			/* PDEBUG(D_PACK,
+				"compute expotimes %d gain %d",
+				expotimes,gainG); */
+
+			if (gainG > 0x3f)
+				gainG = 0x3f;
+			else if (gainG < 4)
+				gainG = 3;
+			i2c_write(gspca_dev, gainG, 0x35);
+
+			if (expotimes >= 0x0256)
+				expotimes = 0x0256;
+			else if (expotimes < 4)
+				expotimes = 3;
+			i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
+		}
+		break;
+	case Rev012A:
+		/* sensor registers is access and memory mapped to 0x8300 */
+		/* readind all 0x83xx block the sensor */
+		/*
+		 * The data from the header seem wrong where is the luma
+		 * and chroma mean value
+		 * at the moment set exposure in contrast set
+		 */
+		break;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame, /* target */
+			__u8 *data,		/* isoc packet */
+			int len)		/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:		/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+		if (sd->ag_cnt >= 0) {
+			if (--sd->ag_cnt < 0) {
+				sd->ag_cnt = AG_CNT_START;
+				setautogain(gspca_dev);
+			}
+		}
+		data += SPCA561_OFFSET_DATA;
+		len -= SPCA561_OFFSET_DATA;
+		if (data[1] & 0x10) {
+			/* compressed bayer */
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					frame, data, len);
+		} else {
+			/* raw bayer (with a header, which we skip) */
+			data += 20;
+			len -= 20;
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+						frame, data, len);
+		}
+		return;
+	case 0xff:		/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data++;
+	len--;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		value = sd->brightness;
+		reg_w_val(gspca_dev->dev, value, 0x8611);
+		reg_w_val(gspca_dev->dev, value, 0x8612);
+		reg_w_val(gspca_dev->dev, value, 0x8613);
+		reg_w_val(gspca_dev->dev, value, 0x8614);
+		break;
+	default:
+/*	case Rev012A: */
+		setcontrast(gspca_dev);
+		break;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 tot;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		tot = 0;
+		reg_r(gspca_dev, 0x8611, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8612, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8613, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8614, 1);
+		tot += gspca_dev->usb_buf[0];
+		sd->brightness = tot >> 2;
+		break;
+	default:
+/*	case Rev012A: */
+		/* no way to read sensor settings */
+		break;
+	}
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 tot;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		tot = 0;
+		reg_r(gspca_dev, 0x8651, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8652, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8653, 1);
+		tot += gspca_dev->usb_buf[0];
+		reg_r(gspca_dev, 0x8654, 1);
+		tot += gspca_dev->usb_buf[0];
+		sd->contrast = tot << 6;
+		break;
+	default:
+/*	case Rev012A: */
+		/* no way to read sensor settings */
+		break;
+	}
+	PDEBUG(D_CONF, "get contrast %d", sd->contrast);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")},
+	{USB_DEVICE(0x041e, 0x403b),  DVNM("Creative Webcam Vista (VF0010)")},
+	{USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")},
+	{USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")},
+	{USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")},
+	{USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")},
+	{USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")},
+	{USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")},
+	{USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")},
+	{USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")},
+	{USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")},
+	{USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
new file mode 100644
index 0000000..c78ee0d
--- /dev/null
+++ b/drivers/media/video/gspca/stk014.c
@@ -0,0 +1,592 @@
+/*
+ * Syntek DV4000 (STK014) subdriver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "stk014"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char lightfreq;
+};
+
+/* global parameters */
+static int sd_quant = 7;		/* <= 4 KO - 7: good (enough!) */
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 127
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define CONTRAST_DEF 127
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define COLOR_DEF 127
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+	{
+	    {
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 1,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+#define FREQ_DEF 1
+		.default_value = FREQ_DEF,
+	    },
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* -- read a register -- */
+static int reg_r(struct gspca_dev *gspca_dev,
+			__u16 index)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			0x00,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0x00,
+			index,
+			gspca_dev->usb_buf, 1,
+			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r err %d", ret);
+		return ret;
+	}
+	return gspca_dev->usb_buf[0];
+}
+
+/* -- write a register -- */
+static int reg_w(struct gspca_dev *gspca_dev,
+			__u16 index, __u16 value)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			0x01,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			index,
+			NULL,
+			0,
+			500);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg_w err %d", ret);
+	return ret;
+}
+
+/* -- get a bulk value (4 bytes) -- */
+static int rcv_val(struct gspca_dev *gspca_dev,
+			int ads)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int alen, ret;
+
+	reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
+	reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
+	reg_w(gspca_dev, 0x636, ads & 0xff);
+	reg_w(gspca_dev, 0x637, 0);
+	reg_w(gspca_dev, 0x638, 4);	/* len & 0xff */
+	reg_w(gspca_dev, 0x639, 0);	/* len >> 8 */
+	reg_w(gspca_dev, 0x63a, 0);
+	reg_w(gspca_dev, 0x63b, 0);
+	reg_w(gspca_dev, 0x630, 5);
+	ret = usb_bulk_msg(dev,
+			usb_rcvbulkpipe(dev, 5),
+			gspca_dev->usb_buf,
+			4,		/* length */
+			&alen,
+			500);		/* timeout in milliseconds */
+	return ret;
+}
+
+/* -- send a bulk value -- */
+static int snd_val(struct gspca_dev *gspca_dev,
+			int ads,
+			unsigned int val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int alen, ret;
+	__u8 seq = 0;
+
+	if (ads == 0x003f08) {
+		ret = reg_r(gspca_dev, 0x0704);
+		if (ret < 0)
+			goto ko;
+		ret = reg_r(gspca_dev, 0x0705);
+		if (ret < 0)
+			goto ko;
+		seq = ret;		/* keep the sequence number */
+		ret = reg_r(gspca_dev, 0x0650);
+		if (ret < 0)
+			goto ko;
+		reg_w(gspca_dev, 0x654, seq);
+	} else {
+		reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+	}
+	reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
+	reg_w(gspca_dev, 0x656, ads & 0xff);
+	reg_w(gspca_dev, 0x657, 0);
+	reg_w(gspca_dev, 0x658, 0x04);	/* size */
+	reg_w(gspca_dev, 0x659, 0);
+	reg_w(gspca_dev, 0x65a, 0);
+	reg_w(gspca_dev, 0x65b, 0);
+	reg_w(gspca_dev, 0x650, 5);
+	gspca_dev->usb_buf[0] = val >> 24;
+	gspca_dev->usb_buf[1] = val >> 16;
+	gspca_dev->usb_buf[2] = val >> 8;
+	gspca_dev->usb_buf[3] = val;
+	ret = usb_bulk_msg(dev,
+			usb_sndbulkpipe(dev, 6),
+			gspca_dev->usb_buf,
+			4,
+			&alen,
+			500);	/* timeout in milliseconds */
+	if (ret < 0)
+		goto ko;
+	if (ads == 0x003f08) {
+		seq += 4;
+		seq &= 0x3f;
+		reg_w(gspca_dev, 0x705, seq);
+	}
+	return ret;
+ko:
+	PDEBUG(D_ERR, "snd_val err %d", ret);
+	return ret;
+}
+
+/* set a camera parameter */
+static int set_par(struct gspca_dev *gspca_dev,
+		   int parval)
+{
+	return snd_val(gspca_dev, 0x003f08, parval);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int parval;
+
+	parval = 0x06000000		/* whiteness */
+		+ (sd->brightness << 16);
+	set_par(gspca_dev, parval);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int parval;
+
+	parval = 0x07000000		/* contrast */
+		+ (sd->contrast << 16);
+	set_par(gspca_dev, parval);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int parval;
+
+	parval = 0x08000000		/* saturation */
+		+ (sd->colors << 16);
+	set_par(gspca_dev, parval);
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	set_par(gspca_dev, sd->lightfreq == 1
+			? 0x33640000		/* 50 Hz */
+			: 0x33780000);		/* 60 Hz */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam = &gspca_dev->cam;
+
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x02;
+	gspca_dev->cam.cam_mode = vga_mode;
+	gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->lightfreq = FREQ_DEF;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	int ret;
+
+	/* check if the device responds */
+	usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+	ret = reg_r(gspca_dev, 0x0740);
+	if (ret < 0)
+		return ret;
+	if (ret != 0xff) {
+		PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
+		return -1;
+	}
+	return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	int ret, value;
+
+	/* work on alternate 1 */
+	usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+
+	set_par(gspca_dev, 0x10000000);
+	set_par(gspca_dev, 0x00000000);
+	set_par(gspca_dev, 0x8002e001);
+	set_par(gspca_dev, 0x14000000);
+	if (gspca_dev->width > 320)
+		value = 0x8002e001;		/* 640x480 */
+	else
+		value = 0x4001f000;		/* 320x240 */
+	set_par(gspca_dev, value);
+	ret = usb_set_interface(gspca_dev->dev,
+					gspca_dev->iface,
+					gspca_dev->alt);
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+			gspca_dev->iface, gspca_dev->alt);
+		goto out;
+	}
+	ret = reg_r(gspca_dev, 0x0630);
+	if (ret < 0)
+		goto out;
+	rcv_val(gspca_dev, 0x000020);	/* << (value ff ff ff ff) */
+	ret = reg_r(gspca_dev, 0x0650);
+	if (ret < 0)
+		goto out;
+	snd_val(gspca_dev, 0x000020, 0xffffffff);
+	reg_w(gspca_dev, 0x0620, 0);
+	reg_w(gspca_dev, 0x0630, 0);
+	reg_w(gspca_dev, 0x0640, 0);
+	reg_w(gspca_dev, 0x0650, 0);
+	reg_w(gspca_dev, 0x0660, 0);
+	setbrightness(gspca_dev);		/* whiteness */
+	setcontrast(gspca_dev);			/* contrast */
+	setcolors(gspca_dev);			/* saturation */
+	set_par(gspca_dev, 0x09800000);		/* Red ? */
+	set_par(gspca_dev, 0x0a800000);		/* Green ? */
+	set_par(gspca_dev, 0x0b800000);		/* Blue ? */
+	set_par(gspca_dev, 0x0d030000);		/* Gamma ? */
+	setfreq(gspca_dev);			/* light frequency */
+
+	/* start the video flow */
+	set_par(gspca_dev, 0x01000000);
+	set_par(gspca_dev, 0x01000000);
+	PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+	return;
+out:
+	PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	set_par(gspca_dev, 0x02000000);
+	set_par(gspca_dev, 0x02000000);
+	usb_set_interface(dev, gspca_dev->iface, 1);
+	reg_r(gspca_dev, 0x0630);
+	rcv_val(gspca_dev, 0x000020);	/* << (value ff ff ff ff) */
+	reg_r(gspca_dev, 0x0650);
+	snd_val(gspca_dev, 0x000020, 0xffffffff);
+	reg_w(gspca_dev, 0x0620, 0);
+	reg_w(gspca_dev, 0x0630, 0);
+	reg_w(gspca_dev, 0x0640, 0);
+	reg_w(gspca_dev, 0x0650, 0);
+	reg_w(gspca_dev, 0x0660, 0);
+	PDEBUG(D_STREAM, "camera stopped");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	static unsigned char ffd9[] = {0xff, 0xd9};
+
+	/* a frame starts with:
+	 *	- 0xff 0xfe
+	 *	- 0x08 0x00	- length (little endian ?!)
+	 *	- 4 bytes = size of whole frame (BE - including header)
+	 *	- 0x00 0x0c
+	 *	- 0xff 0xd8
+	 *	- ..	JPEG image with escape sequences (ff 00)
+	 *		(without ending - ff d9)
+	 */
+	if (data[0] == 0xff && data[1] == 0xfe) {
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+
+		/* put the JPEG 411 header */
+		jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+
+		/* beginning of the frame */
+#define STKHDRSZ 12
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+				data + STKHDRSZ, len - STKHDRSZ);
+#undef STKHDRSZ
+		return;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	info("v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param_named(quant, sd_quant, int, 0644);
+MODULE_PARM_DESC(quant, "Quantization index (0..8)");
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
new file mode 100644
index 0000000..abd7bef
--- /dev/null
+++ b/drivers/media/video/gspca/sunplus.c
@@ -0,0 +1,1677 @@
+/*
+ *		Sunplus spca504(abc) spca533 spca536 library
+ *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "sunplus"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 8)
+static const char version[] = "2.1.8";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	__u8 packet[ISO_MAX_SIZE + 128];
+				/* !! no more than 128 ff in an ISO packet */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	char qindex;
+	char bridge;
+#define BRIDGE_SPCA504 0
+#define BRIDGE_SPCA504B 1
+#define BRIDGE_SPCA504C 2
+#define BRIDGE_SPCA533 3
+#define BRIDGE_SPCA536 4
+	char subtype;
+#define AiptekMiniPenCam13 1
+#define LogitechClickSmart420 2
+#define LogitechClickSmart820 3
+#define MegapixV4 4
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x20,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x1a,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+#define SD_AUTOGAIN 3
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+};
+
+static struct v4l2_pix_format custom_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 464,
+		.sizeimage = 464 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+};
+
+static struct v4l2_pix_format vga_mode2[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 4},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 3},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
+#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
+#define SPCA504_PCCAM600_OFFSET_MODE	 5
+#define SPCA504_PCCAM600_OFFSET_DATA	 14
+ /* Frame packet header offsets for the spca533 */
+#define SPCA533_OFFSET_DATA      16
+#define SPCA533_OFFSET_FRAMSEQ	15
+/* Frame packet header offsets for the spca536 */
+#define SPCA536_OFFSET_DATA      4
+#define SPCA536_OFFSET_FRAMSEQ	 1
+
+/* Initialisation data for the Creative PC-CAM 600 */
+static const __u16 spca504_pccam600_init_data[][3] = {
+/*	{0xa0, 0x0000, 0x0503},  * capture mode */
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0001, 0x21ac},
+	{0x00, 0x0001, 0x21a6},
+	{0x00, 0x0000, 0x21a7},	/* brightness */
+	{0x00, 0x0020, 0x21a8},	/* contrast */
+	{0x00, 0x0001, 0x21ac},	/* sat/hue */
+	{0x00, 0x0000, 0x21ad},	/* hue */
+	{0x00, 0x001a, 0x21ae},	/* saturation */
+	{0x00, 0x0002, 0x21a3},	/* gamma */
+	{0x30, 0x0154, 0x0008},
+	{0x30, 0x0004, 0x0006},
+	{0x30, 0x0258, 0x0009},
+	{0x30, 0x0004, 0x0000},
+	{0x30, 0x0093, 0x0004},
+	{0x30, 0x0066, 0x0005},
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{}
+};
+
+/* Creative PC-CAM 600 specific open data, sent before using the
+ * generic initialisation data from spca504_open_data.
+ */
+static const __u16 spca504_pccam600_open_data[][3] = {
+	{0x00, 0x0001, 0x2501},
+	{0x20, 0x0500, 0x0001},	/* snapshot mode */
+	{0x00, 0x0003, 0x2880},
+	{0x00, 0x0001, 0x2881},
+	{}
+};
+
+/* Initialisation data for the logitech clicksmart 420 */
+static const __u16 spca504A_clicksmart420_init_data[][3] = {
+/*	{0xa0, 0x0000, 0x0503},  * capture mode */
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0001, 0x21ac},
+	{0x00, 0x0001, 0x21a6},
+	{0x00, 0x0000, 0x21a7},	/* brightness */
+	{0x00, 0x0020, 0x21a8},	/* contrast */
+	{0x00, 0x0001, 0x21ac},	/* sat/hue */
+	{0x00, 0x0000, 0x21ad},	/* hue */
+	{0x00, 0x001a, 0x21ae},	/* saturation */
+	{0x00, 0x0002, 0x21a3},	/* gamma */
+	{0x30, 0x0004, 0x000a},
+	{0xb0, 0x0001, 0x0000},
+
+
+	{0x0a1, 0x0080, 0x0001},
+	{0x30, 0x0049, 0x0000},
+	{0x30, 0x0060, 0x0005},
+	{0x0c, 0x0004, 0x0000},
+	{0x00, 0x0000, 0x0000},
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0000, 0x2000},
+
+	{}
+};
+
+/* clicksmart 420 open data ? */
+static const __u16 spca504A_clicksmart420_open_data[][3] = {
+	{0x00, 0x0001, 0x2501},
+	{0x20, 0x0502, 0x0000},
+	{0x06, 0x0000, 0x0000},
+	{0x00, 0x0004, 0x2880},
+	{0x00, 0x0001, 0x2881},
+/* look like setting a qTable */
+	{0x00, 0x0006, 0x2800},
+	{0x00, 0x0004, 0x2801},
+	{0x00, 0x0004, 0x2802},
+	{0x00, 0x0006, 0x2803},
+	{0x00, 0x000a, 0x2804},
+	{0x00, 0x0010, 0x2805},
+	{0x00, 0x0014, 0x2806},
+	{0x00, 0x0018, 0x2807},
+	{0x00, 0x0005, 0x2808},
+	{0x00, 0x0005, 0x2809},
+	{0x00, 0x0006, 0x280a},
+	{0x00, 0x0008, 0x280b},
+	{0x00, 0x000a, 0x280c},
+	{0x00, 0x0017, 0x280d},
+	{0x00, 0x0018, 0x280e},
+	{0x00, 0x0016, 0x280f},
+
+	{0x00, 0x0006, 0x2810},
+	{0x00, 0x0005, 0x2811},
+	{0x00, 0x0006, 0x2812},
+	{0x00, 0x000a, 0x2813},
+	{0x00, 0x0010, 0x2814},
+	{0x00, 0x0017, 0x2815},
+	{0x00, 0x001c, 0x2816},
+	{0x00, 0x0016, 0x2817},
+	{0x00, 0x0006, 0x2818},
+	{0x00, 0x0007, 0x2819},
+	{0x00, 0x0009, 0x281a},
+	{0x00, 0x000c, 0x281b},
+	{0x00, 0x0014, 0x281c},
+	{0x00, 0x0023, 0x281d},
+	{0x00, 0x0020, 0x281e},
+	{0x00, 0x0019, 0x281f},
+
+	{0x00, 0x0007, 0x2820},
+	{0x00, 0x0009, 0x2821},
+	{0x00, 0x000f, 0x2822},
+	{0x00, 0x0016, 0x2823},
+	{0x00, 0x001b, 0x2824},
+	{0x00, 0x002c, 0x2825},
+	{0x00, 0x0029, 0x2826},
+	{0x00, 0x001f, 0x2827},
+	{0x00, 0x000a, 0x2828},
+	{0x00, 0x000e, 0x2829},
+	{0x00, 0x0016, 0x282a},
+	{0x00, 0x001a, 0x282b},
+	{0x00, 0x0020, 0x282c},
+	{0x00, 0x002a, 0x282d},
+	{0x00, 0x002d, 0x282e},
+	{0x00, 0x0025, 0x282f},
+
+	{0x00, 0x0014, 0x2830},
+	{0x00, 0x001a, 0x2831},
+	{0x00, 0x001f, 0x2832},
+	{0x00, 0x0023, 0x2833},
+	{0x00, 0x0029, 0x2834},
+	{0x00, 0x0030, 0x2835},
+	{0x00, 0x0030, 0x2836},
+	{0x00, 0x0028, 0x2837},
+	{0x00, 0x001d, 0x2838},
+	{0x00, 0x0025, 0x2839},
+	{0x00, 0x0026, 0x283a},
+	{0x00, 0x0027, 0x283b},
+	{0x00, 0x002d, 0x283c},
+	{0x00, 0x0028, 0x283d},
+	{0x00, 0x0029, 0x283e},
+	{0x00, 0x0028, 0x283f},
+
+	{0x00, 0x0007, 0x2840},
+	{0x00, 0x0007, 0x2841},
+	{0x00, 0x000a, 0x2842},
+	{0x00, 0x0013, 0x2843},
+	{0x00, 0x0028, 0x2844},
+	{0x00, 0x0028, 0x2845},
+	{0x00, 0x0028, 0x2846},
+	{0x00, 0x0028, 0x2847},
+	{0x00, 0x0007, 0x2848},
+	{0x00, 0x0008, 0x2849},
+	{0x00, 0x000a, 0x284a},
+	{0x00, 0x001a, 0x284b},
+	{0x00, 0x0028, 0x284c},
+	{0x00, 0x0028, 0x284d},
+	{0x00, 0x0028, 0x284e},
+	{0x00, 0x0028, 0x284f},
+
+	{0x00, 0x000a, 0x2850},
+	{0x00, 0x000a, 0x2851},
+	{0x00, 0x0016, 0x2852},
+	{0x00, 0x0028, 0x2853},
+	{0x00, 0x0028, 0x2854},
+	{0x00, 0x0028, 0x2855},
+	{0x00, 0x0028, 0x2856},
+	{0x00, 0x0028, 0x2857},
+	{0x00, 0x0013, 0x2858},
+	{0x00, 0x001a, 0x2859},
+	{0x00, 0x0028, 0x285a},
+	{0x00, 0x0028, 0x285b},
+	{0x00, 0x0028, 0x285c},
+	{0x00, 0x0028, 0x285d},
+	{0x00, 0x0028, 0x285e},
+	{0x00, 0x0028, 0x285f},
+
+	{0x00, 0x0028, 0x2860},
+	{0x00, 0x0028, 0x2861},
+	{0x00, 0x0028, 0x2862},
+	{0x00, 0x0028, 0x2863},
+	{0x00, 0x0028, 0x2864},
+	{0x00, 0x0028, 0x2865},
+	{0x00, 0x0028, 0x2866},
+	{0x00, 0x0028, 0x2867},
+	{0x00, 0x0028, 0x2868},
+	{0x00, 0x0028, 0x2869},
+	{0x00, 0x0028, 0x286a},
+	{0x00, 0x0028, 0x286b},
+	{0x00, 0x0028, 0x286c},
+	{0x00, 0x0028, 0x286d},
+	{0x00, 0x0028, 0x286e},
+	{0x00, 0x0028, 0x286f},
+
+	{0x00, 0x0028, 0x2870},
+	{0x00, 0x0028, 0x2871},
+	{0x00, 0x0028, 0x2872},
+	{0x00, 0x0028, 0x2873},
+	{0x00, 0x0028, 0x2874},
+	{0x00, 0x0028, 0x2875},
+	{0x00, 0x0028, 0x2876},
+	{0x00, 0x0028, 0x2877},
+	{0x00, 0x0028, 0x2878},
+	{0x00, 0x0028, 0x2879},
+	{0x00, 0x0028, 0x287a},
+	{0x00, 0x0028, 0x287b},
+	{0x00, 0x0028, 0x287c},
+	{0x00, 0x0028, 0x287d},
+	{0x00, 0x0028, 0x287e},
+	{0x00, 0x0028, 0x287f},
+
+	{0xa0, 0x0000, 0x0503},
+	{}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+/* FIXME: This Q-table is identical to the Creative PC-CAM one,
+ *		except for one byte. Possibly a typo?
+ *		NWG: 18/05/2003.
+ */
+static const __u8 qtable_spca504_default[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
+	 },
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static void reg_r(struct usb_device *dev,
+			   __u16 req,
+			   __u16 index,
+			   __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, buffer, length,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			    __u16 req,
+			    __u16 value,
+			    __u16 index,
+			    __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, buffer, length,
+			500);
+}
+
+/* write req / index / value */
+static int reg_w_riv(struct usb_device *dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
+		req, index, value, ret);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* read 1 byte */
+static int reg_r_1(struct gspca_dev *gspca_dev,
+			__u16 value)	/* wValue */
+{
+	int ret;
+
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0x20,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			0,			/* index */
+			gspca_dev->usb_buf, 1,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r_1 err %d", ret);
+		return 0;
+	}
+	return gspca_dev->usb_buf[0];
+}
+
+/* read 1 or 2 bytes - returns < 0 if error */
+static int reg_r_12(struct gspca_dev *gspca_dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+
+	gspca_dev->usb_buf[1] = 0;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			gspca_dev->usb_buf, length,
+			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+			const __u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Register write failed for 0x%x,0x%x,0x%x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+				unsigned int request,
+				unsigned int ybase,
+				unsigned int cbase,
+				const __u8 qtable[2][64])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i, err;
+
+	/* loop over y components */
+	for (i = 0; i < 64; i++) {
+		err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
+		if (err < 0)
+			return err;
+	}
+
+	/* loop over c components */
+	for (i = 0; i < 64; i++) {
+		err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
+			     __u16 req, __u16 idx, __u16 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 notdone;
+
+	reg_w_riv(dev, req, idx, val);
+	notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+	reg_w_riv(dev, req, idx, val);
+
+	PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+
+	msleep(200);
+	notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+	PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+}
+
+static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
+			__u16 req,
+			__u16 idx, __u16 val, __u8 stat, __u8 count)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 status;
+	__u8 endcode;
+
+	reg_w_riv(dev, req, idx, val);
+	status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+	endcode = stat;
+	PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+	if (!count)
+		return;
+	count = 200;
+	while (--count > 0) {
+		msleep(10);
+		/* gsmart mini2 write a each wait setting 1 ms is enought */
+/*		reg_w_riv(dev, req, idx, val); */
+		status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+		if (status == endcode) {
+			PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+				status, 200 - count);
+				break;
+		}
+	}
+}
+
+static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
+{
+	int count = 10;
+
+	while (--count > 0) {
+		reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
+		if ((gspca_dev->usb_buf[0] & 0x01) == 0)
+			break;
+		msleep(10);
+	}
+	return gspca_dev->usb_buf[0];
+}
+
+static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int count = 50;
+
+	while (--count > 0) {
+		reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+		if (gspca_dev->usb_buf[0] != 0) {
+			gspca_dev->usb_buf[0] = 0;
+			reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
+			reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+			spca504B_PollingDataReady(gspca_dev);
+			break;
+		}
+		msleep(10);
+	}
+}
+
+static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 *data;
+
+	data = kmalloc(64, GFP_KERNEL);
+	reg_r(dev, 0x20, 0, data, 5);
+	PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+		data[0], data[1], data[2], data[3], data[4]);
+	reg_r(dev, 0x23, 0, data, 64);
+	reg_r(dev, 0x23, 1, data, 64);
+	kfree(data);
+}
+
+static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 Size;
+	__u8 Type;
+	int rc;
+
+	Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	Type = 0;
+	switch (sd->bridge) {
+	case BRIDGE_SPCA533:
+		reg_w(dev, 0x31, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		rc = spca504B_PollingDataReady(gspca_dev);
+		spca50x_GetFirmware(gspca_dev);
+		gspca_dev->usb_buf[0] = 2;			/* type */
+		reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
+		reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
+
+		gspca_dev->usb_buf[0] = Size;
+		reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
+		reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);	/* size */
+		rc = spca504B_PollingDataReady(gspca_dev);
+
+		/* Init the cam width height with some values get on init ? */
+		reg_w(dev, 0x31, 0, 4, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		rc = spca504B_PollingDataReady(gspca_dev);
+		break;
+	default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA536: */
+		gspca_dev->usb_buf[0] = Size;
+		reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
+		reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);	/* size */
+		Type = 6;
+		gspca_dev->usb_buf[0] = Type;
+		reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
+		reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1);	/* type */
+		rc = spca504B_PollingDataReady(gspca_dev);
+		break;
+	case BRIDGE_SPCA504:
+		Size += 3;
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/* spca504a aiptek */
+			spca504A_acknowledged_command(gspca_dev,
+						0x08, Size, 0,
+						0x80 | (Size & 0x0f), 1);
+			spca504A_acknowledged_command(gspca_dev,
+							1, 3, 0, 0x9f, 0);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
+		}
+		break;
+	case BRIDGE_SPCA504C:
+		/* capture mode */
+		reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
+		reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
+		break;
+	}
+}
+
+static void spca504_wait_status(struct gspca_dev *gspca_dev)
+{
+	int cnt;
+
+	cnt = 256;
+	while (--cnt > 0) {
+		/* With this we get the status, when return 0 it's all ok */
+		if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
+			return;
+		msleep(10);
+	}
+}
+
+static void spca504B_setQtable(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	gspca_dev->usb_buf[0] = 3;
+	reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
+	reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
+	spca504B_PollingDataReady(gspca_dev);
+}
+
+static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int pollreg = 1;
+
+	switch (sd->bridge) {
+	case BRIDGE_SPCA504:
+	case BRIDGE_SPCA504C:
+		pollreg = 0;
+		/* fall thru */
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+		reg_w(dev, 0, 0, 0x21a7, NULL, 0);	/* brightness */
+		reg_w(dev, 0, 0x20, 0x21a8, NULL, 0);	/* contrast */
+		reg_w(dev, 0, 0, 0x21ad, NULL, 0);	/* hue */
+		reg_w(dev, 0, 1, 0x21ac, NULL, 0);	/* sat/hue */
+		reg_w(dev, 0, 0x20, 0x21ae, NULL, 0);	/* saturation */
+		reg_w(dev, 0, 0, 0x21a3, NULL, 0);	/* gamma */
+		break;
+	case BRIDGE_SPCA536:
+		reg_w(dev, 0, 0, 0x20f0, NULL, 0);
+		reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
+		reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
+		reg_w(dev, 0, 1, 0x20f4, NULL, 0);
+		reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
+		reg_w(dev, 0, 0, 0x2089, NULL, 0);
+		break;
+	}
+	if (pollreg)
+		spca504B_PollingDataReady(gspca_dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+	__u8 fw;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x400b: */
+/*		case 0x4012: */
+/*		case 0x4013: */
+/*			sd->bridge = BRIDGE_SPCA504C; */
+/*			break; */
+/*		} */
+		break;
+	case 0x0458:		/* Genius KYE cameras */
+/*		switch (product) { */
+/*		case 0x7006: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x0461:		/* MicroInnovation */
+/*		switch (product) { */
+/*		case 0x0821: */
+			sd->bridge = BRIDGE_SPCA533;
+/*			break; */
+/*		} */
+		break;
+	case 0x046d:		/* Logitech Labtec */
+		switch (product) {
+		case 0x0905:
+			sd->subtype = LogitechClickSmart820;
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x0960:
+			sd->subtype = LogitechClickSmart420;
+			sd->bridge = BRIDGE_SPCA504C;
+			break;
+		}
+		break;
+	case 0x0471:				/* Philips */
+/*		switch (product) { */
+/*		case 0x0322: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x04a5:		/* Benq */
+		switch (product) {
+		case 0x3003:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x3008:
+		case 0x300a:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		}
+		break;
+	case 0x04f1:		/* JVC */
+/*		switch (product) { */
+/*		case 0x1001: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x04fc:		/* SunPlus */
+		switch (product) {
+		case 0x500c:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x504a:
+/* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
+			reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
+			fw = gspca_dev->usb_buf[0];
+			if (fw == 1) {
+				sd->subtype = AiptekMiniPenCam13;
+				sd->bridge = BRIDGE_SPCA504;
+			} else if (fw == 2) {
+				sd->bridge = BRIDGE_SPCA504B;
+			} else
+				return -ENODEV;
+			break;
+		case 0x504b:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x5330:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x5360:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xffff:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		}
+		break;
+	case 0x052b:		/* ?? Megapix */
+/*		switch (product) { */
+/*		case 0x1513: */
+			sd->subtype = MegapixV4;
+			sd->bridge = BRIDGE_SPCA533;
+/*			break; */
+/*		} */
+		break;
+	case 0x0546:		/* Polaroid */
+		switch (product) {
+		case 0x3155:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x3191:
+		case 0x3273:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		}
+		break;
+	case 0x055f:		/* Mustek cameras */
+		switch (product) {
+		case 0xc211:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xc230:
+		case 0xc232:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0xc360:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xc420:
+			sd->bridge = BRIDGE_SPCA504;
+			break;
+		case 0xc430:
+		case 0xc440:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0xc520:
+			sd->bridge = BRIDGE_SPCA504;
+			break;
+		case 0xc530:
+		case 0xc540:
+		case 0xc630:
+		case 0xc650:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		}
+		break;
+	case 0x05da:		/* Digital Dream cameras */
+/*		switch (product) { */
+/*		case 0x1018: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x06d6:		/* Trust */
+/*		switch (product) { */
+/*		case 0x0031: */
+			sd->bridge = BRIDGE_SPCA533;	/* SPCA533A */
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+		switch (product) {
+		case 0x1311:
+		case 0x1314:
+		case 0x2211:
+		case 0x2221:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x3261:
+		case 0x3281:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		}
+		break;
+	case 0x08ca:		/* Aiptek */
+		switch (product) {
+		case 0x0104:
+		case 0x0106:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2008:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x2010:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2016:
+		case 0x2018:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x2020:
+		case 0x2022:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2024:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0x2028:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2040:
+		case 0x2042:
+		case 0x2050:
+		case 0x2060:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		}
+		break;
+	case 0x0d64:		/* SunPlus */
+/*		switch (product) { */
+/*		case 0x0303: */
+			sd->bridge = BRIDGE_SPCA536;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA536: */
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+		break;
+	case BRIDGE_SPCA533:
+		cam->cam_mode = custom_mode;
+		cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+		break;
+	case BRIDGE_SPCA504C:
+		cam->cam_mode = vga_mode2;
+		cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+		break;
+	}
+	sd->qindex = 5;			/* set the quantization table */
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int rc;
+	__u8 i;
+	__u8 info[6];
+	int err_code;
+
+	switch (sd->bridge) {
+	case BRIDGE_SPCA504B:
+		reg_w(dev, 0x1d, 0, 0, NULL, 0);
+		reg_w(dev, 0, 1, 0x2306, NULL, 0);
+		reg_w(dev, 0, 0, 0x0d04, NULL, 0);
+		reg_w(dev, 0, 0, 0x2000, NULL, 0);
+		reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
+		reg_w(dev, 0, 0, 0x2306, NULL, 0);
+		/* fall thru */
+	case BRIDGE_SPCA533:
+		rc = spca504B_PollingDataReady(gspca_dev);
+		spca50x_GetFirmware(gspca_dev);
+		break;
+	case BRIDGE_SPCA536:
+		spca50x_GetFirmware(gspca_dev);
+		reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
+		gspca_dev->usb_buf[0] = 0;
+		reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
+		reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
+		rc = spca504B_PollingDataReady(gspca_dev);
+		reg_w(dev, 0x34, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		break;
+	case BRIDGE_SPCA504C:	/* pccam600 */
+		PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
+		reg_w_riv(dev, 0xe0, 0x0000, 0x0000);
+		reg_w_riv(dev, 0xe0, 0x0000, 0x0001);	/* reset */
+		spca504_wait_status(gspca_dev);
+		if (sd->subtype == LogitechClickSmart420)
+			write_vector(gspca_dev,
+					spca504A_clicksmart420_open_data);
+		else
+			write_vector(gspca_dev, spca504_pccam600_open_data);
+		err_code = spca50x_setup_qtable(gspca_dev,
+						0x00, 0x2800,
+						0x2840, qtable_creative_pccam);
+		if (err_code < 0) {
+			PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
+			return err_code;
+		}
+		break;
+	default:
+/*	case BRIDGE_SPCA504: */
+		PDEBUG(D_STREAM, "Opening SPCA504");
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/*****************************/
+			for (i = 0; i < 6; i++)
+				info[i] = reg_r_1(gspca_dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			/* spca504a aiptek */
+			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 1);
+			/* Twice sequencial need status 0xff->0x9e->0x9d */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 0);
+
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0, 0, 0x9d, 1);
+			/******************************/
+			/* spca504a aiptek */
+			spca504A_acknowledged_command(gspca_dev, 0x08,
+							6, 0, 0x86, 1);
+/*			reg_write (dev, 0, 0x2000, 0); */
+/*			reg_write (dev, 0, 0x2883, 1); */
+/*			spca504A_acknowledged_command (gspca_dev, 0x08,
+							6, 0, 0x86, 1); */
+/*			spca504A_acknowledged_command (gspca_dev, 0x24,
+							0, 0, 0x9D, 1); */
+			reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
+			reg_w_riv(dev, 0x0, 0x2310, 0x05);
+			spca504A_acknowledged_command(gspca_dev, 0x01,
+							0x0f, 0, 0xff, 0);
+		}
+		/* setup qtable */
+		reg_w_riv(dev, 0, 0x2000, 0);
+		reg_w_riv(dev, 0, 0x2883, 1);
+		err_code = spca50x_setup_qtable(gspca_dev,
+						0x00, 0x2800,
+						0x2840,
+						qtable_spca504_default);
+		if (err_code < 0) {
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+			return err_code;
+		}
+		break;
+	}
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int rc;
+	int enable;
+	__u8 i;
+	__u8 info[6];
+
+	if (sd->bridge == BRIDGE_SPCA504B)
+		spca504B_setQtable(gspca_dev);
+	spca504B_SetSizeType(gspca_dev);
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA536: */
+		if (sd->subtype == MegapixV4 ||
+		    sd->subtype == LogitechClickSmart820) {
+			reg_w(dev, 0xf0, 0, 0, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+			reg_r(dev, 0xf0, 4, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+		} else {
+			reg_w(dev, 0x31, 0, 4, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+			rc = spca504B_PollingDataReady(gspca_dev);
+		}
+		break;
+	case BRIDGE_SPCA504:
+		if (sd->subtype == AiptekMiniPenCam13) {
+			for (i = 0; i < 6; i++)
+				info[i] = reg_r_1(gspca_dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			/* spca504a aiptek */
+			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 1);
+			/* Twice sequencial need status 0xff->0x9e->0x9d */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 0);
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0, 0, 0x9d, 1);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+			for (i = 0; i < 6; i++)
+				info[i] = reg_r_1(gspca_dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+		}
+		spca504B_SetSizeType(gspca_dev);
+		reg_w_riv(dev, 0x0, 0x270c, 0x05);	/* L92 sno1t.txt */
+		reg_w_riv(dev, 0x0, 0x2310, 0x05);
+		break;
+	case BRIDGE_SPCA504C:
+		if (sd->subtype == LogitechClickSmart420) {
+			write_vector(gspca_dev,
+					spca504A_clicksmart420_init_data);
+		} else {
+			write_vector(gspca_dev, spca504_pccam600_init_data);
+		}
+		enable = (sd->autogain ? 0x04 : 0x01);
+		reg_w_riv(dev, 0x0c, 0x0000, enable);	/* auto exposure */
+		reg_w_riv(dev, 0xb0, 0x0000, enable);	/* auto whiteness */
+
+		/* set default exposure compensation and whiteness balance */
+		reg_w_riv(dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
+		reg_w_riv(dev, 0x30, 0x0002, 1600);
+		spca504B_SetSizeType(gspca_dev);
+		break;
+	}
+	sp5xx_initContBrigHueRegisters(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA536: */
+/*	case BRIDGE_SPCA504B: */
+		reg_w(dev, 0x31, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		spca504B_PollingDataReady(gspca_dev);
+		break;
+	case BRIDGE_SPCA504:
+	case BRIDGE_SPCA504C:
+		reg_w_riv(dev, 0x00, 0x2000, 0x0000);
+
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/* spca504a aiptek */
+/*			spca504A_acknowledged_command(gspca_dev, 0x08,
+							 6, 0, 0x86, 1); */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0x00, 0x00, 0x9d, 1);
+			spca504A_acknowledged_command(gspca_dev, 0x01,
+							0x0f, 0x00, 0xff, 1);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+			reg_w_riv(dev, 0x01, 0x000f, 0x00);
+		}
+		break;
+	}
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, sof = 0;
+	unsigned char *s, *d;
+	static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+	switch (sd->bridge) {
+	case BRIDGE_SPCA533:
+		if (data[0] == 0xff) {
+			if (data[1] != 0x01) {	/* drop packet */
+/*				gspca_dev->last_packet_type = DISCARD_PACKET; */
+				return;
+			}
+			sof = 1;
+			data += SPCA533_OFFSET_DATA;
+			len -= SPCA533_OFFSET_DATA;
+		} else {
+			data += 1;
+			len -= 1;
+		}
+		break;
+	case BRIDGE_SPCA536:
+		if (data[0] == 0xff) {
+			sof = 1;
+			data += SPCA536_OFFSET_DATA;
+			len -= SPCA536_OFFSET_DATA;
+		} else {
+			data += 2;
+			len -= 2;
+		}
+		break;
+	default:
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504B: */
+		switch (data[0]) {
+		case 0xfe:			/* start of frame */
+			sof = 1;
+			data += SPCA50X_OFFSET_DATA;
+			len -= SPCA50X_OFFSET_DATA;
+			break;
+		case 0xff:			/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		default:
+			data += 1;
+			len -= 1;
+			break;
+		}
+		break;
+	case BRIDGE_SPCA504C:
+		switch (data[0]) {
+		case 0xfe:			/* start of frame */
+			sof = 1;
+			data += SPCA504_PCCAM600_OFFSET_DATA;
+			len -= SPCA504_PCCAM600_OFFSET_DATA;
+			break;
+		case 0xff:			/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		default:
+			data += 1;
+			len -= 1;
+			break;
+		}
+		break;
+	}
+	if (sof) {		/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame,
+				((struct sd *) gspca_dev)->qindex,
+				0x22);
+	}
+
+	/* add 0x00 after 0xff */
+	for (i = len; --i >= 0; )
+		if (data[i] == 0xff)
+			break;
+	if (i < 0) {			/* no 0xff */
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		return;
+	}
+	s = data;
+	d = sd->packet;
+	for (i = 0; i < len; i++) {
+		*d++ = *s++;
+		if (s[-1] == 0xff)
+			*d++ = 0x00;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
+		break;
+	case BRIDGE_SPCA536:
+		reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
+		break;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 brightness = 0;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		brightness = reg_r_12(gspca_dev, 0x00, 0x21a7, 2);
+		break;
+	case BRIDGE_SPCA536:
+		brightness = reg_r_12(gspca_dev, 0x00, 0x20f0, 2);
+		break;
+	}
+	sd->brightness = ((brightness & 0xff) - 128) % 255;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
+		break;
+	case BRIDGE_SPCA536:
+		reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
+		break;
+	}
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		sd->contrast = reg_r_12(gspca_dev, 0x00, 0x21a8, 2);
+		break;
+	case BRIDGE_SPCA536:
+		sd->contrast = reg_r_12(gspca_dev, 0x00, 0x20f1, 2);
+		break;
+	}
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
+		break;
+	case BRIDGE_SPCA536:
+		reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
+		break;
+	}
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		sd->colors = reg_r_12(gspca_dev, 0x00, 0x21ae, 2) >> 1;
+		break;
+	case BRIDGE_SPCA536:
+		sd->colors = reg_r_12(gspca_dev, 0x00, 0x20f6, 2) >> 1;
+		break;
+	}
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")},
+	{USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")},
+	{USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")},
+	{USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")},
+	{USB_DEVICE(0x0461, 0x0821), DVNM("Fujifilm MV-1")},
+	{USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")},
+	{USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")},
+	{USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")},
+	{USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")},
+	{USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")},
+	{USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")},
+	{USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")},
+	{USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")},
+	{USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")},
+	{USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")},
+	{USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")},
+	{USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")},
+	{USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")},
+	{USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")},
+	{USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")},
+	{USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")},
+	{USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")},
+	{USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")},
+	{USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")},
+	{USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")},
+	{USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")},
+	{USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")},
+	{USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")},
+	{USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")},
+	{USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")},
+	{USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")},
+	{USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")},
+	{USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")},
+	{USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")},
+	{USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")},
+	{USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")},
+	{USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")},
+	{USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")},
+	{USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")},
+	{USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")},
+	{USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")},
+	{USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")},
+	{USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")},
+	{USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")},
+	{USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")},
+	{USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")},
+	{USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")},
+	{USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")},
+	{USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")},
+	{USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")},
+	{USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")},
+	{USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")},
+	{USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")},
+	{USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")},
+	{USB_DEVICE(0x08ca, 0x2050), DVNM("Medion MD 41437")},
+	{USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")},
+	{USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
new file mode 100644
index 0000000..00f47e4
--- /dev/null
+++ b/drivers/media/video/gspca/t613.c
@@ -0,0 +1,1038 @@
+/*
+ *Notes: * t613  + tas5130A
+ *	* Focus to light do not balance well as in win.
+ *	  Quality in win is not good, but its kinda better.
+ *	 * Fix some "extraneous bytes", most of apps will show the image anyway
+ *	 * Gamma table, is there, but its really doing something?
+ *	 * 7~8 Fps, its ok, max on win its 10.
+ *			Costantino Leandro
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+#define MAX_GAMMA 0x10		/* 0 to 15 */
+
+/* From LUVCVIEW */
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+
+MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+	unsigned char gamma;
+	unsigned char sharpness;
+	unsigned char freq;
+	unsigned char whitebalance;
+	unsigned char mirror;
+	unsigned char effect;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 0,
+	  .maximum = 0x0f,
+	  .step = 1,
+	  .default_value = 0x09,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0x0d,
+	  .step = 1,
+	  .default_value = 0x07,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+#define SD_COLOR 2
+	{
+	 {
+	  .id = V4L2_CID_SATURATION,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Color",
+	  .minimum = 0,
+	  .maximum = 0x0f,
+	  .step = 1,
+	  .default_value = 0x05,
+	  },
+	 .set = sd_setcolors,
+	 .get = sd_getcolors,
+	 },
+#define SD_GAMMA 3
+	{
+	 {
+	  .id = V4L2_CID_GAMMA,	/* (gamma on win) */
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Gamma (Untested)",
+	  .minimum = 0,
+	  .maximum = MAX_GAMMA,
+	  .step = 1,
+	  .default_value = 0x09,
+	  },
+	 .set = sd_setgamma,
+	 .get = sd_getgamma,
+	 },
+#define SD_AUTOGAIN 4
+	{
+	 {
+	  .id = V4L2_CID_GAIN,	/* here, i activate only the lowlight,
+				 * some apps dont bring up the
+				 * backligth_compensation control) */
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Low Light",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 0x01,
+	  },
+	 .set = sd_setlowlight,
+	 .get = sd_getlowlight,
+	 },
+#define SD_MIRROR 5
+	{
+	 {
+	  .id = V4L2_CID_HFLIP,
+	  .type = V4L2_CTRL_TYPE_BOOLEAN,
+	  .name = "Mirror Image",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 0,
+	  },
+	 .set = sd_setflip,
+	 .get = sd_getflip
+	},
+#define SD_LIGHTFREQ 6
+	{
+	 {
+	  .id = V4L2_CID_POWER_LINE_FREQUENCY,
+	  .type = V4L2_CTRL_TYPE_MENU,
+	  .name = "Light Frequency Filter",
+	  .minimum = 1,		/* 1 -> 0x50, 2->0x60 */
+	  .maximum = 2,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setfreq,
+	 .get = sd_getfreq},
+
+#define SD_WHITE_BALANCE 7
+	{
+	 {
+	  .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "White Balance",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setwhitebalance,
+	 .get = sd_getwhitebalance
+	},
+#define SD_SHARPNESS 8		/* (aka definition on win) */
+	{
+	 {
+	  .id = V4L2_CID_SHARPNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Sharpness",
+	  .minimum = 0,
+	  .maximum = MAX_GAMMA,	/* 0 to 16 */
+	  .step = 1,
+	  .default_value = 0x06,
+	  },
+	 .set = sd_setsharpness,
+	 .get = sd_getsharpness,
+	 },
+#define SD_EFFECTS 9
+	{
+	 {
+	  .id = V4L2_CID_EFFECTS,
+	  .type = V4L2_CTRL_TYPE_MENU,
+	  .name = "Webcam Effects",
+	  .minimum = 0,
+	  .maximum = 4,
+	  .step = 1,
+	  .default_value = 0,
+	  },
+	 .set = sd_seteffect,
+	 .get = sd_geteffect
+	},
+};
+
+static char *effects_control[] = {
+	"Normal",
+	"Emboss",		/* disabled */
+	"Monochrome",
+	"Sepia",
+	"Sketch",
+	"Sun Effect",		/* disabled */
+	"Negative",
+};
+
+static struct v4l2_pix_format vga_mode_t16[] = {
+	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 4},
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 3},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+static const __u8 effects_table[MAX_EFFECTS][6] = {
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
+	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},	/* Monochrome */
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},	/* Sepia */
+	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},	/* Croquis */
+	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},	/* Sun Effect */
+	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
+};
+
+static const __u8 gamma_table[MAX_GAMMA][34] = {
+	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+	 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+	 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
+	 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
+	 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
+	 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
+	 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
+	 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
+	 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
+	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
+	 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
+	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+	 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+	 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
+	 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+	 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+	 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
+	 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+	 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+	 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+	 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
+	 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
+	 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
+	 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
+	 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
+	 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
+	 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+	 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+	 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+	 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
+	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
+	 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
+	 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
+	 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
+	 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
+	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
+	 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
+	 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
+	 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
+	 0xA0, 0xFF},
+	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
+	 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
+	 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
+	 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
+	 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
+	 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
+	 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
+	 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
+	 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
+	 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
+	 0xA0, 0xFF}
+};
+
+static const __u8 tas5130a_sensor_init[][8] = {
+	{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+	{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+	{},
+};
+
+/* read 1 byte */
+static int reg_r_1(struct gspca_dev *gspca_dev,
+		   __u16 index)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0,		/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			gspca_dev->usb_buf, 1, 500);
+	return gspca_dev->usb_buf[0];
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+			__u16 value,
+			__u16 index,
+			const __u8 *buffer, __u16 len)
+{
+	if (buffer == NULL) {
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0,
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				value, index,
+				NULL, 0, 500);
+		return;
+	}
+	if (len <= sizeof gspca_dev->usb_buf) {
+		memcpy(gspca_dev->usb_buf, buffer, len);
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0,
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				value, index,
+				gspca_dev->usb_buf, len, 500);
+	} else {
+		__u8 *tmpbuf;
+
+		tmpbuf = kmalloc(len, GFP_KERNEL);
+		memcpy(tmpbuf, buffer, len);
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0,
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				value, index,
+				tmpbuf, len, 500);
+		kfree(tmpbuf);
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+
+	cam->cam_mode = vga_mode_t16;
+	cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+	sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+	sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+	sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+	sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+	return 0;
+}
+
+static int init_default_parameters(struct gspca_dev *gspca_dev)
+{
+	/* some of this registers are not really neded, because
+	 * they are overriden by setbrigthness, setcontrast, etc,
+	 * but wont hurt anyway, and can help someone with similar webcam
+	 * to see the initial parameters.*/
+	int i = 0;
+	__u8 test_byte;
+
+	static const __u8 read_indexs[] =
+		{ 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+	static const __u8 n1[6] =
+			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+	static const __u8 n2[2] =
+			{0x08, 0x00};
+	static const __u8 nset[6] =
+		{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+	static const __u8 n3[6] =
+			{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+	static const __u8 n4[0x46] =
+		{0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+		 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+		 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+		 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+		 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+		 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+		 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+		 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+		 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+	static const __u8 nset4[18] = {
+		0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
+		0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+		0xe8, 0xe0
+	};
+	/* ojo puede ser 0xe6 en vez de 0xe9 */
+	static const __u8 nset2[20] = {
+		0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
+		0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+		0xd8, 0xc8, 0xd9, 0xfc
+	};
+	static const __u8 missing[8] =
+		{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+	static const __u8 nset3[18] = {
+		0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
+		0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+		0xcf, 0xe0
+	};
+	static const __u8 nset5[4] =
+		{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
+	static const __u8 nset6[34] = {
+		0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
+		0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+		0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
+		0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
+		0xa0, 0xff
+	};			/* Gamma */
+	static const __u8 nset7[4] =
+			{ 0x66, 0xca, 0xa8, 0xf8 };	/* 50/60 Hz */
+	static const __u8 nset9[4] =
+			{ 0x0b, 0x04, 0x0a, 0x78 };
+	static const __u8 nset8[6] =
+			{ 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+	static const __u8 nset10[6] =
+			{ 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
+
+	reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
+	reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
+	reg_r_1(gspca_dev, 0x0063);
+	reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
+
+	while (read_indexs[i] != 0x00) {
+		test_byte = reg_r_1(gspca_dev, read_indexs[i]);
+		PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
+		       test_byte);
+		i++;
+	}
+
+	reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
+	reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
+	reg_r_1(gspca_dev, 0x0080);
+	reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
+	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
+	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
+	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
+	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
+	reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
+	reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
+	reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
+	reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
+	reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
+	reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+
+	reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
+
+	reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
+	reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
+	reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
+
+	reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
+	reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
+	reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
+	reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
+
+	reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
+	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
+	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
+	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned int brightness;
+	__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
+	brightness = sd->brightness;
+
+	if (brightness < 7) {
+		set6[3] = 0x70 - (brightness * 0xa);
+	} else {
+		set6[1] = 0x24;
+		set6[3] = 0x00 + ((brightness - 7) * 0xa);
+	}
+
+	reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	__u8 flipcmd[8] =
+	    { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+
+	if (sd->mirror == 1)
+		flipcmd[3] = 0x01;
+
+	reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+	if (sd->effect == 1 || sd->effect == 5) {
+		PDEBUG(D_CONF,
+		       "This effect have been disabled for webcam \"safety\"");
+		return;
+	}
+
+	if (sd->effect == 1 || sd->effect == 4)
+		reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+	else
+		reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	__u8 white_balance[8] =
+	    { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+
+	if (sd->whitebalance == 1)
+		white_balance[7] = 0x3c;
+
+	reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+	if (sd->freq == 2)	/* 60hz */
+		freq[1] = 0x00;
+
+	reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned int contrast = sd->contrast;
+	__u16 reg_to_write = 0x00;
+
+	if (contrast < 7)
+		reg_to_write = 0x8ea9 - (0x200 * contrast);
+	else
+		reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
+
+	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 reg_to_write;
+
+	reg_to_write = 0xc0bb + sd->colors * 0x100;
+	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 reg_to_write;
+
+	reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return *val;
+}
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->whitebalance = val;
+	if (gspca_dev->streaming)
+		setwhitebalance(gspca_dev);
+	return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->whitebalance;
+	return *val;
+}
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->mirror = val;
+	if (gspca_dev->streaming)
+		setflip(gspca_dev);
+	return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->mirror;
+	return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->effect = val;
+	if (gspca_dev->streaming)
+		seteffect(gspca_dev);
+	return 0;
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->effect;
+	return *val;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gamma = val;
+	if (gspca_dev->streaming)
+		setgamma(gspca_dev);
+	return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	*val = sd->gamma;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->freq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->freq;
+	return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->sharpness = val;
+	if (gspca_dev->streaming)
+		setsharpness(gspca_dev);
+	return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->sharpness;
+	return 0;
+}
+
+/* Low Light set  here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val != 0)
+		reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
+	else
+		reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
+	return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	int mode;
+
+	static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+	static const __u8 t3[] =
+		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+	static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+	switch (mode) {
+	case 1:		/* 352x288 */
+		t2[1] = 0x40;
+		break;
+	case 2:		/* 320x240 */
+		t2[1] = 0x10;
+		break;
+	case 3:		/* 176x144 */
+		t2[1] = 0x50;
+		break;
+	case 4:		/* 160x120 */
+		t2[1] = 0x20;
+		break;
+	default:	/* 640x480 (0x00) */
+		break;
+	}
+
+	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
+	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
+	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
+	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
+		/* just in case and to keep sync with logs  (for mine) */
+	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
+		/* just in case and to keep sync with logs  (for mine) */
+	reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
+	reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
+	reg_r_1(gspca_dev, 0x0012);
+	reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
+	reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
+	reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
+	/* restart on each start, just in case, sometimes regs goes wrong
+	 * when using controls from app */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	int sof = 0;
+	static __u8 ffd9[] = { 0xff, 0xd9 };
+
+	if (data[0] == 0x5a) {
+		/* Control Packet, after this came the header again,
+		 * but extra bytes came in the packet before this,
+		 * sometimes an EOF arrives, sometimes not... */
+		return;
+	}
+
+	if (data[len - 1] == 0xff && data[len] == 0xd9) {
+		/* Just in case, i have seen packets with the marker,
+		 * other's do not include it... */
+		data += 2;
+		len -= 4;
+	} else if (data[2] == 0xff && data[3] == 0xd8) {
+		sof = 1;
+		data += 2;
+		len -= 2;
+	} else {
+		data += 2;
+		len -= 2;
+	}
+
+	if (sof) {
+		/* extra bytes....., could be processed too but would be
+		 * a waste of time, right now leave the application and
+		 * libjpeg do it for ourserlves.. */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		return;
+	}
+
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	case V4L2_CID_EFFECTS:
+		if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
+			strncpy((char *) menu->name,
+				effects_control[menu->index], 32);
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	init_default_parameters(gspca_dev);
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
new file mode 100644
index 0000000..0b79389
--- /dev/null
+++ b/drivers/media/video/gspca/tv8532.c
@@ -0,0 +1,670 @@
+/*
+ * Quickcam cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ *
+ */
+#define MODULE_NAME "tv8532"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("TV8532 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	int buflen;			/* current length of tmpbuf */
+	__u8 tmpbuf[352 * 288 + 10 * 288];	/* no protection... */
+	__u8 tmpbuf2[352 * 288];		/* no protection... */
+
+	unsigned short brightness;
+	unsigned short contrast;
+
+	char packet;
+	char synchro;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 1,
+	  .maximum = 0x2ff,
+	  .step = 1,
+	  .default_value = 0x18f,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0xffff,
+	  .step = 1,
+	  .default_value = 0x7fff,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+#define TESTCLK 0x10		/* reg 0x2c -> 0x12 //10 */
+#define TESTCOMP 0x90		/* reg 0x28 -> 0x80 */
+#define TESTLINE 0x81		/* reg 0x29 -> 0x81 */
+#define QCIFLINE 0x41		/* reg 0x29 -> 0x81 */
+#define TESTPTL 0x14		/* reg 0x2D -> 0x14 */
+#define TESTPTH 0x01		/* reg 0x2E -> 0x01 */
+#define TESTPTBL 0x12		/* reg 0x2F -> 0x0a */
+#define TESTPTBH 0x01		/* reg 0x30 -> 0x01 */
+#define ADWIDTHL 0xe8		/* reg 0x0c -> 0xe8 */
+#define ADWIDTHH 0x03		/* reg 0x0d -> 0x03 */
+#define ADHEIGHL 0x90		/* reg 0x0e -> 0x91 //93 */
+#define ADHEIGHH 0x01		/* reg 0x0f -> 0x01 */
+#define EXPOL 0x8f		/* reg 0x1c -> 0x8f */
+#define EXPOH 0x01		/* reg 0x1d -> 0x01 */
+#define ADCBEGINL 0x44		/* reg 0x10 -> 0x46 //47 */
+#define ADCBEGINH 0x00		/* reg 0x11 -> 0x00 */
+#define ADRBEGINL 0x0a		/* reg 0x14 -> 0x0b //0x0c */
+#define ADRBEGINH 0x00		/* reg 0x15 -> 0x00 */
+#define TV8532_CMD_UPDATE 0x84
+
+#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_DataL 0x04
+#define TV8532_EEprom_DataM 0x05
+#define TV8532_EEprom_DataH 0x06
+#define TV8532_EEprom_TableLength 0x07
+#define TV8532_EEprom_Write 0x08
+#define TV8532_PART_CTRL 0x00
+#define TV8532_CTRL 0x01
+#define TV8532_CMD_EEprom_Open 0x30
+#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_UDP_UPDATE 0x31
+#define TV8532_GPIO 0x39
+#define TV8532_GPIO_OE 0x3B
+#define TV8532_REQ_RegWrite 0x02
+#define TV8532_REQ_RegRead 0x03
+
+#define TV8532_ADWIDTH_L 0x0C
+#define TV8532_ADWIDTH_H 0x0D
+#define TV8532_ADHEIGHT_L 0x0E
+#define TV8532_ADHEIGHT_H 0x0F
+#define TV8532_EXPOSURE 0x1C
+#define TV8532_QUANT_COMP 0x28
+#define TV8532_MODE_PACKET 0x29
+#define TV8532_SETCLK 0x2C
+#define TV8532_POINT_L 0x2D
+#define TV8532_POINT_H 0x2E
+#define TV8532_POINTB_L 0x2F
+#define TV8532_POINTB_H 0x30
+#define TV8532_BUDGET_L 0x2A
+#define TV8532_BUDGET_H 0x2B
+#define TV8532_VID_L 0x34
+#define TV8532_VID_H 0x35
+#define TV8532_PID_L 0x36
+#define TV8532_PID_H 0x37
+#define TV8532_DeviceID 0x83
+#define TV8532_AD_SLOPE 0x91
+#define TV8532_AD_BITCTRL 0x94
+#define TV8532_AD_COLBEGIN_L 0x10
+#define TV8532_AD_COLBEGIN_H 0x11
+#define TV8532_AD_ROWBEGIN_L 0x14
+#define TV8532_AD_ROWBEGIN_H 0x15
+
+static const __u32 tv_8532_eeprom_data[] = {
+/*	add		dataL	   dataM	dataH */
+	0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+	0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+	0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+	0x0c0509f1, 0
+};
+
+static int reg_r(struct gspca_dev *gspca_dev,
+		 __u16 index)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			TV8532_REQ_RegRead,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,	/* value */
+			index, gspca_dev->usb_buf, 1,
+			500);
+	return gspca_dev->usb_buf[0];
+}
+
+/* write 1 byte */
+static void reg_w_1(struct gspca_dev *gspca_dev,
+		  __u16 index, __u8 value)
+{
+	gspca_dev->usb_buf[0] = value;
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			TV8532_REQ_RegWrite,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,	/* value */
+			index, gspca_dev->usb_buf, 1, 500);
+}
+
+/* write 2 bytes */
+static void reg_w_2(struct gspca_dev *gspca_dev,
+		  __u16 index, __u8 val1, __u8 val2)
+{
+	gspca_dev->usb_buf[0] = val1;
+	gspca_dev->usb_buf[1] = val2;
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			TV8532_REQ_RegWrite,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,	/* value */
+			index, gspca_dev->usb_buf, 2, 500);
+}
+
+static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	__u8 reg, data0, data1, data2;
+
+	reg_w_1(gspca_dev, TV8532_GPIO, 0xb0);
+	reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open);
+/*	msleep(1); */
+	while (tv_8532_eeprom_data[i]) {
+		reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+		reg_w_1(gspca_dev, TV8532_EEprom_Add, reg);
+		/* msleep(1); */
+		data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+		reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0);
+		/* msleep(1); */
+		data1 = (tv_8532_eeprom_data[i] & 0x0000ff00) >> 8;
+		reg_w_1(gspca_dev, TV8532_EEprom_DataM, data1);
+		/* msleep(1); */
+		data2 = (tv_8532_eeprom_data[i] & 0x00ff0000) >> 16;
+		reg_w_1(gspca_dev, TV8532_EEprom_DataH, data2);
+		/* msleep(1); */
+		reg_w_1(gspca_dev, TV8532_EEprom_Write, 0);
+		/* msleep(10); */
+		i++;
+	}
+	reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i);
+/*	msleep(1); */
+	reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close);
+	msleep(10);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	tv_8532WriteEEprom(gspca_dev);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 1;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	return 0;
+}
+
+static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+{
+	__u8 data;
+
+	data = reg_r(gspca_dev, 0x0001);
+	PDEBUG(D_USBI, "register 0x01-> %x", data);
+	data = reg_r(gspca_dev, 0x0002);
+	PDEBUG(D_USBI, "register 0x02-> %x", data);
+	reg_r(gspca_dev, TV8532_ADWIDTH_L);
+	reg_r(gspca_dev, TV8532_ADWIDTH_H);
+	reg_r(gspca_dev, TV8532_QUANT_COMP);
+	reg_r(gspca_dev, TV8532_MODE_PACKET);
+	reg_r(gspca_dev, TV8532_SETCLK);
+	reg_r(gspca_dev, TV8532_POINT_L);
+	reg_r(gspca_dev, TV8532_POINT_H);
+	reg_r(gspca_dev, TV8532_POINTB_L);
+	reg_r(gspca_dev, TV8532_POINTB_H);
+	reg_r(gspca_dev, TV8532_BUDGET_L);
+	reg_r(gspca_dev, TV8532_BUDGET_H);
+	reg_r(gspca_dev, TV8532_VID_L);
+	reg_r(gspca_dev, TV8532_VID_H);
+	reg_r(gspca_dev, TV8532_PID_L);
+	reg_r(gspca_dev, TV8532_PID_H);
+	reg_r(gspca_dev, TV8532_DeviceID);
+	reg_r(gspca_dev, TV8532_AD_COLBEGIN_L);
+	reg_r(gspca_dev, TV8532_AD_COLBEGIN_H);
+	reg_r(gspca_dev, TV8532_AD_ROWBEGIN_L);
+	reg_r(gspca_dev, TV8532_AD_ROWBEGIN_H);
+}
+
+static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+{
+	reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+			ADCBEGINL);			/* 0x10 */
+	reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+			ADCBEGINH);			/* also digital gain */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL,
+			TV8532_CMD_UPDATE);		/* 0x00<-0x84 */
+
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0a);
+	/******************************************************/
+	reg_w_1(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL); /* 0e */
+	reg_w_1(gspca_dev, TV8532_ADHEIGHT_H, ADHEIGHH); /* 0f */
+	reg_w_2(gspca_dev, TV8532_EXPOSURE,
+			EXPOL, EXPOH);			/* 350d 0x014c; 1c */
+	reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_L,
+			ADCBEGINL);			/* 0x10 */
+	reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+			ADCBEGINH);			/* also digital gain */
+	reg_w_1(gspca_dev, TV8532_AD_ROWBEGIN_L,
+			ADRBEGINL);			/* 0x14 */
+
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00);	/* 0x91 */
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02);	/* 0x94 */
+
+	reg_w_1(gspca_dev, TV8532_CTRL,
+			TV8532_CMD_EEprom_Close);	/* 0x01 */
+
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x00);	/* 0x91 */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL,
+			TV8532_CMD_UPDATE);		/* 0x00<-0x84 */
+}
+
+static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	/* strange polling from tgc */
+	for (i = 0; i < 10; i++) {
+		reg_w_1(gspca_dev, TV8532_SETCLK,
+			TESTCLK);		/* 0x48; //0x08; 0x2c */
+		reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+		reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);	/* 0x31 */
+	}
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+	tv_8532ReadRegisters(gspca_dev);
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+	reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL,
+				ADHEIGHH);	/* 401d 0x0169; 0e */
+	reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL,
+				EXPOH);		/* 350d 0x014c; 1c */
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL);	/* 0x20; 0x0c */
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH);	/* 0x0d */
+
+	/*******************************************************************/
+	reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+			TESTCOMP);	/* 0x72 compressed mode 0x28 */
+	reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+			TESTLINE);	/* 0x84; // CIF | 4 packet 0x29 */
+
+	/************************************************/
+	reg_w_1(gspca_dev, TV8532_SETCLK,
+			TESTCLK);		/* 0x48; //0x08; 0x2c */
+	reg_w_1(gspca_dev, TV8532_POINT_L,
+			TESTPTL);		/* 0x38; 0x2d */
+	reg_w_1(gspca_dev, TV8532_POINT_H,
+			TESTPTH);		/* 0x04; 0x2e */
+	reg_w_1(gspca_dev, TV8532_POINTB_L,
+			TESTPTBL);		/* 0x04; 0x2f */
+	reg_w_1(gspca_dev, TV8532_POINTB_H,
+			TESTPTBH);		/* 0x04; 0x30 */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL,
+			TV8532_CMD_UPDATE);	/* 0x00<-0x84 */
+	/*************************************************/
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);	/* 0x31 */
+	msleep(200);
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);	/* 0x31 */
+	/*************************************************/
+	tv_8532_setReg(gspca_dev);
+	/*************************************************/
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+	/*************************************************/
+	tv_8532_setReg(gspca_dev);
+	/*************************************************/
+	tv_8532_PollReg(gspca_dev);
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int brightness = sd->brightness;
+
+	reg_w_2(gspca_dev, TV8532_EXPOSURE,
+		brightness >> 8, brightness);		/* 1c */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+	tv_8532ReadRegisters(gspca_dev);
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+	reg_w_2(gspca_dev, TV8532_ADHEIGHT_L,
+		ADHEIGHL, ADHEIGHH);	/* 401d 0x0169; 0e */
+/*	reg_w_2(gspca_dev, TV8532_EXPOSURE,
+		EXPOL, EXPOH);		 * 350d 0x014c; 1c */
+	setbrightness(gspca_dev);
+
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL);	/* 0x20; 0x0c */
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH);	/* 0x0d */
+
+	/************************************************/
+	reg_w_1(gspca_dev, TV8532_QUANT_COMP,
+			TESTCOMP);	/* 0x72 compressed mode 0x28 */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+		/* 176x144 */
+		reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+			QCIFLINE);	/* 0x84; // CIF | 4 packet 0x29 */
+	} else {
+		/* 352x288 */
+		reg_w_1(gspca_dev, TV8532_MODE_PACKET,
+			TESTLINE);	/* 0x84; // CIF | 4 packet 0x29 */
+	}
+	/************************************************/
+	reg_w_1(gspca_dev, TV8532_SETCLK,
+			TESTCLK);		/* 0x48; //0x08; 0x2c */
+	reg_w_1(gspca_dev, TV8532_POINT_L,
+			TESTPTL);		/* 0x38; 0x2d */
+	reg_w_1(gspca_dev, TV8532_POINT_H,
+			TESTPTH);		/* 0x04; 0x2e */
+	reg_w_1(gspca_dev, TV8532_POINTB_L,
+			TESTPTBL);		/* 0x04; 0x2f */
+	reg_w_1(gspca_dev, TV8532_POINTB_H,
+			TESTPTBH);		/* 0x04; 0x30 */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL,
+			TV8532_CMD_UPDATE);	/* 0x00<-0x84 */
+	/************************************************/
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);	/* 0x31 */
+	msleep(200);
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);	/* 0x31 */
+	/************************************************/
+	tv_8532_setReg(gspca_dev);
+	/************************************************/
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+	/************************************************/
+	tv_8532_setReg(gspca_dev);
+	/************************************************/
+	tv_8532_PollReg(gspca_dev);
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);	/* 0x31 */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void tv8532_preprocess(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/* we should received a whole frame with header and EOL marker
+ * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
+ * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
+ * Alternate pixels bayer RG 4 bytes EOL */
+	int width = gspca_dev->width;
+	int height = gspca_dev->height;
+	unsigned char *dst = sd->tmpbuf2;
+	unsigned char *data = sd->tmpbuf;
+	int i;
+
+	/* precompute where is the good bayer line */
+	if (((data[3] + data[width + 7]) >> 1)
+	    + (data[4] >> 2)
+	    + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
+	    + (data[3] >> 2)
+	    + (data[width + 5] >> 1))
+		data += 3;
+	else
+		data += 2;
+	for (i = 0; i < height / 2; i++) {
+		memcpy(dst, data, width);
+		data += width + 3;
+		dst += width;
+		memcpy(dst, data, width);
+		data += width + 7;
+		dst += width;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (data[0] != 0x80) {
+		sd->packet++;
+		if (sd->buflen + len > sizeof sd->tmpbuf) {
+			if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+				PDEBUG(D_PACK, "buffer overflow");
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			}
+			return;
+		}
+		memcpy(&sd->tmpbuf[sd->buflen], data, len);
+		sd->buflen += len;
+		return;
+	}
+
+	/* here we detect 0x80 */
+	/* counter is limited so we need few header for a frame :) */
+
+	/* header 0x80 0x80 0x80 0x80 0x80 */
+	/* packet  00   63  127  145  00   */
+	/* sof     0     1   1    0    0   */
+
+	/* update sequence */
+	if (sd->packet == 63 || sd->packet == 127)
+		sd->synchro = 1;
+
+	/* is there a frame start ? */
+	if (sd->packet >= (gspca_dev->height >> 1) - 1) {
+		PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
+		       sd->packet);
+		if (!sd->synchro) {	/* start of frame */
+			if (gspca_dev->last_packet_type == FIRST_PACKET) {
+				tv8532_preprocess(gspca_dev);
+				frame = gspca_frame_add(gspca_dev,
+							LAST_PACKET,
+							frame, sd->tmpbuf2,
+							gspca_dev->width *
+							    gspca_dev->width);
+			}
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					frame, data, 0);
+			memcpy(sd->tmpbuf, data, len);
+			sd->buflen = len;
+			sd->packet = 0;
+			return;
+		}
+		if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+			PDEBUG(D_PACK,
+			       "Warning wrong TV8532 frame detection %d",
+			       sd->packet);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+		}
+		return;
+	}
+
+	if (!sd->synchro) {
+		/* Drop packet frame corrupt */
+		PDEBUG(D_PACK, "DROP SOF %d packet %d",
+		       sd->synchro, sd->packet);
+		sd->packet = 0;
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+		return;
+	}
+	sd->synchro = 1;
+	sd->packet++;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")},
+	{USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")},
+	{USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")},
+	{USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")},
+	{USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
new file mode 100644
index 0000000..fcf2c9e
--- /dev/null
+++ b/drivers/media/video/gspca/vc032x.c
@@ -0,0 +1,1818 @@
+/*
+ *		Z-star vc0321 library
+ *		Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ *		Copyright (C) 2006 Michel Xhaard
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char autogain;
+	unsigned char lightfreq;
+
+	char qindex;
+	char bridge;
+#define BRIDGE_VC0321 0
+#define BRIDGE_VC0323 1
+	char sensor;
+#define SENSOR_HV7131R 0
+#define SENSOR_MI1320 1
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_PO3130NC 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define AUTOGAIN_DEF 1
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+	{
+	    {
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 0,
+		.maximum = 2,	/* 0: No, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+#define FREQ_DEF 1
+		.default_value = FREQ_DEF,
+		.default_value = 1,
+	    },
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
+};
+
+static struct v4l2_pix_format vc0321_mode[] = {
+	{320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+		.bytesperline = 320 * 2,
+		.sizeimage = 320 * 240 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+		.bytesperline = 640 * 2,
+		.sizeimage = 640 * 480 * 2,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+static struct v4l2_pix_format vc0323_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+static const __u8 mi1310_socinitVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x64, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x00, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x03, 0xcc},
+	{0xb3, 0x23, 0xc0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x04, 0xcc},
+	{0xb3, 0x17, 0xff, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb8, 0x00, 0x00, 0xcc},
+	{0xbc, 0x00, 0xd0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x9f, 0x0b, 0xbb},
+	{0x5b, 0x00, 0x01, 0xbb},
+	{0x2f, 0xde, 0x20, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x05, 0x00, 0x07, 0xbb},
+	{0x34, 0x00, 0x00, 0xbb},
+	{0x35, 0xff, 0x00, 0xbb},
+	{0xdc, 0x07, 0x02, 0xbb},
+	{0xdd, 0x3c, 0x18, 0xbb},
+	{0xde, 0x92, 0x6d, 0xbb},
+	{0xdf, 0xcd, 0xb1, 0xbb},
+	{0xe0, 0xff, 0xe7, 0xbb},
+	{0x06, 0xf0, 0x0d, 0xbb},
+	{0x06, 0x70, 0x0e, 0xbb},
+	{0x4c, 0x00, 0x01, 0xbb},
+	{0x4d, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x2e, 0x0c, 0x55, 0xbb},
+	{0x21, 0xb6, 0x6e, 0xbb},
+	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc1, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x07, 0x00, 0x84, 0xbb},
+	{0x08, 0x02, 0x4a, 0xbb},
+	{0x05, 0x01, 0x10, 0xbb},
+	{0x06, 0x00, 0x39, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x58, 0x02, 0x67, 0xbb},
+	{0x57, 0x02, 0x00, 0xbb},
+	{0x5a, 0x02, 0x67, 0xbb},
+	{0x59, 0x02, 0x00, 0xbb},
+	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},
+	{0x39, 0x06, 0x18, 0xbb},
+	{0x3a, 0x06, 0x18, 0xbb},
+	{0x3b, 0x06, 0x18, 0xbb},
+	{0x3c, 0x06, 0x18, 0xbb},
+	{0x64, 0x7b, 0x5b, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc0, 0xbb},
+	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},
+	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},
+	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x02, 0xcc},
+	{0xb6, 0x02, 0x80, 0xcc},
+	{0xb6, 0x05, 0x01, 0xcc},
+	{0xb6, 0x04, 0xe0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb6, 0x13, 0x25, 0xcc},
+	{0xb6, 0x18, 0x02, 0xcc},
+	{0xb6, 0x17, 0x58, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},
+	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},
+	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},
+	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x80, 0x00, 0x03, 0xbb},
+	{0x81, 0xc7, 0x14, 0xbb},
+	{0x82, 0xeb, 0xe8, 0xbb},
+	{0x83, 0xfe, 0xf4, 0xbb},
+	{0x84, 0xcd, 0x10, 0xbb},
+	{0x85, 0xf3, 0xee, 0xbb},
+	{0x86, 0xff, 0xf1, 0xbb},
+	{0x87, 0xcd, 0x10, 0xbb},
+	{0x88, 0xf3, 0xee, 0xbb},
+	{0x89, 0x01, 0xf1, 0xbb},
+	{0x8a, 0xe5, 0x17, 0xbb},
+	{0x8b, 0xe8, 0xe2, 0xbb},
+	{0x8c, 0xf7, 0xed, 0xbb},
+	{0x8d, 0x00, 0xff, 0xbb},
+	{0x8e, 0xec, 0x10, 0xbb},
+	{0x8f, 0xf0, 0xed, 0xbb},
+	{0x90, 0xf9, 0xf2, 0xbb},
+	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xe9, 0x0d, 0xbb},
+	{0x93, 0xf4, 0xf2, 0xbb},
+	{0x94, 0xfb, 0xf5, 0xbb},
+	{0x95, 0x00, 0xff, 0xbb},
+	{0xb6, 0x0f, 0x08, 0xbb},
+	{0xb7, 0x3d, 0x16, 0xbb},
+	{0xb8, 0x0c, 0x04, 0xbb},
+	{0xb9, 0x1c, 0x07, 0xbb},
+	{0xba, 0x0a, 0x03, 0xbb},
+	{0xbb, 0x1b, 0x09, 0xbb},
+	{0xbc, 0x17, 0x0d, 0xbb},
+	{0xbd, 0x23, 0x1d, 0xbb},
+	{0xbe, 0x00, 0x28, 0xbb},
+	{0xbf, 0x11, 0x09, 0xbb},
+	{0xc0, 0x16, 0x15, 0xbb},
+	{0xc1, 0x00, 0x1b, 0xbb},
+	{0xc2, 0x0e, 0x07, 0xbb},
+	{0xc3, 0x14, 0x10, 0xbb},
+	{0xc4, 0x00, 0x17, 0xbb},
+	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x06, 0xf4, 0x8e, 0xbb},
+	{0x00, 0x00, 0x50, 0xdd},
+	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x24, 0x50, 0x20, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x34, 0x0c, 0x50, 0xbb},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x03, 0x03, 0xc0, 0xbb},
+	{},
+};
+static const __u8 mi1310_socinitQVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},	{0xb3, 0x06, 0x00, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x02, 0x00, 0xcc},	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x03, 0xcc},
+	{0xb3, 0x23, 0xc0, 0xcc},	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},	{0xb3, 0x16, 0x04, 0xcc},
+	{0xb3, 0x17, 0xff, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb8, 0x00, 0x00, 0xcc},	{0xbc, 0x00, 0xf0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x9f, 0x0b, 0xbb},	{0x5b, 0x00, 0x01, 0xbb},
+	{0x2f, 0xde, 0x20, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x05, 0x00, 0x07, 0xbb},	{0x34, 0x00, 0x00, 0xbb},
+	{0x35, 0xff, 0x00, 0xbb},	{0xdc, 0x07, 0x02, 0xbb},
+	{0xdd, 0x3c, 0x18, 0xbb},	{0xde, 0x92, 0x6d, 0xbb},
+	{0xdf, 0xcd, 0xb1, 0xbb},	{0xe0, 0xff, 0xe7, 0xbb},
+	{0x06, 0xf0, 0x0d, 0xbb},	{0x06, 0x70, 0x0e, 0xbb},
+	{0x4c, 0x00, 0x01, 0xbb},	{0x4d, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x2e, 0x0c, 0x55, 0xbb},
+	{0x21, 0xb6, 0x6e, 0xbb},	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc1, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x07, 0x00, 0x84, 0xbb},	{0x08, 0x02, 0x4a, 0xbb},
+	{0x05, 0x01, 0x10, 0xbb},	{0x06, 0x00, 0x39, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x58, 0x02, 0x67, 0xbb},
+	{0x57, 0x02, 0x00, 0xbb},	{0x5a, 0x02, 0x67, 0xbb},
+	{0x59, 0x02, 0x00, 0xbb},	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},	{0x39, 0x06, 0x18, 0xbb},
+	{0x3a, 0x06, 0x18, 0xbb},	{0x3b, 0x06, 0x18, 0xbb},
+	{0x3c, 0x06, 0x18, 0xbb},	{0x64, 0x7b, 0x5b, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc0, 0xbb},	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x01, 0xcc},	{0xb6, 0x02, 0x40, 0xcc},
+	{0xb6, 0x05, 0x00, 0xcc},	{0xb6, 0x04, 0xf0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x25, 0xcc},
+	{0xb6, 0x18, 0x00, 0xcc},	{0xb6, 0x17, 0x96, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x80, 0x00, 0x03, 0xbb},	{0x81, 0xc7, 0x14, 0xbb},
+	{0x82, 0xeb, 0xe8, 0xbb},	{0x83, 0xfe, 0xf4, 0xbb},
+	{0x84, 0xcd, 0x10, 0xbb},	{0x85, 0xf3, 0xee, 0xbb},
+	{0x86, 0xff, 0xf1, 0xbb},	{0x87, 0xcd, 0x10, 0xbb},
+	{0x88, 0xf3, 0xee, 0xbb},	{0x89, 0x01, 0xf1, 0xbb},
+	{0x8a, 0xe5, 0x17, 0xbb},	{0x8b, 0xe8, 0xe2, 0xbb},
+	{0x8c, 0xf7, 0xed, 0xbb},	{0x8d, 0x00, 0xff, 0xbb},
+	{0x8e, 0xec, 0x10, 0xbb},	{0x8f, 0xf0, 0xed, 0xbb},
+	{0x90, 0xf9, 0xf2, 0xbb},	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xe9, 0x0d, 0xbb},	{0x93, 0xf4, 0xf2, 0xbb},
+	{0x94, 0xfb, 0xf5, 0xbb},	{0x95, 0x00, 0xff, 0xbb},
+	{0xb6, 0x0f, 0x08, 0xbb},	{0xb7, 0x3d, 0x16, 0xbb},
+	{0xb8, 0x0c, 0x04, 0xbb},	{0xb9, 0x1c, 0x07, 0xbb},
+	{0xba, 0x0a, 0x03, 0xbb},	{0xbb, 0x1b, 0x09, 0xbb},
+	{0xbc, 0x17, 0x0d, 0xbb},	{0xbd, 0x23, 0x1d, 0xbb},
+	{0xbe, 0x00, 0x28, 0xbb},	{0xbf, 0x11, 0x09, 0xbb},
+	{0xc0, 0x16, 0x15, 0xbb},	{0xc1, 0x00, 0x1b, 0xbb},
+	{0xc2, 0x0e, 0x07, 0xbb},	{0xc3, 0x14, 0x10, 0xbb},
+	{0xc4, 0x00, 0x17, 0xbb},	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x06, 0xf4, 0x8e, 0xbb},
+	{0x00, 0x00, 0x50, 0xdd},	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x24, 0x50, 0x20, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x34, 0x0c, 0x50, 0xbb},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x03, 0x03, 0xc0, 0xbb},
+	{},
+};
+
+static const __u8 mi1320_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 mi1320_matrix[9] = {
+	0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static const __u8 mi1320_initVGA_data[][4] = {
+	{0xb3, 0x01, 0x01, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb0, 0x16, 0x03, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x00, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xc8, 0xcc},	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x03, 0xcc},	{0xb3, 0x23, 0xc0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x04, 0xcc},	{0xb3, 0x17, 0xff, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},	{0xbc, 0x00, 0xd0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x0d, 0x00, 0x09, 0xbb},	{0x00, 0x01, 0x00, 0xdd},
+	{0x0d, 0x00, 0x08, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0xa1, 0x05, 0x00, 0xbb},	{0xa4, 0x03, 0xc0, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xc8, 0x9f, 0x0b, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0x20, 0x01, 0x00, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x9d, 0x3c, 0xa0, 0xbb},
+	{0x47, 0x30, 0x30, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x0a, 0x80, 0x11, 0xbb},	{0x35, 0x00, 0x22, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x9d, 0xc5, 0x05, 0xbb},
+	{0xdc, 0x0f, 0xfc, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x06, 0x74, 0x0e, 0xbb},	{0x80, 0x00, 0x06, 0xbb},
+	{0x81, 0x04, 0x00, 0xbb},	{0x82, 0x01, 0x02, 0xbb},
+	{0x83, 0x03, 0x02, 0xbb},	{0x84, 0x05, 0x00, 0xbb},
+	{0x85, 0x01, 0x00, 0xbb},	{0x86, 0x03, 0x02, 0xbb},
+	{0x87, 0x05, 0x00, 0xbb},	{0x88, 0x01, 0x00, 0xbb},
+	{0x89, 0x02, 0x02, 0xbb},	{0x8a, 0xfd, 0x04, 0xbb},
+	{0x8b, 0xfc, 0xfd, 0xbb},	{0x8c, 0xff, 0xfd, 0xbb},
+	{0x8d, 0x00, 0x00, 0xbb},	{0x8e, 0xfe, 0x05, 0xbb},
+	{0x8f, 0xfc, 0xfd, 0xbb},	{0x90, 0xfe, 0xfd, 0xbb},
+	{0x91, 0x00, 0x00, 0xbb},	{0x92, 0xfe, 0x03, 0xbb},
+	{0x93, 0xfd, 0xfe, 0xbb},	{0x94, 0xff, 0xfd, 0xbb},
+	{0x95, 0x00, 0x00, 0xbb},	{0xb6, 0x07, 0x05, 0xbb},
+	{0xb7, 0x13, 0x06, 0xbb},	{0xb8, 0x08, 0x06, 0xbb},
+	{0xb9, 0x14, 0x08, 0xbb},	{0xba, 0x06, 0x05, 0xbb},
+	{0xbb, 0x13, 0x06, 0xbb},	{0xbc, 0x03, 0x01, 0xbb},
+	{0xbd, 0x03, 0x04, 0xbb},	{0xbe, 0x00, 0x02, 0xbb},
+	{0xbf, 0x03, 0x01, 0xbb},	{0xc0, 0x02, 0x04, 0xbb},
+	{0xc1, 0x00, 0x04, 0xbb},	{0xc2, 0x02, 0x01, 0xbb},
+	{0xc3, 0x01, 0x03, 0xbb},	{0xc4, 0x00, 0x04, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x05, 0x01, 0x13, 0xbb},
+	{0x06, 0x00, 0x11, 0xbb},	{0x07, 0x00, 0x85, 0xbb},
+	{0x08, 0x00, 0x27, 0xbb},	{0x20, 0x01, 0x03, 0xbb},
+	{0x21, 0x80, 0x00, 0xbb},	{0x22, 0x0d, 0x0f, 0xbb},
+	{0x24, 0x80, 0x00, 0xbb},	{0x59, 0x00, 0xff, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x39, 0x03, 0x0d, 0xbb},
+	{0x3a, 0x06, 0x1b, 0xbb},	{0x3b, 0x00, 0x95, 0xbb},
+	{0x3c, 0x04, 0xdb, 0xbb},	{0x57, 0x02, 0x00, 0xbb},
+	{0x58, 0x02, 0x66, 0xbb},	{0x59, 0x00, 0xff, 0xbb},
+	{0x5a, 0x01, 0x33, 0xbb},	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},	{0x64, 0x5e, 0x1c, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x2f, 0xd1, 0x00, 0xbb},
+	{0x5b, 0x00, 0x01, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0x36, 0x68, 0x10, 0xbb},	{0x00, 0x00, 0x30, 0xdd},
+	{0x37, 0x82, 0x00, 0xbb},	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x05, 0xcc},	{0xb6, 0x02, 0x00, 0xcc},
+	{0xb6, 0x05, 0x04, 0xcc},	{0xb6, 0x04, 0x00, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x29, 0xcc},
+	{0xb6, 0x18, 0x0a, 0xcc},	{0xb6, 0x17, 0x00, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x26, 0xcc},
+	{0xbf, 0xc1, 0x02, 0xcc},	{0xbf, 0xcc, 0x04, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+static const __u8 mi1320_initQVGA_data[][4] = {
+	{0xb3, 0x01, 0x01, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb0, 0x16, 0x03, 0xcc},	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xc8, 0xcc},	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},	{0xb8, 0x00, 0x00, 0xcc},
+	{0xbc, 0x00, 0xd0, 0xcc},	{0xbc, 0x01, 0x01, 0xcc},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x0d, 0x00, 0x09, 0xbb},
+	{0x00, 0x01, 0x00, 0xdd},	{0x0d, 0x00, 0x08, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x02, 0x00, 0x64, 0xbb},
+	{0x05, 0x01, 0x78, 0xbb},	{0x06, 0x00, 0x11, 0xbb},
+	{0x07, 0x01, 0x42, 0xbb},	{0x08, 0x00, 0x11, 0xbb},
+	{0x20, 0x01, 0x00, 0xbb},	{0x21, 0x80, 0x00, 0xbb},
+	{0x22, 0x0d, 0x0f, 0xbb},	{0x24, 0x80, 0x00, 0xbb},
+	{0x59, 0x00, 0xff, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x9d, 0x3c, 0xa0, 0xbb},	{0x47, 0x30, 0x30, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x0a, 0x80, 0x11, 0xbb},
+	{0x35, 0x00, 0x22, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0x9d, 0xc5, 0x05, 0xbb},	{0xdc, 0x0f, 0xfc, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x06, 0x74, 0x0e, 0xbb},
+	{0x80, 0x00, 0x06, 0xbb},	{0x81, 0x04, 0x00, 0xbb},
+	{0x82, 0x01, 0x02, 0xbb},	{0x83, 0x03, 0x02, 0xbb},
+	{0x84, 0x05, 0x00, 0xbb},	{0x85, 0x01, 0x00, 0xbb},
+	{0x86, 0x03, 0x02, 0xbb},	{0x87, 0x05, 0x00, 0xbb},
+	{0x88, 0x01, 0x00, 0xbb},	{0x89, 0x02, 0x02, 0xbb},
+	{0x8a, 0xfd, 0x04, 0xbb},	{0x8b, 0xfc, 0xfd, 0xbb},
+	{0x8c, 0xff, 0xfd, 0xbb},	{0x8d, 0x00, 0x00, 0xbb},
+	{0x8e, 0xfe, 0x05, 0xbb},	{0x8f, 0xfc, 0xfd, 0xbb},
+	{0x90, 0xfe, 0xfd, 0xbb},	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xfe, 0x03, 0xbb},	{0x93, 0xfd, 0xfe, 0xbb},
+	{0x94, 0xff, 0xfd, 0xbb},	{0x95, 0x00, 0x00, 0xbb},
+	{0xb6, 0x07, 0x05, 0xbb},	{0xb7, 0x13, 0x06, 0xbb},
+	{0xb8, 0x08, 0x06, 0xbb},	{0xb9, 0x14, 0x08, 0xbb},
+	{0xba, 0x06, 0x05, 0xbb},	{0xbb, 0x13, 0x06, 0xbb},
+	{0xbc, 0x03, 0x01, 0xbb},	{0xbd, 0x03, 0x04, 0xbb},
+	{0xbe, 0x00, 0x02, 0xbb},	{0xbf, 0x03, 0x01, 0xbb},
+	{0xc0, 0x02, 0x04, 0xbb},	{0xc1, 0x00, 0x04, 0xbb},
+	{0xc2, 0x02, 0x01, 0xbb},	{0xc3, 0x01, 0x03, 0xbb},
+	{0xc4, 0x00, 0x04, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x00, 0x00, 0xbb},	{0x2e, 0x00, 0x00, 0xbb},
+	{0x2e, 0x0c, 0x5b, 0xbb},	{0x2f, 0xd1, 0x00, 0xbb},
+	{0x39, 0x03, 0xca, 0xbb},	{0x3a, 0x06, 0x80, 0xbb},
+	{0x3b, 0x01, 0x52, 0xbb},	{0x3c, 0x05, 0x40, 0xbb},
+	{0x57, 0x01, 0x9c, 0xbb},	{0x58, 0x01, 0xee, 0xbb},
+	{0x59, 0x00, 0xf0, 0xbb},	{0x5a, 0x01, 0x20, 0xbb},
+	{0x5c, 0x1d, 0x17, 0xbb},	{0x5d, 0x22, 0x1c, 0xbb},
+	{0x64, 0x1e, 0x1c, 0xbb},	{0x5b, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x36, 0x68, 0x10, 0xbb},
+	{0x00, 0x00, 0x30, 0xdd},	{0x37, 0x81, 0x00, 0xbb},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xbf, 0xc0, 0x26, 0xcc},	{0xbf, 0xc1, 0x02, 0xcc},
+	{0xbf, 0xcc, 0x04, 0xcc},	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+
+static const __u8 po3130_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 po3130_matrix[9] = {
+	0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static const __u8 po3130_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x04, 0xcc},	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x03, 0x1a, 0xcc},
+	{0xb3, 0x04, 0x15, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe8, 0xcc},	{0xb8, 0x08, 0xe8, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0xf6, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0x71, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0x00, 0x1e, 0xc6, 0xaa},	{0x00, 0x20, 0x44, 0xaa},
+	{0x00, 0xad, 0x02, 0xaa},	{0x00, 0xae, 0x2c, 0xaa},
+	{0x00, 0x12, 0x08, 0xaa},	{0x00, 0x17, 0x41, 0xaa},
+	{0x00, 0x19, 0x41, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{0x00, 0x21, 0x00, 0xaa},	{0x00, 0x36, 0xc0, 0xaa},
+	{0x00, 0x37, 0xc8, 0xaa},	{0x00, 0x3b, 0x36, 0xaa},
+	{0x00, 0x4b, 0xfe, 0xaa},	{0x00, 0x51, 0x1c, 0xaa},
+	{0x00, 0x52, 0x01, 0xaa},	{0x00, 0x55, 0x0a, 0xaa},
+	{0x00, 0x59, 0x02, 0xaa},	{0x00, 0x5a, 0x04, 0xaa},
+	{0x00, 0x5c, 0x10, 0xaa},	{0x00, 0x5d, 0x10, 0xaa},
+	{0x00, 0x5e, 0x10, 0xaa},	{0x00, 0x5f, 0x10, 0xaa},
+	{0x00, 0x61, 0x00, 0xaa},	{0x00, 0x62, 0x18, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x70, 0x68, 0xaa},
+	{0x00, 0x80, 0x71, 0xaa},	{0x00, 0x81, 0x08, 0xaa},
+	{0x00, 0x82, 0x00, 0xaa},	{0x00, 0x83, 0x55, 0xaa},
+	{0x00, 0x84, 0x06, 0xaa},	{0x00, 0x85, 0x06, 0xaa},
+	{0x00, 0x86, 0x13, 0xaa},	{0x00, 0x87, 0x18, 0xaa},
+	{0x00, 0xaa, 0x3f, 0xaa},	{0x00, 0xab, 0x44, 0xaa},
+	{0x00, 0xb0, 0x68, 0xaa},	{0x00, 0xb5, 0x10, 0xaa},
+	{0x00, 0xb8, 0x20, 0xaa},	{0x00, 0xb9, 0xa0, 0xaa},
+	{0x00, 0xbc, 0x04, 0xaa},	{0x00, 0x8b, 0x40, 0xaa},
+	{0x00, 0x8c, 0x91, 0xaa},	{0x00, 0x8d, 0x8f, 0xaa},
+	{0x00, 0x8e, 0x91, 0xaa},	{0x00, 0x8f, 0x43, 0xaa},
+	{0x00, 0x90, 0x92, 0xaa},	{0x00, 0x91, 0x89, 0xaa},
+	{0x00, 0x92, 0x9d, 0xaa},	{0x00, 0x93, 0x46, 0xaa},
+	{0x00, 0xd6, 0x22, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0xd6, 0x62, 0xaa},
+	{0x00, 0x73, 0x00, 0xaa},	{0x00, 0x74, 0x10, 0xaa},
+	{0x00, 0x75, 0x20, 0xaa},	{0x00, 0x76, 0x2b, 0xaa},
+	{0x00, 0x77, 0x36, 0xaa},	{0x00, 0x78, 0x49, 0xaa},
+	{0x00, 0x79, 0x5a, 0xaa},	{0x00, 0x7a, 0x7f, 0xaa},
+	{0x00, 0x7b, 0x9b, 0xaa},	{0x00, 0x7c, 0xba, 0xaa},
+	{0x00, 0x7d, 0xd4, 0xaa},	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0xd6, 0xa2, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0x4c, 0x07, 0xaa},
+	{0x00, 0x4b, 0xe0, 0xaa},	{0x00, 0x4e, 0x77, 0xaa},
+	{0x00, 0x59, 0x02, 0xaa},	{0x00, 0x4d, 0x0a, 0xaa},
+/*	{0x00, 0xd1, 0x00, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc}, */
+	{0x00, 0xd1, 0x3c, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},	{0x00, 0x05, 0x00, 0xaa},
+	{0xb3, 0x5c, 0x00, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+static const __u8 po3130_rundata[][4] = {
+	{0x00, 0x47, 0x45, 0xaa},	{0x00, 0x48, 0x9b, 0xaa},
+	{0x00, 0x49, 0x3a, 0xaa},	{0x00, 0x4a, 0x01, 0xaa},
+	{0x00, 0x44, 0x40, 0xaa},
+/*	{0x00, 0xd5, 0x7c, 0xaa}, */
+	{0x00, 0xad, 0x04, 0xaa},	{0x00, 0xae, 0x00, 0xaa},
+	{0x00, 0xb0, 0x78, 0xaa},	{0x00, 0x98, 0x02, 0xaa},
+	{0x00, 0x94, 0x25, 0xaa},	{0x00, 0x95, 0x25, 0xaa},
+	{0x00, 0x59, 0x68, 0xaa},	{0x00, 0x44, 0x20, 0xaa},
+	{0x00, 0x17, 0x50, 0xaa},	{0x00, 0x19, 0x50, 0xaa},
+	{0x00, 0xd1, 0x3c, 0xaa},	{0x00, 0xd1, 0x3c, 0xaa},
+	{0x00, 0x1e, 0x06, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{}
+};
+
+static const __u8 po3130_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x09, 0xcc},
+	{0xb3, 0x00, 0x04, 0xcc},	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x03, 0x1a, 0xcc},
+	{0xb3, 0x04, 0x15, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb8, 0x08, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0xf6, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0x00, 0x1e, 0xc6, 0xaa},	{0x00, 0x20, 0x44, 0xaa},
+	{0x00, 0xad, 0x02, 0xaa},	{0x00, 0xae, 0x2c, 0xaa},
+	{0x00, 0x12, 0x08, 0xaa},	{0x00, 0x17, 0x41, 0xaa},
+	{0x00, 0x19, 0x41, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{0x00, 0x21, 0x00, 0xaa},	{0x00, 0x36, 0xc0, 0xaa},
+	{0x00, 0x37, 0xc8, 0xaa},	{0x00, 0x3b, 0x36, 0xaa},
+	{0x00, 0x4b, 0xfe, 0xaa},	{0x00, 0x51, 0x1c, 0xaa},
+	{0x00, 0x52, 0x01, 0xaa},	{0x00, 0x55, 0x0a, 0xaa},
+	{0x00, 0x59, 0x6f, 0xaa},	{0x00, 0x5a, 0x04, 0xaa},
+	{0x00, 0x5c, 0x10, 0xaa},	{0x00, 0x5d, 0x10, 0xaa},
+	{0x00, 0x5e, 0x10, 0xaa},	{0x00, 0x5f, 0x10, 0xaa},
+	{0x00, 0x61, 0x00, 0xaa},	{0x00, 0x62, 0x18, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x70, 0x68, 0xaa},
+	{0x00, 0x80, 0x71, 0xaa},	{0x00, 0x81, 0x08, 0xaa},
+	{0x00, 0x82, 0x00, 0xaa},	{0x00, 0x83, 0x55, 0xaa},
+	{0x00, 0x84, 0x06, 0xaa},	{0x00, 0x85, 0x06, 0xaa},
+	{0x00, 0x86, 0x13, 0xaa},	{0x00, 0x87, 0x18, 0xaa},
+	{0x00, 0xaa, 0x3f, 0xaa},	{0x00, 0xab, 0x44, 0xaa},
+	{0x00, 0xb0, 0x68, 0xaa},	{0x00, 0xb5, 0x10, 0xaa},
+	{0x00, 0xb8, 0x20, 0xaa},	{0x00, 0xb9, 0xa0, 0xaa},
+	{0x00, 0xbc, 0x04, 0xaa},	{0x00, 0x8b, 0x40, 0xaa},
+	{0x00, 0x8c, 0x91, 0xaa},	{0x00, 0x8d, 0x8f, 0xaa},
+	{0x00, 0x8e, 0x91, 0xaa},	{0x00, 0x8f, 0x43, 0xaa},
+	{0x00, 0x90, 0x92, 0xaa},	{0x00, 0x91, 0x89, 0xaa},
+	{0x00, 0x92, 0x9d, 0xaa},	{0x00, 0x93, 0x46, 0xaa},
+	{0x00, 0xd6, 0x22, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0xd6, 0x62, 0xaa},
+	{0x00, 0x73, 0x00, 0xaa},	{0x00, 0x74, 0x10, 0xaa},
+	{0x00, 0x75, 0x20, 0xaa},	{0x00, 0x76, 0x2b, 0xaa},
+	{0x00, 0x77, 0x36, 0xaa},	{0x00, 0x78, 0x49, 0xaa},
+	{0x00, 0x79, 0x5a, 0xaa},	{0x00, 0x7a, 0x7f, 0xaa},
+	{0x00, 0x7b, 0x9b, 0xaa},	{0x00, 0x7c, 0xba, 0xaa},
+	{0x00, 0x7d, 0xd4, 0xaa},	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0xd6, 0xa2, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0x4c, 0x07, 0xaa},
+	{0x00, 0x4b, 0xe0, 0xaa},	{0x00, 0x4e, 0x77, 0xaa},
+	{0x00, 0x59, 0x66, 0xaa},	{0x00, 0x4d, 0x0a, 0xaa},
+	{0x00, 0xd1, 0x00, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},	{0x00, 0x05, 0x00, 0xaa},
+	{0xb3, 0x5c, 0x00, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+
+static const __u8 hv7131r_gamma[17] = {
+/*	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ *	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+	0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
+	0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+};
+static const __u8 hv7131r_matrix[9] = {
+	0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static const __u8 hv7131r_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x01, 0x45, 0xcc},	{0xb3, 0x03, 0x0b, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0x91, 0xcc},	{0xb3, 0x00, 0x27, 0xcc},
+	{0xbc, 0x00, 0x73, 0xcc},
+	{0xb8, 0x00, 0x23, 0xcc},	{0x00, 0x01, 0x0c, 0xaa},
+	{0x00, 0x14, 0x01, 0xaa},	{0x00, 0x15, 0xe6, 0xaa},
+	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x17, 0x86, 0xaa},	{0x00, 0x23, 0x00, 0xaa},
+	{0x00, 0x25, 0x09, 0xaa},	{0x00, 0x26, 0x27, 0xaa},
+	{0x00, 0x27, 0xc0, 0xaa},
+	{0xb8, 0x2c, 0x60, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},	{0xb8, 0x34, 0x65, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},	{0xb8, 0x01, 0x7d, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0x00, 0x30, 0x18, 0xaa},
+	{}
+};
+
+static const __u8 hv7131r_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x03, 0x0b, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0x91, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},
+	{0x00, 0x01, 0x0c, 0xaa},	{0x00, 0x14, 0x01, 0xaa},
+	{0x00, 0x15, 0xe6, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x17, 0x86, 0xaa},
+	{0x00, 0x23, 0x00, 0xaa},	{0x00, 0x25, 0x01, 0xaa},
+	{0x00, 0x26, 0xd4, 0xaa},	{0x00, 0x27, 0xc0, 0xaa},
+	{0xbc, 0x02, 0x08, 0xcc},
+	{0xbc, 0x03, 0x70, 0xcc},	{0xbc, 0x04, 0x08, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x3c, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x04, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb8, 0xfe, 0x02, 0xcc},
+	{0xb8, 0xff, 0x07, 0xcc},	{0xb9, 0x00, 0x14, 0xcc},
+	{0xb9, 0x01, 0x14, 0xcc},	{0xb9, 0x02, 0x14, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x02, 0xcc},	{0xb9, 0x05, 0x05, 0xcc},
+	{0xb9, 0x06, 0x0f, 0xcc},	{0xb9, 0x07, 0x0f, 0xcc},
+	{0xb9, 0x08, 0x0f, 0xcc},
+	{0xb8, 0x2c, 0x60, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x65, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x7d, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},	{0x00, 0x30, 0x18, 0xaa},
+	{}
+};
+
+static const __u8 ov7660_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 ov7660_matrix[9] = {
+	0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static const __u8 ov7660_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},
+	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x21, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x1d, 0x01, 0xcc},
+	{0xb3, 0x1f, 0x02, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+	{0xb8, 0x01, 0x7d, 0xcc},
+	{0xbc, 0x00, 0x73, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
+	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x12, 0x05, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{0x00, 0x40, 0xc1, 0xaa},	{0x00, 0x35, 0x00, 0xaa},
+	{0x00, 0x36, 0x00, 0xaa},
+	{0x00, 0x3c, 0x68, 0xaa},	{0x00, 0x1b, 0x05, 0xaa},
+	{0x00, 0x39, 0x43, 0xaa},
+	{0x00, 0x8d, 0xcf, 0xaa},
+	{0x00, 0x8b, 0xcc, 0xaa},	{0x00, 0x8c, 0xcc, 0xaa},
+	{0x00, 0x0f, 0x62, 0xaa},
+	{0x00, 0x35, 0x84, 0xaa},
+	{0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+	{0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+	{0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+	{0x00, 0x9e, 0x40, 0xaa},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},
+	{0x00, 0x02, 0x80, 0xaa},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},	{0xb9, 0x02, 0x28, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+
+	{0x00, 0x29, 0x3c, 0xaa},	{0xb3, 0x01, 0x45, 0xcc},
+	{}
+};
+static const __u8 ov7660_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x21, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x1d, 0x01, 0xcc},
+	{0xb3, 0x1f, 0x02, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+	{0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+	{0xbc, 0x00, 0xd3, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
+	{0x00, 0x12, 0x80, 0xaa},	{0x00, 0x12, 0x05, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{0x00, 0x40, 0xc1, 0xaa},	{0x00, 0x35, 0x00, 0xaa},
+	{0x00, 0x36, 0x00, 0xaa},
+	{0x00, 0x3c, 0x68, 0xaa},	{0x00, 0x1b, 0x05, 0xaa},
+	{0x00, 0x39, 0x43, 0xaa},	{0x00, 0x8d, 0xcf, 0xaa},
+	{0x00, 0x8b, 0xcc, 0xaa},	{0x00, 0x8c, 0xcc, 0xaa},
+	{0x00, 0x0f, 0x62, 0xaa},	{0x00, 0x35, 0x84, 0xaa},
+	{0x00, 0x3b, 0x08, 0xaa}, /* 0  * Nightframe 1/4 + 50Hz -> 0xC8 */
+	{0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+	{0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+	{0x00, 0x9e, 0x40, 0xaa},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},
+	{0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+	{0xbc, 0x02, 0x08, 0xcc},
+	{0xbc, 0x03, 0x70, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},
+	{0xb8, 0x37, 0x00, 0xcc},
+	{0xbc, 0x04, 0x08, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x3c, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x04, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+/* */
+	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+/* */
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+/* */
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+	{0x00, 0x29, 0x3c, 0xaa},
+	{0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+	{}
+};
+
+static const __u8 ov7660_50HZ[][4] = {
+	{0x00, 0x3b, 0x08, 0xaa},
+	{0x00, 0x9d, 0x40, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{}
+};
+
+static const __u8 ov7660_60HZ[][4] = {
+	{0x00, 0x3b, 0x00, 0xaa},
+	{0x00, 0x9e, 0x40, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{}
+};
+
+static const __u8 ov7660_NoFliker[][4] = {
+	{0x00, 0x13, 0x87, 0xaa},
+	{}
+};
+
+static const __u8 ov7670_initVGA_JPG[][4] = {
+	{0xb3, 0x01, 0x05, 0xcc},
+	{0x00, 0x00, 0x30, 0xdd},	{0xb0, 0x03, 0x19, 0xcc},
+	{0x00, 0x00, 0x10, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0x41, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x02, 0xcc},	{0xb6, 0x02, 0x80, 0xcc},
+	{0xb6, 0x05, 0x01, 0xcc},	{0xb6, 0x04, 0xe0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x13, 0xcc},
+	{0xb6, 0x18, 0x02, 0xcc},	{0xb6, 0x17, 0x58, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x77, 0x05, 0xaa},
+	{},
+};
+
+static const __u8 ov7670_initQVGA_JPG[][4] = {
+	{0xb3, 0x01, 0x05, 0xcc},	{0x00, 0x00, 0x30, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x01, 0xcc},	{0xb6, 0x02, 0x40, 0xcc},
+	{0xb6, 0x05, 0x00, 0xcc},	{0xb6, 0x04, 0xf0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x21, 0xcc},
+	{0xb6, 0x18, 0x00, 0xcc},	{0xb6, 0x17, 0x96, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x77, 0x05, 0xaa },
+	{},
+};
+
+struct sensor_info {
+	int sensorId;
+	__u8 I2cAdd;
+	__u8 IdAdd;
+	__u16 VpId;
+	__u8 m1;
+	__u8 m2;
+	__u8 op;
+	};
+
+static const struct sensor_info sensor_info_data[] = {
+/*      sensorId,         I2cAdd,	IdAdd,  VpId,  m1,    m2,  op */
+	{SENSOR_HV7131R,    0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+	{SENSOR_OV7660,     0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+	{SENSOR_PO3130NC,   0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+	{SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+	{SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+	{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+};
+
+/* read 'len' bytes in gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 req,
+		  __u16 index,
+		  __u16 len)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			1,			/* value */
+			index, gspca_dev->usb_buf, len,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			    __u16 req,
+			    __u16 value,
+			    __u16 index)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0,
+			500);
+}
+
+static void read_sensor_register(struct gspca_dev *gspca_dev,
+				__u16 address, __u16 *value)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 ldata, mdata, hdata;
+	int retry = 50;
+
+	*value = 0;
+
+	reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+	/*PDEBUG(D_PROBE, " I2c Bus Busy Wait  0x%02X ", tmpvalue); */
+	if (!(gspca_dev->usb_buf[0] & 0x02)) {
+		PDEBUG(D_ERR, "I2c Bus Busy Wait %d",
+			gspca_dev->usb_buf[0] & 0x02);
+		return;
+	}
+	reg_w(dev, 0xa0, address, 0xb33a);
+	reg_w(dev, 0xa0, 0x02, 0xb339);
+
+	reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+	while (retry-- && gspca_dev->usb_buf[0]) {
+		reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+/*		PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+		msleep(1);
+	}
+	reg_r(gspca_dev, 0xa1, 0xb33e, 1);
+	hdata = gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0xa1, 0xb33d, 1);
+	mdata = gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0xa1, 0xb33c, 1);
+	ldata = gspca_dev->usb_buf[0];
+	PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+		hdata, mdata, ldata);
+	reg_r(gspca_dev, 0xa1, 0xb334, 1);
+	if (gspca_dev->usb_buf[0] == 0x02)
+		*value = (ldata << 8) + mdata;
+	else
+		*value = ldata;
+}
+
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+	__u16 value;
+	const struct sensor_info *ptsensor_info;
+
+	reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
+	PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]);
+	for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
+		ptsensor_info = &sensor_info_data[i];
+		reg_w(dev, 0xa0, 0x02, 0xb334);
+		reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
+		reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
+		reg_w(dev, 0xa0, 0x01, 0xb308);
+		reg_w(dev, 0xa0, 0x0c, 0xb309);
+		reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+/*		PDEBUG(D_PROBE,
+			"check sensor VC032X -> %d Add -> ox%02X!",
+			i, ptsensor_info->I2cAdd); */
+		reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+		read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
+		if (value == ptsensor_info->VpId) {
+/*			PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
+				ptsensor_info->VpId); */
+			return ptsensor_info->sensorId;
+		}
+	}
+	return -1;
+}
+
+static __u8 i2c_write(struct gspca_dev *gspca_dev,
+			__u8 reg, const __u8 *val, __u8 size)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	if (size > 3 || size < 1)
+		return -EINVAL;
+	reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+	reg_w(dev, 0xa0, size, 0xb334);
+	reg_w(dev, 0xa0, reg, 0xb33a);
+	switch (size) {
+	case 1:
+		reg_w(dev, 0xa0, val[0], 0xb336);
+		break;
+	case 2:
+		reg_w(dev, 0xa0, val[0], 0xb336);
+		reg_w(dev, 0xa0, val[1], 0xb337);
+		break;
+	case 3:
+		reg_w(dev, 0xa0, val[0], 0xb336);
+		reg_w(dev, 0xa0, val[1], 0xb337);
+		reg_w(dev, 0xa0, val[2], 0xb338);
+		break;
+	default:
+		reg_w(dev, 0xa0, 0x01, 0xb334);
+		return -EINVAL;
+	}
+	reg_w(dev, 0xa0, 0x01, 0xb339);
+	reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+	return gspca_dev->usb_buf[0] == 0;
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+			const __u8 *tab, __u8 tabsize, __u16 addr)
+{
+	int j;
+	__u16 ad = addr;
+
+	for (j = 0; j < tabsize; j++)
+		reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+			const __u8 data[][4])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i = 0;
+
+	for (;;) {
+		switch (data[i][3]) {
+		default:
+			return;
+		case 0xcc:			/* normal write */
+			reg_w(dev, 0xa0, data[i][2],
+					((data[i][0])<<8) | data[i][1]);
+			break;
+		case 0xaa:			/* i2c op */
+			i2c_write(gspca_dev, data[i][1], &data[i][2], 1);
+			break;
+		case 0xbb:			/* i2c op */
+			i2c_write(gspca_dev, data[i][0], &data[i][1], 2);
+			break;
+		case 0xdd:
+			msleep(data[i][2] + 10);
+			break;
+		}
+		i++;
+	}
+	/*not reached*/
+}
+
+/*
+ "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+ "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+ */
+
+static void vc0321_reset(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+	reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+	msleep(100);
+	reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+	msleep(100);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	int sensor;
+	__u16 product;
+
+	product = id->idProduct;
+	sd->bridge = BRIDGE_VC0321;
+	switch (id->idVendor) {
+	case 0x0ac8:		/* Vimicro z-star */
+		switch (product) {
+		case 0x0323:
+			sd->bridge = BRIDGE_VC0323;
+			break;
+		}
+		break;
+	case 0x17ef:		/* Lenovo */
+/*		switch (product) { */
+/*		case 0x4802:	 * Lenovo MI1310_SOC */
+			sd->bridge = BRIDGE_VC0323;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x02;
+	if (sd->bridge == BRIDGE_VC0321) {
+		cam->cam_mode = vc0321_mode;
+		cam->nmodes = ARRAY_SIZE(vc0321_mode);
+	} else {
+		cam->cam_mode = vc0323_mode;
+		cam->nmodes = ARRAY_SIZE(vc0323_mode);
+	}
+
+	vc0321_reset(gspca_dev);
+	sensor = vc032x_probe_sensor(gspca_dev);
+	switch (sensor) {
+	case -1:
+		PDEBUG(D_PROBE, "Unknown sensor...");
+		return -EINVAL;
+	case SENSOR_HV7131R:
+		PDEBUG(D_PROBE, "Find Sensor HV7131R");
+		sd->sensor = SENSOR_HV7131R;
+		break;
+	case SENSOR_MI1310_SOC:
+		PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+		sd->sensor = SENSOR_MI1310_SOC;
+		break;
+	case SENSOR_MI1320:
+		PDEBUG(D_PROBE, "Find Sensor MI1320");
+		sd->sensor = SENSOR_MI1320;
+		break;
+	case SENSOR_OV7660:
+		PDEBUG(D_PROBE, "Find Sensor OV7660");
+		sd->sensor = SENSOR_OV7660;
+		break;
+	case SENSOR_OV7670:
+		PDEBUG(D_PROBE, "Find Sensor OV7670");
+		sd->sensor = SENSOR_OV7670;
+		break;
+	case SENSOR_PO3130NC:
+		PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+		sd->sensor = SENSOR_PO3130NC;
+		break;
+	}
+
+	sd->qindex = 7;
+	sd->autogain = AUTOGAIN_DEF;
+	sd->lightfreq = FREQ_DEF;
+
+	if (sd->bridge == BRIDGE_VC0321) {
+		reg_r(gspca_dev, 0x8a, 0, 3);
+		reg_w(dev, 0x87, 0x00, 0x0f0f);
+
+		reg_r(gspca_dev, 0x8b, 0, 3);
+		reg_w(dev, 0x88, 0x00, 0x0202);
+	}
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static const __u8 (*ov7660_freq_tb[3])[4] =
+		{ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+	if (sd->sensor != SENSOR_OV7660)
+		return;
+	usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	const __u8 *GammaT = NULL;
+	const __u8 *MatrixT = NULL;
+	int mode;
+
+	/* Assume start use the good resolution from gspca_dev->mode */
+	if (sd->bridge == BRIDGE_VC0321) {
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+	}
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		GammaT = hv7131r_gamma;
+		MatrixT = hv7131r_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, hv7131r_initVGA_data);
+		}
+		break;
+	case SENSOR_OV7660:
+		GammaT = ov7660_gamma;
+		MatrixT = ov7660_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, ov7660_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, ov7660_initVGA_data);
+		}
+		break;
+	case SENSOR_OV7670:
+		/*GammaT = ov7660_gamma; */
+		/*MatrixT = ov7660_matrix; */
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+		}
+		break;
+	case SENSOR_MI1310_SOC:
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+		}
+		break;
+	case SENSOR_MI1320:
+		GammaT = mi1320_gamma;
+		MatrixT = mi1320_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, mi1320_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, mi1320_initVGA_data);
+		}
+		break;
+	case SENSOR_PO3130NC:
+		GammaT = po3130_gamma;
+		MatrixT = po3130_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, po3130_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, po3130_initVGA_data);
+		}
+		usb_exchange(gspca_dev, po3130_rundata);
+		break;
+	default:
+		PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+		return;
+	}
+	if (GammaT && MatrixT) {
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+		put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+		/* Seem SHARPNESS */
+		/*
+		reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+		*/
+		/* all 0x40 ??? do nothing
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+		*/
+		/* Only works for HV7131R ??
+		reg_r (gspca_dev, 0xa1, 0xb881, 1);
+		reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+		reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+		*/
+		/* only hv7131r et ov7660
+		reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+		reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+		*/
+		/* set the led on 0x0892 0x0896 */
+		reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+		msleep(100);
+		setquality(gspca_dev);
+		setautogain(gspca_dev);
+		setlightfreq(gspca_dev);
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+	reg_w(dev, 0xa0, 0x01, 0xb301);
+	reg_w(dev, 0xa0, 0x09, 0xb003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+/*	struct usb_device *dev = gspca_dev->dev;
+	__u8 buffread;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+	reg_w(dev, 0xa0, 0x01, 0xb301);
+	reg_w(dev, 0xa0, 0x09, 0xb303);
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+*/
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso pkt length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (data[0] == 0xff && data[1] == 0xd8) {
+		PDEBUG(D_PACK,
+			"vc032x header packet found len %d", len);
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+						data, 0);
+		if (sd->bridge == BRIDGE_VC0321) {
+#define VCHDRSZ 46
+			data += VCHDRSZ;
+			len -= VCHDRSZ;
+#undef VCHDRSZ
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, len);
+		return;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy((char *) menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")},
+	{USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")},
+	{USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")},
+	{USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")},
+	{USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")},
+	{USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")},
+	{USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")},
+	{USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/zc3xx-reg.h b/drivers/media/video/gspca/zc3xx-reg.h
new file mode 100644
index 0000000..f52e09c
--- /dev/null
+++ b/drivers/media/video/gspca/zc3xx-reg.h
@@ -0,0 +1,261 @@
+/*
+ * zc030x registers
+ *
+ * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * The register aliases used here came from this driver:
+ *	http://zc0302.sourceforge.net/zc0302.php
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+/* Define the register map */
+#define ZC3XX_R000_SYSTEMCONTROL       0x0000
+#define ZC3XX_R001_SYSTEMOPERATING     0x0001
+
+/* Picture size */
+#define ZC3XX_R002_CLOCKSELECT         0x0002
+#define ZC3XX_R003_FRAMEWIDTHHIGH      0x0003
+#define ZC3XX_R004_FRAMEWIDTHLOW       0x0004
+#define ZC3XX_R005_FRAMEHEIGHTHIGH     0x0005
+#define ZC3XX_R006_FRAMEHEIGHTLOW      0x0006
+
+/* JPEG control */
+#define ZC3XX_R008_CLOCKSETTING        0x0008
+
+/* Test mode */
+#define ZC3XX_R00B_TESTMODECONTROL     0x000b
+
+/* Frame retreiving */
+#define ZC3XX_R00C_LASTACQTIME         0x000c
+#define ZC3XX_R00D_MONITORRES          0x000d
+#define ZC3XX_R00E_TIMESTAMPHIGH       0x000e
+#define ZC3XX_R00F_TIMESTAMPLOW        0x000f
+#define ZC3XX_R018_FRAMELOST           0x0018
+#define ZC3XX_R019_AUTOADJUSTFPS       0x0019
+#define ZC3XX_R01A_LASTFRAMESTATE      0x001a
+#define ZC3XX_R025_DATACOUNTER         0x0025
+
+/* Stream and sensor specific */
+#define ZC3XX_R010_CMOSSENSORSELECT    0x0010
+#define ZC3XX_R011_VIDEOSTATUS         0x0011
+#define ZC3XX_R012_VIDEOCONTROLFUNC    0x0012
+
+/* Horizontal and vertical synchros */
+#define ZC3XX_R01D_HSYNC_0             0x001d
+#define ZC3XX_R01E_HSYNC_1             0x001e
+#define ZC3XX_R01F_HSYNC_2             0x001f
+#define ZC3XX_R020_HSYNC_3             0x0020
+
+/* Target picture size in byte */
+#define ZC3XX_R022_TARGETPICTSIZE_0    0x0022
+#define ZC3XX_R023_TARGETPICTSIZE_1    0x0023
+#define ZC3XX_R024_TARGETPICTSIZE_2    0x0024
+
+/* Audio registers */
+#define ZC3XX_R030_AUDIOADC            0x0030
+#define ZC3XX_R031_AUDIOSTREAMSTATUS   0x0031
+#define ZC3XX_R032_AUDIOSTATUS         0x0032
+
+/* Sensor interface */
+#define ZC3XX_R080_HBLANKHIGH          0x0080
+#define ZC3XX_R081_HBLANKLOW           0x0081
+#define ZC3XX_R082_RESETLEVELADDR      0x0082
+#define ZC3XX_R083_RGAINADDR           0x0083
+#define ZC3XX_R084_GGAINADDR           0x0084
+#define ZC3XX_R085_BGAINADDR           0x0085
+#define ZC3XX_R086_EXPTIMEHIGH         0x0086
+#define ZC3XX_R087_EXPTIMEMID          0x0087
+#define ZC3XX_R088_EXPTIMELOW          0x0088
+#define ZC3XX_R089_RESETBLACKHIGH      0x0089
+#define ZC3XX_R08A_RESETWHITEHIGH      0x008a
+#define ZC3XX_R08B_I2CDEVICEADDR       0x008b
+#define ZC3XX_R08C_I2CIDLEANDNACK      0x008c
+#define ZC3XX_R08D_COMPABILITYMODE     0x008d
+#define ZC3XX_R08E_COMPABILITYMODE2    0x008e
+
+/* I2C control */
+#define ZC3XX_R090_I2CCOMMAND          0x0090
+#define ZC3XX_R091_I2CSTATUS           0x0091
+#define ZC3XX_R092_I2CADDRESSSELECT    0x0092
+#define ZC3XX_R093_I2CSETVALUE         0x0093
+#define ZC3XX_R094_I2CWRITEACK         0x0094
+#define ZC3XX_R095_I2CREAD             0x0095
+#define ZC3XX_R096_I2CREADACK          0x0096
+
+/* Window inside the sensor array */
+#define ZC3XX_R097_WINYSTARTHIGH       0x0097
+#define ZC3XX_R098_WINYSTARTLOW        0x0098
+#define ZC3XX_R099_WINXSTARTHIGH       0x0099
+#define ZC3XX_R09A_WINXSTARTLOW        0x009a
+#define ZC3XX_R09B_WINHEIGHTHIGH       0x009b
+#define ZC3XX_R09C_WINHEIGHTLOW        0x009c
+#define ZC3XX_R09D_WINWIDTHHIGH        0x009d
+#define ZC3XX_R09E_WINWIDTHLOW         0x009e
+#define ZC3XX_R119_FIRSTYHIGH          0x0119
+#define ZC3XX_R11A_FIRSTYLOW           0x011a
+#define ZC3XX_R11B_FIRSTXHIGH          0x011b
+#define ZC3XX_R11C_FIRSTXLOW           0x011c
+
+/* Max sensor array size */
+#define ZC3XX_R09F_MAXXHIGH            0x009f
+#define ZC3XX_R0A0_MAXXLOW             0x00a0
+#define ZC3XX_R0A1_MAXYHIGH            0x00a1
+#define ZC3XX_R0A2_MAXYLOW             0x00a2
+#define ZC3XX_R0A3_EXPOSURETIMEHIGH    0x00a3
+#define ZC3XX_R0A4_EXPOSURETIMELOW     0x00a4
+#define ZC3XX_R0A5_EXPOSUREGAIN        0x00a5
+#define ZC3XX_R0A6_EXPOSUREBLACKLVL    0x00a6
+
+/* Other registers */
+#define ZC3XX_R100_OPERATIONMODE       0x0100
+#define ZC3XX_R101_SENSORCORRECTION    0x0101
+
+/* Gains */
+#define ZC3XX_R116_RGAIN               0x0116
+#define ZC3XX_R117_GGAIN               0x0117
+#define ZC3XX_R118_BGAIN               0x0118
+#define ZC3XX_R11D_GLOBALGAIN          0x011d
+#define ZC3XX_R1A8_DIGITALGAIN         0x01a8
+#define ZC3XX_R1A9_DIGITALLIMITDIFF    0x01a9
+#define ZC3XX_R1AA_DIGITALGAINSTEP     0x01aa
+
+/* Auto correction */
+#define ZC3XX_R180_AUTOCORRECTENABLE   0x0180
+#define ZC3XX_R181_WINXSTART           0x0181
+#define ZC3XX_R182_WINXWIDTH           0x0182
+#define ZC3XX_R183_WINXCENTER          0x0183
+#define ZC3XX_R184_WINYSTART           0x0184
+#define ZC3XX_R185_WINYWIDTH           0x0185
+#define ZC3XX_R186_WINYCENTER          0x0186
+
+/* Gain range */
+#define ZC3XX_R187_MAXGAIN             0x0187
+#define ZC3XX_R188_MINGAIN             0x0188
+
+/* Auto exposure and white balance */
+#define ZC3XX_R189_AWBSTATUS           0x0189
+#define ZC3XX_R18A_AWBFREEZE           0x018a
+#define ZC3XX_R18B_AESTATUS            0x018b
+#define ZC3XX_R18C_AEFREEZE            0x018c
+#define ZC3XX_R18F_AEUNFREEZE          0x018f
+#define ZC3XX_R190_EXPOSURELIMITHIGH   0x0190
+#define ZC3XX_R191_EXPOSURELIMITMID    0x0191
+#define ZC3XX_R192_EXPOSURELIMITLOW    0x0192
+#define ZC3XX_R195_ANTIFLICKERHIGH     0x0195
+#define ZC3XX_R196_ANTIFLICKERMID      0x0196
+#define ZC3XX_R197_ANTIFLICKERLOW      0x0197
+
+/* What is this ? */
+#define ZC3XX_R18D_YTARGET             0x018d
+#define ZC3XX_R18E_RESETLVL            0x018e
+
+/* Color */
+#define ZC3XX_R1A0_REDMEANAFTERAGC     0x01a0
+#define ZC3XX_R1A1_GREENMEANAFTERAGC   0x01a1
+#define ZC3XX_R1A2_BLUEMEANAFTERAGC    0x01a2
+#define ZC3XX_R1A3_REDMEANAFTERAWB     0x01a3
+#define ZC3XX_R1A4_GREENMEANAFTERAWB   0x01a4
+#define ZC3XX_R1A5_BLUEMEANAFTERAWB    0x01a5
+#define ZC3XX_R1A6_YMEANAFTERAE        0x01a6
+#define ZC3XX_R1A7_CALCGLOBALMEAN      0x01a7
+
+#define ZC3XX_R1A2_BLUEMEANAFTERAGC    0x01a2
+
+/* Matrixes */
+
+/* Color matrix is like :
+   R' = R * RGB00 + G * RGB01 + B * RGB02 + RGB03
+   G' = R * RGB10 + G * RGB11 + B * RGB22 + RGB13
+   B' = R * RGB20 + G * RGB21 + B * RGB12 + RGB23
+ */
+#define ZC3XX_R10A_RGB00               0x010a
+#define ZC3XX_R10B_RGB01               0x010b
+#define ZC3XX_R10C_RGB02               0x010c
+#define ZC3XX_R113_RGB03               0x0113
+#define ZC3XX_R10D_RGB10               0x010d
+#define ZC3XX_R10E_RGB11               0x010e
+#define ZC3XX_R10F_RGB12               0x010f
+#define ZC3XX_R114_RGB13               0x0114
+#define ZC3XX_R110_RGB20               0x0110
+#define ZC3XX_R111_RGB21               0x0111
+#define ZC3XX_R112_RGB22               0x0112
+#define ZC3XX_R115_RGB23               0x0115
+
+/* Gamma matrix */
+#define ZC3XX_R120_GAMMA00             0x0120
+#define ZC3XX_R121_GAMMA01             0x0121
+#define ZC3XX_R122_GAMMA02             0x0122
+#define ZC3XX_R123_GAMMA03             0x0123
+#define ZC3XX_R124_GAMMA04             0x0124
+#define ZC3XX_R125_GAMMA05             0x0125
+#define ZC3XX_R126_GAMMA06             0x0126
+#define ZC3XX_R127_GAMMA07             0x0127
+#define ZC3XX_R128_GAMMA08             0x0128
+#define ZC3XX_R129_GAMMA09             0x0129
+#define ZC3XX_R12A_GAMMA0A             0x012a
+#define ZC3XX_R12B_GAMMA0B             0x012b
+#define ZC3XX_R12C_GAMMA0C             0x012c
+#define ZC3XX_R12D_GAMMA0D             0x012d
+#define ZC3XX_R12E_GAMMA0E             0x012e
+#define ZC3XX_R12F_GAMMA0F             0x012f
+#define ZC3XX_R130_GAMMA10             0x0130
+#define ZC3XX_R131_GAMMA11             0x0131
+#define ZC3XX_R132_GAMMA12             0x0132
+#define ZC3XX_R133_GAMMA13             0x0133
+#define ZC3XX_R134_GAMMA14             0x0134
+#define ZC3XX_R135_GAMMA15             0x0135
+#define ZC3XX_R136_GAMMA16             0x0136
+#define ZC3XX_R137_GAMMA17             0x0137
+#define ZC3XX_R138_GAMMA18             0x0138
+#define ZC3XX_R139_GAMMA19             0x0139
+#define ZC3XX_R13A_GAMMA1A             0x013a
+#define ZC3XX_R13B_GAMMA1B             0x013b
+#define ZC3XX_R13C_GAMMA1C             0x013c
+#define ZC3XX_R13D_GAMMA1D             0x013d
+#define ZC3XX_R13E_GAMMA1E             0x013e
+#define ZC3XX_R13F_GAMMA1F             0x013f
+
+/* Luminance gamma */
+#define ZC3XX_R140_YGAMMA00            0x0140
+#define ZC3XX_R141_YGAMMA01            0x0141
+#define ZC3XX_R142_YGAMMA02            0x0142
+#define ZC3XX_R143_YGAMMA03            0x0143
+#define ZC3XX_R144_YGAMMA04            0x0144
+#define ZC3XX_R145_YGAMMA05            0x0145
+#define ZC3XX_R146_YGAMMA06            0x0146
+#define ZC3XX_R147_YGAMMA07            0x0147
+#define ZC3XX_R148_YGAMMA08            0x0148
+#define ZC3XX_R149_YGAMMA09            0x0149
+#define ZC3XX_R14A_YGAMMA0A            0x014a
+#define ZC3XX_R14B_YGAMMA0B            0x014b
+#define ZC3XX_R14C_YGAMMA0C            0x014c
+#define ZC3XX_R14D_YGAMMA0D            0x014d
+#define ZC3XX_R14E_YGAMMA0E            0x014e
+#define ZC3XX_R14F_YGAMMA0F            0x014f
+#define ZC3XX_R150_YGAMMA10            0x0150
+#define ZC3XX_R151_YGAMMA11            0x0151
+
+#define ZC3XX_R1C5_SHARPNESSMODE       0x01c5
+#define ZC3XX_R1C6_SHARPNESS00         0x01c6
+#define ZC3XX_R1C7_SHARPNESS01         0x01c7
+#define ZC3XX_R1C8_SHARPNESS02         0x01c8
+#define ZC3XX_R1C9_SHARPNESS03         0x01c9
+#define ZC3XX_R1CA_SHARPNESS04         0x01ca
+#define ZC3XX_R1CB_SHARPNESS05         0x01cb
+
+/* Synchronization */
+#define ZC3XX_R190_SYNC00LOW           0x0190
+#define ZC3XX_R191_SYNC00MID           0x0191
+#define ZC3XX_R192_SYNC00HIGH          0x0192
+#define ZC3XX_R195_SYNC01LOW           0x0195
+#define ZC3XX_R196_SYNC01MID           0x0196
+#define ZC3XX_R197_SYNC01HIGH          0x0197
+
+/* Dead pixels */
+#define ZC3XX_R250_DEADPIXELSMODE      0x0250
+
+/* EEPROM */
+#define ZC3XX_R300_EEPROMCONFIG        0x0300
+#define ZC3XX_R301_EEPROMACCESS        0x0301
+#define ZC3XX_R302_EEPROMSTATUS        0x0302
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
new file mode 100644
index 0000000..b761b11
--- /dev/null
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -0,0 +1,7623 @@
+/*
+ *	Z-Star/Vimicro zc301/zc302p/vc30x library
+ *	Copyright (C) 2004 2005 2006 Michel Xhaard
+ *		mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ */
+
+#define MODULE_NAME "zc3xx"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
+		"Serge A. Suchkov <Serge.A.S@tochka.ru>");
+MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int force_sensor = -1;
+
+#include "jpeg.h"
+#include "zc3xx-reg.h"
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	__u8 brightness;
+	__u8 contrast;
+	__u8 gamma;
+	__u8 autogain;
+	__u8 lightfreq;
+	__u8 sharpness;
+
+	char qindex;
+	char sensor;			/* Type of image sensor chip */
+/* !! values used in different tables */
+#define SENSOR_CS2102 0
+#define SENSOR_CS2102K 1
+#define SENSOR_GC0305 2
+#define SENSOR_HDCS2020 3
+#define SENSOR_HDCS2020b 4
+#define SENSOR_HV7131B 5
+#define SENSOR_HV7131C 6
+#define SENSOR_ICM105A 7
+#define SENSOR_MC501CB 8
+#define SENSOR_OV7620 9
+/*#define SENSOR_OV7648 9 - same values */
+#define SENSOR_OV7630C 10
+#define SENSOR_PAS106 11
+#define SENSOR_PB0330 12
+#define SENSOR_PO2030 13
+#define SENSOR_TAS5130CK 14
+#define SENSOR_TAS5130CXX 15
+#define SENSOR_TAS5130C_VF0250 16
+#define SENSOR_MAX 17
+	unsigned short chip_revision;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 128,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 256,
+		.step    = 1,
+		.default_value = 128,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_GAMMA 2
+	{
+	    {
+		.id      = V4L2_CID_GAMMA,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gamma",
+		.minimum = 1,
+		.maximum = 6,
+		.step    = 1,
+		.default_value = 4,
+	    },
+	    .set = sd_setgamma,
+	    .get = sd_getgamma,
+	},
+#define SD_AUTOGAIN 3
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+#define SD_FREQ 4
+	{
+	    {
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 0,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
+#define SD_SHARPNESS 5
+	{
+	    {
+		.id	 = V4L2_CID_SHARPNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Sharpness",
+		.minimum = 0,
+		.maximum = 3,
+		.step    = 1,
+		.default_value = 2,
+	    },
+	    .set = sd_setsharpness,
+	    .get = sd_getsharpness,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* usb exchanges */
+struct usb_action {
+	__u8	req;
+	__u8	val;
+	__u16	idx;
+};
+
+static const struct usb_action cs2102_Initial[] = {
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x20, ZC3XX_R080_HBLANKHIGH},
+	{0xa0, 0x21, ZC3XX_R081_HBLANKLOW},
+	{0xa0, 0x30, ZC3XX_R083_RGAINADDR},
+	{0xa0, 0x31, ZC3XX_R084_GGAINADDR},
+	{0xa0, 0x32, ZC3XX_R085_BGAINADDR},
+	{0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH},
+	{0xa0, 0x24, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x25, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xaa, 0x02, 0x0008},
+	{0xaa, 0x03, 0x0000},
+	{0xaa, 0x11, 0x0000},
+	{0xaa, 0x12, 0x0089},
+	{0xaa, 0x13, 0x0000},
+	{0xaa, 0x14, 0x00e9},
+	{0xaa, 0x20, 0x0000},
+	{0xaa, 0x22, 0x0000},
+	{0xaa, 0x0b, 0x0004},
+	{0xaa, 0x30, 0x0030},
+	{0xaa, 0x31, 0x0030},
+	{0xaa, 0x32, 0x0030},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x10, 0x01ae},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x00, 0x01ad},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x24, ZC3XX_R120_GAMMA00},	/* gamma 5 */
+	{0xa0, 0x44, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x64, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x84, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x9d, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xb2, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xc4, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xd3, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xe0, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xeb, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x18, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x20, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0e, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0001},
+	{0xaa, 0x24, 0x0055},
+	{0xaa, 0x25, 0x00cc},
+	{0xaa, 0x21, 0x003f},
+	{0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x39, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x70, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xb0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+
+static const struct usb_action cs2102_InitialScale[] = {
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x20, ZC3XX_R080_HBLANKHIGH},
+	{0xa0, 0x21, ZC3XX_R081_HBLANKLOW},
+	{0xa0, 0x30, ZC3XX_R083_RGAINADDR},
+	{0xa0, 0x31, ZC3XX_R084_GGAINADDR},
+	{0xa0, 0x32, ZC3XX_R085_BGAINADDR},
+	{0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH},
+	{0xa0, 0x24, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x25, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xaa, 0x02, 0x0008},
+	{0xaa, 0x03, 0x0000},
+	{0xaa, 0x11, 0x0001},
+	{0xaa, 0x12, 0x0087},
+	{0xaa, 0x13, 0x0001},
+	{0xaa, 0x14, 0x00e7},
+	{0xaa, 0x20, 0x0000},
+	{0xaa, 0x22, 0x0000},
+	{0xaa, 0x0b, 0x0004},
+	{0xaa, 0x30, 0x0030},
+	{0xaa, 0x31, 0x0030},
+	{0xaa, 0x32, 0x0030},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x00, 0x01ad},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x24, ZC3XX_R120_GAMMA00},	/* gamma 5 */
+	{0xa0, 0x44, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x64, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x84, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x9d, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xb2, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xc4, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xd3, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xe0, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xeb, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xf4, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xfb, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x18, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x20, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0e, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x23, 0x0000},
+	{0xaa, 0x24, 0x00aa},
+	{0xaa, 0x25, 0x00e6},
+	{0xaa, 0x21, 0x003f},
+	{0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x55, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xcc, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x18, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x6a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x3f, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xa5, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf0, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+static const struct usb_action cs2102_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x008c}, /* 00,0f,8c,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x00ac}, /* 00,04,ac,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x00ac}, /* 00,11,ac,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x00ac}, /* 00,1d,ac,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x42, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,42,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+	{0xa0, 0x8c, ZC3XX_R01D_HSYNC_0}, /* 00,1d,8c,cc */
+	{0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
+	{0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
+	{}
+};
+static const struct usb_action cs2102_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x0093}, /* 00,0f,93,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x00a1}, /* 00,04,a1,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x00a1}, /* 00,11,a1,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x00a1}, /* 00,1d,a1,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xf7, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f7,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+	{0xa0, 0x93, ZC3XX_R01D_HSYNC_0}, /* 00,1d,93,cc */
+	{0xa0, 0xb0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,b0,cc */
+	{0xa0, 0xd0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,d0,cc */
+	{}
+};
+static const struct usb_action cs2102_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x005d}, /* 00,0f,5d,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x00aa}, /* 00,04,aa,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x00aa}, /* 00,11,aa,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x00aa}, /* 00,1d,aa,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xe4, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e4,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3a,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+	{0xa0, 0x5d, ZC3XX_R01D_HSYNC_0}, /* 00,1d,5d,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+	{0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
+	{}
+};
+static const struct usb_action cs2102_60HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x00b7}, /* 00,0f,b7,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x00be}, /* 00,04,be,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x00be}, /* 00,11,be,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x00be}, /* 00,1d,be,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xfc, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,fc,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x69, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,69,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
+	{0xa0, 0xb7, ZC3XX_R01D_HSYNC_0}, /* 00,1d,b7,cc */
+	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+	{0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+	{}
+};
+static const struct usb_action cs2102_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+	{}
+};
+static const struct usb_action cs2102_NoFlikerScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+	{0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+	{0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+	{0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+	{0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+	{0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+	{0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x3f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,3f,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0x59, ZC3XX_R01D_HSYNC_0}, /* 00,1d,59,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+	{}
+};
+
+/* CS2102_KOCOM */
+static const struct usb_action cs2102K_Initial[] = {
+	{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x01, 0x01b1},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{}
+};
+
+static const struct usb_action cs2102K_InitialScale[] = {
+	{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x01, 0x01b1},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0A, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0B, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0C, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0D, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xA3, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x03, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x08, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0E, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x18, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0C, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x01, 0x01b1},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x22, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x0f, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x19, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x1f, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x4c, ZC3XX_R118_BGAIN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x96, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x44, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x44, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{}
+};
+
+static const struct usb_action gc0305_Initial[] = {	/* 640x480 */
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},	/* 00,00,01,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00,08,03,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},	/* 00,10,01,cc */
+	{0xa0, 0x04, ZC3XX_R002_CLOCKSELECT},	/* 00,02,04,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},	/* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},	/* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},	/* 00,05,01,cc */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},	/* 00,06,e0,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},	/* 00,01,01,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,01,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},	/* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},	/* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},	/* 01,1c,00,cc */
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},	/* 00,9c,e6,cc */
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},	/* 00,9e,86,cc */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},	/* 00,8b,98,cc */
+	{0xaa, 0x13, 0x0002},	/* 00,13,02,aa */
+	{0xaa, 0x15, 0x0003},	/* 00,15,03,aa */
+	{0xaa, 0x01, 0x0000},	/* 00,01,00,aa */
+	{0xaa, 0x02, 0x0000},	/* 00,02,00,aa */
+	{0xaa, 0x1a, 0x0000},	/* 00,1a,00,aa */
+	{0xaa, 0x1c, 0x0017},	/* 00,1c,17,aa */
+	{0xaa, 0x1d, 0x0080},	/* 00,1d,80,aa */
+	{0xaa, 0x1f, 0x0008},	/* 00,1f,08,aa */
+	{0xaa, 0x21, 0x0012},	/* 00,21,12,aa */
+	{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},	/* 00,86,82,cc */
+	{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},	/* 00,87,83,cc */
+	{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},	/* 00,88,84,cc */
+	{0xaa, 0x05, 0x0000},	/* 00,05,00,aa */
+	{0xaa, 0x0a, 0x0000},	/* 00,0a,00,aa */
+	{0xaa, 0x0b, 0x00b0},	/* 00,0b,b0,aa */
+	{0xaa, 0x0c, 0x0000},	/* 00,0c,00,aa */
+	{0xaa, 0x0d, 0x00b0},	/* 00,0d,b0,aa */
+	{0xaa, 0x0e, 0x0000},	/* 00,0e,00,aa */
+	{0xaa, 0x0f, 0x00b0},	/* 00,0f,b0,aa */
+	{0xaa, 0x10, 0x0000},	/* 00,10,00,aa */
+	{0xaa, 0x11, 0x00b0},	/* 00,11,b0,aa */
+	{0xaa, 0x16, 0x0001},	/* 00,16,01,aa */
+	{0xaa, 0x17, 0x00e6},	/* 00,17,e6,aa */
+	{0xaa, 0x18, 0x0002},	/* 00,18,02,aa */
+	{0xaa, 0x19, 0x0086},	/* 00,19,86,aa */
+	{0xaa, 0x20, 0x0000},	/* 00,20,00,aa */
+	{0xaa, 0x1b, 0x0020},	/* 00,1b,20,aa */
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},	/* 01,01,b7,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* 01,00,0d,cc */
+	{0xa0, 0x76, ZC3XX_R189_AWBSTATUS},	/* 01,89,76,cc */
+	{0xa0, 0x09, 0x01ad},	/* 01,ad,09,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},	/* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},	/* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},	/* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* 03,01,08,cc */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},	/* 01,a8,60,cc */
+	{0xa0, 0x85, ZC3XX_R18D_YTARGET},	/* 01,8d,85,cc */
+	{0xa0, 0x00, 0x011e},	/* 01,1e,00,cc */
+	{0xa0, 0x52, ZC3XX_R116_RGAIN},	/* 01,16,52,cc */
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},	/* 01,17,40,cc */
+	{0xa0, 0x52, ZC3XX_R118_BGAIN},	/* 01,18,52,cc */
+	{0xa0, 0x03, ZC3XX_R113_RGB03},	/* 01,13,03,cc */
+	{}
+};
+static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},	/* 00,00,01,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00,08,03,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},	/* 00,10,01,cc */
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},	/* 00,02,10,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},	/* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},	/* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},	/* 00,05,01,cc */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},	/* 00,06,e0,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},	/* 00,01,01,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,01,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},	/* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},	/* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},	/* 01,1c,00,cc */
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},	/* 00,9c,e8,cc */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},	/* 00,9e,88,cc */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},	/* 00,8b,98,cc */
+	{0xaa, 0x13, 0x0000},	/* 00,13,00,aa */
+	{0xaa, 0x15, 0x0001},	/* 00,15,01,aa */
+	{0xaa, 0x01, 0x0000},	/* 00,01,00,aa */
+	{0xaa, 0x02, 0x0000},	/* 00,02,00,aa */
+	{0xaa, 0x1a, 0x0000},	/* 00,1a,00,aa */
+	{0xaa, 0x1c, 0x0017},	/* 00,1c,17,aa */
+	{0xaa, 0x1d, 0x0080},	/* 00,1d,80,aa */
+	{0xaa, 0x1f, 0x0008},	/* 00,1f,08,aa */
+	{0xaa, 0x21, 0x0012},	/* 00,21,12,aa */
+	{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},	/* 00,86,82,cc */
+	{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},	/* 00,87,83,cc */
+	{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},	/* 00,88,84,cc */
+	{0xaa, 0x05, 0x0000},	/* 00,05,00,aa */
+	{0xaa, 0x0a, 0x0000},	/* 00,0a,00,aa */
+	{0xaa, 0x0b, 0x00b0},	/* 00,0b,b0,aa */
+	{0xaa, 0x0c, 0x0000},	/* 00,0c,00,aa */
+	{0xaa, 0x0d, 0x00b0},	/* 00,0d,b0,aa */
+	{0xaa, 0x0e, 0x0000},	/* 00,0e,00,aa */
+	{0xaa, 0x0f, 0x00b0},	/* 00,0f,b0,aa */
+	{0xaa, 0x10, 0x0000},	/* 00,10,00,aa */
+	{0xaa, 0x11, 0x00b0},	/* 00,11,b0,aa */
+	{0xaa, 0x16, 0x0001},	/* 00,16,01,aa */
+	{0xaa, 0x17, 0x00e8},	/* 00,17,e8,aa */
+	{0xaa, 0x18, 0x0002},	/* 00,18,02,aa */
+	{0xaa, 0x19, 0x0088},	/* 00,19,88,aa */
+	{0xaa, 0x20, 0x0000},	/* 00,20,00,aa */
+	{0xaa, 0x1b, 0x0020},	/* 00,1b,20,aa */
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},	/* 01,01,b7,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* 01,00,0d,cc */
+	{0xa0, 0x76, ZC3XX_R189_AWBSTATUS},	/* 01,89,76,cc */
+	{0xa0, 0x09, 0x01ad},	/* 01,ad,09,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},	/* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},	/* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},	/* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* 03,01,08,cc */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},	/* 01,a8,60,cc */
+	{0xa0, 0x00, 0x011e},	/* 01,1e,00,cc */
+	{0xa0, 0x52, ZC3XX_R116_RGAIN},	/* 01,16,52,cc */
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},	/* 01,17,40,cc */
+	{0xa0, 0x52, ZC3XX_R118_BGAIN},	/* 01,18,52,cc */
+	{0xa0, 0x03, ZC3XX_R113_RGB03},	/* 01,13,03,cc */
+	{}
+};
+static const struct usb_action gc0305_50HZ[] = {
+	{0xaa, 0x82, 0x0000},	/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0002},	/* 00,83,02,aa */
+	{0xaa, 0x84, 0x0038},	/* 00,84,38,aa */	/* win: 00,84,ec */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc */
+	{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,0b,cc */
+	{0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,18,cc */
+							/* win: 01,92,10 */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc */
+	{0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,8e,cc */
+							/* win: 01,97,ec */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},	/* 01,8c,0e,cc */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,15,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,24,cc */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},	/* 00,1d,62,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},	/* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},	/* 00,1f,c8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},	/* 00,20,ff,cc */
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},	/* 01,1d,60,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc */
+/*	{0xa0, 0x85, ZC3XX_R18D_YTARGET},	 * 01,8d,85,cc *
+						 * if 640x480 */
+	{}
+};
+static const struct usb_action gc0305_60HZ[] = {
+	{0xaa, 0x82, 0x0000},	/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0000},	/* 00,83,00,aa */
+	{0xaa, 0x84, 0x00ec},	/* 00,84,ec,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc */
+	{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,0b,cc */
+	{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,10,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc */
+	{0xa0, 0xec, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,ec,cc */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},	/* 01,8c,0e,cc */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,15,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,a9,10,cc */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,24,cc */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},	/* 00,1d,62,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},	/* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},	/* 00,1f,c8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},	/* 00,20,ff,cc */
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},	/* 01,1d,60,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc */
+	{0xa0, 0x80, ZC3XX_R18D_YTARGET},	/* 01,8d,80,cc */
+	{}
+};
+
+static const struct usb_action gc0305_NoFliker[] = {
+	{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE},	/* 01,00,0c,cc */
+	{0xaa, 0x82, 0x0000},	/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0000},	/* 00,83,00,aa */
+	{0xaa, 0x84, 0x0020},	/* 00,84,20,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc */
+	{0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,00,cc */
+	{0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,48,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,10,cc */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},	/* 01,8c,0e,cc */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,15,cc */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},	/* 00,1d,62,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},	/* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},	/* 00,1f,c8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},	/* 00,20,ff,cc */
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},	/* 01,1d,60,cc */
+	{0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,03,cc */
+	{0xa0, 0x80, ZC3XX_R18D_YTARGET},	/* 01,8d,80,cc */
+	{}
+};
+
+/* play poker with registers at your own risk !! */
+static const struct usb_action hdcs2020xx_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},
+						/* D0 ?? E0 did not start */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x02, 0x0002},
+	{0xaa, 0x07, 0x0006},
+	{0xaa, 0x08, 0x0002},
+	{0xaa, 0x09, 0x0006},
+	{0xaa, 0x0a, 0x0001},
+	{0xaa, 0x0b, 0x0001},
+	{0xaa, 0x0c, 0x0008},
+	{0xaa, 0x0d, 0x0000},
+	{0xaa, 0x10, 0x0000},
+	{0xaa, 0x12, 0x0005},
+	{0xaa, 0x13, 0x0063},
+	{0xaa, 0x15, 0x0070},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x70, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x11, ZC3XX_R120_GAMMA00},	/* gamma ~4 */
+	{0xa0, 0x37, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x58, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x91, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa6, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb8, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc7, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd3, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xde, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x23, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+
+	{0xa0, 0x4c, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf5, ZC3XX_R10B_RGB01},
+	{0xa0, 0xff, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf9, ZC3XX_R10D_RGB10},
+	{0xa0, 0x51, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf5, ZC3XX_R10F_RGB12},
+	{0xa0, 0xfb, ZC3XX_R110_RGB20},
+	{0xa0, 0xed, ZC3XX_R111_RGB21},
+	{0xa0, 0x5f, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+	{0xaa, 0x20, 0x0004},
+	{0xaa, 0x21, 0x003d},
+	{0xaa, 0x03, 0x0041},
+	{0xaa, 0x04, 0x0010},
+	{0xaa, 0x05, 0x003d},
+	{0xaa, 0x0e, 0x0001},
+	{0xaa, 0x0f, 0x0000},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x41, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0195},
+	{0xa1, 0x01, 0x0196},
+	{0xa1, 0x01, 0x0197},
+	{0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x1d, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x85, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0116},
+	{0xa1, 0x01, 0x0118},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x1d, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x85, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0116},
+	{0xa1, 0x01, 0x0118},
+/*	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+	{0xa0, 0x00, 0x0007},
+	{}
+};
+
+static const struct usb_action hdcs2020xx_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x02, 0x0002},
+	{0xaa, 0x07, 0x0006},
+	{0xaa, 0x08, 0x0002},
+	{0xaa, 0x09, 0x0006},
+	{0xaa, 0x0a, 0x0001},
+	{0xaa, 0x0b, 0x0001},
+	{0xaa, 0x0c, 0x0008},
+	{0xaa, 0x0d, 0x0000},
+	{0xaa, 0x10, 0x0000},
+	{0xaa, 0x12, 0x0005},
+	{0xaa, 0x13, 0x0063},
+	{0xaa, 0x15, 0x0070},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x70, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x11, ZC3XX_R120_GAMMA00},	/* gamma ~4*/
+	{0xa0, 0x37, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x58, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x91, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa6, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb8, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc7, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd3, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xde, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x23, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x60, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xff, ZC3XX_R10B_RGB01},
+	{0xa0, 0xff, ZC3XX_R10C_RGB02},
+	{0xa0, 0xff, ZC3XX_R10D_RGB10},
+	{0xa0, 0x60, ZC3XX_R10E_RGB11},
+	{0xa0, 0xff, ZC3XX_R10F_RGB12},
+	{0xa0, 0xff, ZC3XX_R110_RGB20},
+	{0xa0, 0xff, ZC3XX_R111_RGB21},
+	{0xa0, 0x60, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
+	{0xaa, 0x20, 0x0002},
+	{0xaa, 0x21, 0x001b},
+	{0xaa, 0x03, 0x0044},
+	{0xaa, 0x04, 0x0008},
+	{0xaa, 0x05, 0x001b},
+	{0xaa, 0x0e, 0x0001},
+	{0xaa, 0x0f, 0x0000},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x44, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xeb, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0195},
+	{0xa1, 0x01, 0x0196},
+	{0xa1, 0x01, 0x0197},
+	{0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x1d, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x99, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0116},
+	{0xa1, 0x01, 0x0118},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x1d, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x99, ZC3XX_R118_BGAIN},
+/*	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+	{0xa0, 0x00, 0x0007},
+/*	{0xa0, 0x18, 0x00fe}, */
+	{}
+};
+static const struct usb_action hdcs2020xb_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* qtable 0x05 */
+	{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x1c, 0x0000},
+	{0xaa, 0x0a, 0x0001},
+	{0xaa, 0x0b, 0x0006},
+	{0xaa, 0x0c, 0x007b},
+	{0xaa, 0x0d, 0x00a7},
+	{0xaa, 0x03, 0x00fb},
+	{0xaa, 0x05, 0x0000},
+	{0xaa, 0x06, 0x0003},
+	{0xaa, 0x09, 0x0008},
+
+	{0xaa, 0x0f, 0x0018},	/* set sensor gain */
+	{0xaa, 0x10, 0x0018},
+	{0xaa, 0x11, 0x0018},
+	{0xaa, 0x12, 0x0018},
+
+	{0xaa, 0x15, 0x004e},
+	{0xaa, 0x1c, 0x0004},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x70, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+
+	{0xa0, 0x66, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xed, ZC3XX_R10B_RGB01},
+	{0xa0, 0xed, ZC3XX_R10C_RGB02},
+	{0xa0, 0xed, ZC3XX_R10D_RGB10},
+	{0xa0, 0x66, ZC3XX_R10E_RGB11},
+	{0xa0, 0xed, ZC3XX_R10F_RGB12},
+	{0xa0, 0xed, ZC3XX_R110_RGB20},
+	{0xa0, 0xed, ZC3XX_R111_RGB21},
+	{0xa0, 0x66, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x13, 0x0031},
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x0e, 0x0004},
+	{0xaa, 0x19, 0x00cd},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 0x14 */
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x18, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x2c, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x41, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+static const struct usb_action hdcs2020xb_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x1c, 0x0000},
+	{0xaa, 0x0a, 0x0001},
+	{0xaa, 0x0b, 0x0006},
+	{0xaa, 0x0c, 0x007a},
+	{0xaa, 0x0d, 0x00a7},
+	{0xaa, 0x03, 0x00fb},
+	{0xaa, 0x05, 0x0000},
+	{0xaa, 0x06, 0x0003},
+	{0xaa, 0x09, 0x0008},
+	{0xaa, 0x0f, 0x0018},	/* original setting */
+	{0xaa, 0x10, 0x0018},
+	{0xaa, 0x11, 0x0018},
+	{0xaa, 0x12, 0x0018},
+	{0xaa, 0x15, 0x004e},
+	{0xaa, 0x1c, 0x0004},
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x70, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x66, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xed, ZC3XX_R10B_RGB01},
+	{0xa0, 0xed, ZC3XX_R10C_RGB02},
+	{0xa0, 0xed, ZC3XX_R10D_RGB10},
+	{0xa0, 0x66, ZC3XX_R10E_RGB11},
+	{0xa0, 0xed, ZC3XX_R10F_RGB12},
+	{0xa0, 0xed, ZC3XX_R110_RGB20},
+	{0xa0, 0xed, ZC3XX_R111_RGB21},
+	{0xa0, 0x66, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ /**** set exposure ***/
+	{0xaa, 0x13, 0x0031},
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x0e, 0x0004},
+	{0xaa, 0x19, 0x00cd},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x18, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x2c, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x41, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+static const struct usb_action hdcs2020b_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x13, 0x0018}, /* 00,13,18,aa */
+	{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+	{0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */
+	{0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+	{0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */
+	{0xa0, 0x05, ZC3XX_R01D_HSYNC_0}, /* 00,1d,05,cc */
+	{0xa0, 0x1a, ZC3XX_R01E_HSYNC_1}, /* 00,1e,1a,cc */
+	{0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */
+	{}
+};
+static const struct usb_action hdcs2020b_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x13, 0x0031}, /* 00,13,31,aa */
+	{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+	{0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+	{0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+	{0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */
+	{0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, /* 00,1e,18,cc */
+	{0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */
+	{}
+};
+static const struct usb_action hdcs2020b_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x13, 0x0010}, /* 00,13,10,aa */
+	{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+	{0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+	{0xaa, 0x19, 0x0000}, /* 00,19,00,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+	{0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */
+	{0xa0, 0x17, ZC3XX_R01E_HSYNC_1}, /* 00,1e,17,cc */
+	{0xa0, 0x2a, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2a,cc */
+	{}
+};
+
+static const struct usb_action hv7131bxx_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xaa, 0x30, 0x002d},
+	{0xaa, 0x01, 0x0005},
+	{0xaa, 0x11, 0x0000},
+	{0xaa, 0x13, 0x0001},	/* {0xaa, 0x13, 0x0000}, */
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x15, 0x00e8},
+	{0xaa, 0x16, 0x0002},
+	{0xaa, 0x17, 0x0086},
+	{0xaa, 0x31, 0x0038},
+	{0xaa, 0x32, 0x0038},
+	{0xaa, 0x33, 0x0038},
+	{0xaa, 0x5b, 0x0001},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0xc0, 0x019b},
+	{0xa0, 0xa0, 0x019c},
+	{0xa0, 0x02, ZC3XX_R188_MINGAIN},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xaa, 0x02, 0x0080},	/* {0xaa, 0x02, 0x0090}; */
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x25, 0x0007},
+	{0xaa, 0x26, 0x00a1},
+	{0xaa, 0x27, 0x0020},
+	{0xaa, 0x20, 0x0000},
+	{0xaa, 0x21, 0x00a0},
+	{0xaa, 0x22, 0x0016},
+	{0xaa, 0x23, 0x0040},
+
+	{0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 2F */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},	/* 4d */
+	{0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x07, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xa0, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x16, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x40, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa1, 0x01, 0x001d},
+	{0xa1, 0x01, 0x001e},
+	{0xa1, 0x01, 0x001f},
+	{0xa1, 0x01, 0x0020},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+/*	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+	{}
+};
+
+static const struct usb_action hv7131bxx_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xaa, 0x30, 0x002d},
+	{0xaa, 0x01, 0x0005},
+	{0xaa, 0x11, 0x0001},
+	{0xaa, 0x13, 0x0000},	/* {0xaa, 0x13, 0x0001}; */
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x15, 0x00e6},
+	{0xaa, 0x16, 0x0002},
+	{0xaa, 0x17, 0x0086},
+	{0xaa, 0x31, 0x0038},
+	{0xaa, 0x32, 0x0038},
+	{0xaa, 0x33, 0x0038},
+	{0xaa, 0x5b, 0x0001},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x70, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0xc0, 0x019b},
+	{0xa0, 0xa0, 0x019c},
+	{0xa0, 0x02, ZC3XX_R188_MINGAIN},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xaa, 0x02, 0x0090},	/* {0xaa, 0x02, 0x0080}, */
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x25, 0x0007},
+	{0xaa, 0x26, 0x00a1},
+	{0xaa, 0x27, 0x0020},
+	{0xaa, 0x20, 0x0000},
+	{0xaa, 0x21, 0x0040},
+	{0xaa, 0x22, 0x0013},
+	{0xaa, 0x23, 0x004c},
+	{0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 2f */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},	/* 4d */
+	{0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},	/* 60 */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0x13, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0x4c, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa1, 0x01, 0x001d},
+	{0xa1, 0x01, 0x001e},
+	{0xa1, 0x01, 0x001f},
+	{0xa1, 0x01, 0x0020},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+/*	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+	{}
+};
+
+static const struct usb_action hv7131cxx_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xaa, 0x01, 0x000c},
+	{0xaa, 0x11, 0x0000},
+	{0xaa, 0x13, 0x0000},
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x15, 0x00e8},
+	{0xaa, 0x16, 0x0002},
+	{0xaa, 0x17, 0x0088},
+
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x89, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0xc0, 0x019b},
+	{0xa0, 0xa0, 0x019c},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x60, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf0, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf0, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf0, ZC3XX_R10D_RGB10},
+	{0xa0, 0x60, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf0, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf0, ZC3XX_R110_RGB20},
+	{0xa0, 0xf0, ZC3XX_R111_RGB21},
+	{0xa0, 0x60, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x25, 0x0007},
+	{0xaa, 0x26, 0x0053},
+	{0xaa, 0x27, 0x0000},
+
+	{0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 2f */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},	/* 9b */
+	{0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},	/* 80 */
+	{0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa1, 0x01, 0x001d},
+	{0xa1, 0x01, 0x001e},
+	{0xa1, 0x01, 0x001f},
+	{0xa1, 0x01, 0x0020},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action hv7131cxx_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},	/* diff */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},	/* 1e0 */
+
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xaa, 0x01, 0x000c},
+	{0xaa, 0x11, 0x0000},
+	{0xaa, 0x13, 0x0000},
+	{0xaa, 0x14, 0x0001},
+	{0xaa, 0x15, 0x00e8},
+	{0xaa, 0x16, 0x0002},
+	{0xaa, 0x17, 0x0088},
+
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},	/* 00 */
+
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x89, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0xc0, 0x019b},
+	{0xa0, 0xa0, 0x019c},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+						/* read the i2c chips ident */
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x60, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf0, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf0, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf0, ZC3XX_R10D_RGB10},
+	{0xa0, 0x60, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf0, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf0, ZC3XX_R110_RGB20},
+	{0xa0, 0xf0, ZC3XX_R111_RGB21},
+	{0xa0, 0x60, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x25, 0x0007},
+	{0xaa, 0x26, 0x0053},
+	{0xaa, 0x27, 0x0000},
+
+	{0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 2f */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},	/* 9b */
+	{0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},	/* 80 */
+
+	{0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
+
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa1, 0x01, 0x001d},
+	{0xa1, 0x01, 0x001e},
+	{0xa1, 0x01, 0x001f},
+	{0xa1, 0x01, 0x0020},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action icm105axx_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH},
+	{0xa0, 0x01, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH},
+	{0xa0, 0x01, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x01, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x01, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xaa, 0x01, 0x0010},
+	{0xaa, 0x03, 0x0000},
+	{0xaa, 0x04, 0x0001},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0001},
+	{0xaa, 0x04, 0x0011},
+	{0xaa, 0x05, 0x00a0},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0002},
+	{0xaa, 0x04, 0x0013},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0003},
+	{0xaa, 0x04, 0x0015},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0004},
+	{0xaa, 0x04, 0x0017},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x000d},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0005},
+	{0xaa, 0x04, 0x0019},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0006},
+	{0xaa, 0x04, 0x0017},
+	{0xaa, 0x05, 0x0026},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0007},
+	{0xaa, 0x04, 0x0019},
+	{0xaa, 0x05, 0x0022},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0008},
+	{0xaa, 0x04, 0x0021},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0009},
+	{0xaa, 0x04, 0x0023},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x000d},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000a},
+	{0xaa, 0x04, 0x0025},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000b},
+	{0xaa, 0x04, 0x00ec},
+	{0xaa, 0x05, 0x002e},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000c},
+	{0xaa, 0x04, 0x00fa},
+	{0xaa, 0x05, 0x002a},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x07, 0x000d},
+	{0xaa, 0x01, 0x0005},
+	{0xaa, 0x94, 0x0002},
+	{0xaa, 0x90, 0x0000},
+	{0xaa, 0x91, 0x001f},
+	{0xaa, 0x10, 0x0064},
+	{0xaa, 0x9b, 0x00f0},
+	{0xaa, 0x9c, 0x0002},
+	{0xaa, 0x14, 0x001a},
+	{0xaa, 0x20, 0x0080},
+	{0xaa, 0x22, 0x0080},
+	{0xaa, 0x24, 0x0080},
+	{0xaa, 0x26, 0x0080},
+	{0xaa, 0x00, 0x0084},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xaa, 0xa8, 0x00c0},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0008},
+
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x52, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf7, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf7, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf7, ZC3XX_R10D_RGB10},
+	{0xa0, 0x52, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf7, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf7, ZC3XX_R110_RGB20},
+	{0xa0, 0xf7, ZC3XX_R111_RGB21},
+	{0xa0, 0x52, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x0d, 0x0003},
+	{0xaa, 0x0c, 0x008c},
+	{0xaa, 0x0e, 0x0095},
+	{0xaa, 0x0f, 0x0002},
+	{0xaa, 0x1c, 0x0094},
+	{0xaa, 0x1d, 0x0002},
+	{0xaa, 0x20, 0x0080},
+	{0xaa, 0x22, 0x0080},
+	{0xaa, 0x24, 0x0080},
+	{0xaa, 0x26, 0x0080},
+	{0xaa, 0x00, 0x0084},
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xe3, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xec, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf5, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0xc0, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+
+static const struct usb_action icm105axx_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH},
+	{0xa0, 0x02, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH},
+	{0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x02, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xaa, 0x01, 0x0010},
+	{0xaa, 0x03, 0x0000},
+	{0xaa, 0x04, 0x0001},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0001},
+	{0xaa, 0x04, 0x0011},
+	{0xaa, 0x05, 0x00a0},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0002},
+	{0xaa, 0x04, 0x0013},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0001},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0003},
+	{0xaa, 0x04, 0x0015},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0004},
+	{0xaa, 0x04, 0x0017},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x000d},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0005},
+	{0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x19, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xaa, 0x05, 0x0020},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0006},
+	{0xaa, 0x04, 0x0017},
+	{0xaa, 0x05, 0x0026},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0007},
+	{0xaa, 0x04, 0x0019},
+	{0xaa, 0x05, 0x0022},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0008},
+	{0xaa, 0x04, 0x0021},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x0009},
+	{0xaa, 0x04, 0x0023},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x000d},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000a},
+	{0xaa, 0x04, 0x0025},
+	{0xaa, 0x05, 0x00aa},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000b},
+	{0xaa, 0x04, 0x00ec},
+	{0xaa, 0x05, 0x002e},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x03, 0x000c},
+	{0xaa, 0x04, 0x00fa},
+	{0xaa, 0x05, 0x002a},
+	{0xaa, 0x06, 0x0005},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x07, 0x000d},
+	{0xaa, 0x01, 0x0005},
+	{0xaa, 0x94, 0x0002},
+	{0xaa, 0x90, 0x0000},
+	{0xaa, 0x91, 0x0010},
+	{0xaa, 0x10, 0x0064},
+	{0xaa, 0x9b, 0x00f0},
+	{0xaa, 0x9c, 0x0002},
+	{0xaa, 0x14, 0x001a},
+	{0xaa, 0x20, 0x0080},
+	{0xaa, 0x22, 0x0080},
+	{0xaa, 0x24, 0x0080},
+	{0xaa, 0x26, 0x0080},
+	{0xaa, 0x00, 0x0084},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xaa, 0xa8, 0x0080},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{0xa1, 0x01, 0x0008},
+
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x52, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf7, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf7, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf7, ZC3XX_R10D_RGB10},
+	{0xa0, 0x52, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf7, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf7, ZC3XX_R110_RGB20},
+	{0xa0, 0xf7, ZC3XX_R111_RGB21},
+	{0xa0, 0x52, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x0d, 0x0003},
+	{0xaa, 0x0c, 0x0020},
+	{0xaa, 0x0e, 0x000e},
+	{0xaa, 0x0f, 0x0002},
+	{0xaa, 0x1c, 0x000d},
+	{0xaa, 0x1d, 0x0002},
+	{0xaa, 0x20, 0x0080},
+	{0xaa, 0x22, 0x0080},
+	{0xaa, 0x24, 0x0080},
+	{0xaa, 0x26, 0x0080},
+	{0xaa, 0x00, 0x0084},
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xc8, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xd8, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},
+	{}
+};
+static const struct usb_action icm105a_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */
+	{0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,0d,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,1a,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4b,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+	{0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */
+	{0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d8,cc */
+	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{}
+};
+static const struct usb_action icm105a_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */
+	{0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,94,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,84,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+	{0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e3,cc */
+	{0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, /* 00,1e,ec,cc */
+	{0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f5,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+	{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+	{}
+};
+static const struct usb_action icm105a_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+	{0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x08, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,08,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x41, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,41,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+	{0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+	{0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+	{0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{}
+};
+static const struct usb_action icm105a_60HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+	{0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x85, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,85,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,08,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */
+	{0xa0, 0xc2, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c2,cc */
+	{0xa0, 0xd6, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d6,cc */
+	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+	{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+	{}
+};
+static const struct usb_action icm105a_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+	{0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x00, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+	{0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+	{0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{}
+};
+static const struct usb_action icm105a_NoFlikerScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+	{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+	{0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */
+	{0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+	{0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+	{0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+	{0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+	{0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+	{0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+	{0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */
+	{0xa0, 0x80, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,80,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */
+	{0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */
+	{0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */
+	{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
+	{}
+};
+
+static const struct usb_action MC501CB_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+	{0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+	{0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */
+	{0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */
+	{0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */
+	{0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+	{0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+	{0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+	{0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+	{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+	{0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+	{0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+	{0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+	{0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+	{0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+	{0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+	{0xaa, 0x18, 0x00de}, /* 00,18,de,aa */
+	{0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+	{0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */
+	{0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+	{0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+	{0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+	{0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+	{0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+	{0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+	{0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+	{0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+	{0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+	{0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+	{0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+	{0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+	{0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+	{0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+	{0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+	{0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+	{0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+	{0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+	{0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+	{0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+	{0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+	{0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+	{0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+	{0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+	{0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+	{0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+	{0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+	{0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+	{0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+	{0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+	{0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+	{0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+	{0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+	{0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+	{0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+	{0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+	{0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+	{0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+	{0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+	{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+	{0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+	{0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+	{0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */
+	{0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+	{0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */
+	{0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */
+	{0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */
+	{0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */
+	{0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+	{0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+	{0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+	{0xaa, 0x51, 0x0027}, /* 00,51,27,aa */
+	{0xaa, 0x52, 0x0020}, /* 00,52,20,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+	{0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+	{0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+	{0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+	{0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+	{0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+	{0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+	{0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_Initial[] = {	 /* 320x240 */
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+	{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
+	{0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+	{0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */
+	{0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */
+	{0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */
+	{0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+	{0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+	{0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+	{0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+	{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+	{0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+	{0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+	{0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+	{0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+	{0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+	{0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+	{0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+	{0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */
+	{0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+	{0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */
+	{0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+	{0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+	{0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+	{0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+	{0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+	{0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+	{0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+	{0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+	{0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+	{0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+	{0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+	{0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+	{0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+	{0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+	{0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+	{0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+	{0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+	{0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+	{0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+	{0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+	{0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+	{0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+	{0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+	{0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+	{0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+	{0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+	{0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+	{0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+	{0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+	{0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+	{0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+	{0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+	{0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+	{0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+	{0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+	{0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+	{0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+	{0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+	{0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+	{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+	{0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+	{0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+	{0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */
+	{0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+	{0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */
+	{0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */
+	{0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */
+	{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+	{0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+	{0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+	{0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+	{0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */
+	{0xaa, 0x52, 0x0041}, /* 00,52,41,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+	{0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+	{0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+	{0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+	{0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+	{0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+	{0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+	{0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_50HZ[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+	{0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+	{0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+	{0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
+	{0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
+	{0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+	{0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+	{0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_50HZScale[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+	{0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+	{0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+	{0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
+	{0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
+	{0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_60HZ[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+	{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+	{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+	{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_60HZScale[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+	{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+	{0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+	{0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_NoFliker[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+	{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+	{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+	{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+	{}
+};
+
+static const struct usb_action MC501CB_NoFlikerScale[] = {
+	{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+	{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+	{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+	{0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+	{0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+	{}
+};
+
+/* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
+static const struct usb_action OV7620_mode0[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */
+	{0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */
+	{0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */
+	{0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */
+	{0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */
+	{0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */
+	{0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+	{0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */
+	{0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+	{0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+	{0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+	{0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+	{0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+	{0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+	{0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+	{0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+	{0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+	{0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+	{0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+	{0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */
+	{0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+	{0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+	{0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+	{0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+	{0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+	{0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+	{0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+	{0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+	{0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+	{0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+	{0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+	{0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+	{0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+	{0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+	{0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+	{0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+	{0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+	{0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */
+	{0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */
+	{0xa0, 0x40, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,40,cc */
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */
+	{}
+};
+
+/* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
+static const struct usb_action OV7620_mode1[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x50, ZC3XX_R002_CLOCKSELECT},	/* 00,02,50,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00,08,00,cc */
+						/* mx change? */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */
+	{0xa0, 0x02, ZC3XX_R083_RGAINADDR},	/* 00,83,02,cc */
+	{0xa0, 0x01, ZC3XX_R085_BGAINADDR},	/* 00,85,01,cc */
+	{0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH},	/* 00,86,80,cc */
+	{0xa0, 0x81, ZC3XX_R087_EXPTIMEMID},	/* 00,87,81,cc */
+	{0xa0, 0x10, ZC3XX_R088_EXPTIMELOW},	/* 00,88,10,cc */
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},	/* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},	/* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},	/* 01,1c,00,cc */
+	{0xa0, 0xd6, ZC3XX_R09C_WINHEIGHTLOW},	/* 00,9c,d6,cc */
+						/* OV7648 00,9c,d8,cc */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},	/* 00,9e,88,cc */
+	{0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+	{0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+	{0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+	{0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+	{0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+	{0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+	{0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+	{0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+	{0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+	{0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+	{0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+	{0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+	{0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+	{0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */
+	{0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+	{0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+	{0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+	{0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+	{0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+	{0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+	{0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+	{0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+	{0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+	{0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+	{0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+	{0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+	{0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+	{0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},	/* 01,89,06,cc */
+	{0xa0, 0x00, 0x01ad},			/* 01,ad,00,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},	/* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* 03,01,08,cc */
+	{0xa0, 0x68, ZC3XX_R116_RGAIN},		/* 01,16,68,cc */
+	{0xa0, 0x52, ZC3XX_R118_BGAIN},		/* 01,18,52,cc */
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},	/* 01,1d,50,cc */
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+	{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},	/* 01,a8,50,cc */
+	{}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,50HZ */
+static const struct usb_action OV7620_50HZ[] = {
+	{0xaa, 0x13, 0x00a3},	/* 00,13,a3,aa */
+	{0xdd, 0x00, 0x0100},	/* 00,01,00,dd */
+	{0xaa, 0x2b, 0x0096},	/* 00,2b,96,aa */
+	{0xaa, 0x75, 0x008a},	/* 00,75,8a,aa */
+	{0xaa, 0x2d, 0x0005},	/* 00,2d,05,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,04,cc */
+	{0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,18,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc */
+	{0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,83,cc */
+	{0xaa, 0x10, 0x0082},				/* 00,10,82,aa */
+	{0xaa, 0x76, 0x0003},				/* 00,76,03,aa */
+/*	{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},		 * 00,02,40,cc
+							 if mode0 (640x480) */
+	{}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,60HZ */
+static const struct usb_action OV7620_60HZ[] = {
+	{0xaa, 0x13, 0x00a3},			/* 00,13,a3,aa */
+						/* (bug in zs211.inf) */
+	{0xdd, 0x00, 0x0100},			/* 00,01,00,dd */
+	{0xaa, 0x2b, 0x0000},			/* 00,2b,00,aa */
+	{0xaa, 0x75, 0x008a},			/* 00,75,8a,aa */
+	{0xaa, 0x2d, 0x0005},			/* 00,2d,05,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */
+	{0xaa, 0x10, 0x0020},			/* 00,10,20,aa */
+	{0xaa, 0x76, 0x0003},			/* 00,76,03,aa */
+/*	{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},	 * 00,02,40,cc
+						 * if mode0 (640x480) */
+/* ?? in gspca v1, it was
+	{0xa0, 0x00, 0x0039},  * 00,00,00,dd *
+	{0xa1, 0x01, 0x0037},		*/
+	{}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
+static const struct usb_action OV7620_NoFliker[] = {
+	{0xaa, 0x13, 0x00a3},			/* 00,13,a3,aa */
+						/* (bug in zs211.inf) */
+	{0xdd, 0x00, 0x0100},			/* 00,01,00,dd */
+	{0xaa, 0x2b, 0x0000},			/* 00,2b,00,aa */
+	{0xaa, 0x75, 0x008e},			/* 00,75,8e,aa */
+	{0xaa, 0x2d, 0x0001},			/* 00,2d,01,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */
+	{0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */
+/*	{0xa0, 0x44, ZC3XX_R002_CLOCKSELECT},	 * 00,02,44,cc
+						 - if mode1 (320x240) */
+/* ?? was
+	{0xa0, 0x00, 0x0039},  * 00,00,00,dd *
+	{0xa1, 0x01, 0x0037},		*/
+	{}
+};
+
+static const struct usb_action ov7630c_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xaa, 0x12, 0x0080},
+	{0xa0, 0x02, ZC3XX_R083_RGAINADDR},
+	{0xa0, 0x01, ZC3XX_R085_BGAINADDR},
+	{0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH},
+	{0xa0, 0x91, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x10, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x12, 0x0069},
+	{0xaa, 0x04, 0x0020},
+	{0xaa, 0x06, 0x0050},
+	{0xaa, 0x13, 0x0083},
+	{0xaa, 0x14, 0x0000},
+	{0xaa, 0x15, 0x0024},
+	{0xaa, 0x17, 0x0018},
+	{0xaa, 0x18, 0x00ba},
+	{0xaa, 0x19, 0x0002},
+	{0xaa, 0x1a, 0x00f6},
+	{0xaa, 0x1b, 0x0002},
+	{0xaa, 0x20, 0x00c2},
+	{0xaa, 0x24, 0x0060},
+	{0xaa, 0x25, 0x0040},
+	{0xaa, 0x26, 0x0030},
+	{0xaa, 0x27, 0x00ea},
+	{0xaa, 0x28, 0x00a0},
+	{0xaa, 0x21, 0x0000},
+	{0xaa, 0x2a, 0x0081},
+	{0xaa, 0x2b, 0x0096},
+	{0xaa, 0x2d, 0x0094},
+	{0xaa, 0x2f, 0x003d},
+	{0xaa, 0x30, 0x0024},
+	{0xaa, 0x60, 0x0000},
+	{0xaa, 0x61, 0x0040},
+	{0xaa, 0x68, 0x007c},
+	{0xaa, 0x6f, 0x0015},
+	{0xaa, 0x75, 0x0088},
+	{0xaa, 0x77, 0x00b5},
+	{0xaa, 0x01, 0x0060},
+	{0xaa, 0x02, 0x0060},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x46, ZC3XX_R118_BGAIN},
+	{0xa0, 0x04, ZC3XX_R113_RGB03},
+/* 0x10, */
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+/* 0x03, */
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x01, ZC3XX_R120_GAMMA00},	/* gamma 2 ?*/
+	{0xa0, 0x0c, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x1f, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x3a, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x53, ZC3XX_R124_GAMMA04},
+	{0xa0, 0x6d, ZC3XX_R125_GAMMA05},
+	{0xa0, 0x85, ZC3XX_R126_GAMMA06},
+	{0xa0, 0x9c, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xb0, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xc2, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xd1, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xde, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xe9, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf2, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xf9, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x05, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x0f, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x16, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x19, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x19, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x17, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x15, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x12, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x10, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x0e, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x0b, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x09, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x08, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x06, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x03, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xaa, 0x10, 0x001b},
+	{0xaa, 0x76, 0x0002},
+	{0xaa, 0x2a, 0x0081},
+	{0xaa, 0x2b, 0x0000},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xb8, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x37, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xaa, 0x13, 0x0083},	/* 40 */
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action ov7630c_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+
+	{0xaa, 0x12, 0x0080},
+	{0xa0, 0x02, ZC3XX_R083_RGAINADDR},
+	{0xa0, 0x01, ZC3XX_R085_BGAINADDR},
+	{0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH},
+	{0xa0, 0x91, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x10, ZC3XX_R088_EXPTIMELOW},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+	{0xaa, 0x12, 0x0069},	/* i2c */
+	{0xaa, 0x04, 0x0020},
+	{0xaa, 0x06, 0x0050},
+	{0xaa, 0x13, 0x00c3},
+	{0xaa, 0x14, 0x0000},
+	{0xaa, 0x15, 0x0024},
+	{0xaa, 0x19, 0x0003},
+	{0xaa, 0x1a, 0x00f6},
+	{0xaa, 0x1b, 0x0002},
+	{0xaa, 0x20, 0x00c2},
+	{0xaa, 0x24, 0x0060},
+	{0xaa, 0x25, 0x0040},
+	{0xaa, 0x26, 0x0030},
+	{0xaa, 0x27, 0x00ea},
+	{0xaa, 0x28, 0x00a0},
+	{0xaa, 0x21, 0x0000},
+	{0xaa, 0x2a, 0x0081},
+	{0xaa, 0x2b, 0x0096},
+	{0xaa, 0x2d, 0x0084},
+	{0xaa, 0x2f, 0x003d},
+	{0xaa, 0x30, 0x0024},
+	{0xaa, 0x60, 0x0000},
+	{0xaa, 0x61, 0x0040},
+	{0xaa, 0x68, 0x007c},
+	{0xaa, 0x6f, 0x0015},
+	{0xaa, 0x75, 0x0088},
+	{0xaa, 0x77, 0x00b5},
+	{0xaa, 0x01, 0x0060},
+	{0xaa, 0x02, 0x0060},
+	{0xaa, 0x17, 0x0018},
+	{0xaa, 0x18, 0x00ba},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R116_RGAIN},
+	{0xa0, 0x46, ZC3XX_R118_BGAIN},
+	{0xa0, 0x04, ZC3XX_R113_RGB03},
+
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x4e, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xfe, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf7, ZC3XX_R10D_RGB10},
+	{0xa0, 0x4d, ZC3XX_R10E_RGB11},
+	{0xa0, 0xfc, ZC3XX_R10F_RGB12},
+	{0xa0, 0x00, ZC3XX_R110_RGB20},
+	{0xa0, 0xf6, ZC3XX_R111_RGB21},
+	{0xa0, 0x4a, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x16, ZC3XX_R120_GAMMA00},	/* gamma ~4 */
+	{0xa0, 0x3a, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x5b, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x7c, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x94, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa9, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xbb, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xca, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd7, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xe1, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xea, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xf1, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf7, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xfc, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x20, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x4e, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xfe, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf7, ZC3XX_R10D_RGB10},
+	{0xa0, 0x4d, ZC3XX_R10E_RGB11},
+	{0xa0, 0xfc, ZC3XX_R10F_RGB12},
+	{0xa0, 0x00, ZC3XX_R110_RGB20},
+	{0xa0, 0xf6, ZC3XX_R111_RGB21},
+	{0xa0, 0x4a, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xaa, 0x10, 0x000d},
+	{0xaa, 0x76, 0x0002},
+	{0xaa, 0x2a, 0x0081},
+	{0xaa, 0x2b, 0x0000},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xd8, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x1b, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xaa, 0x13, 0x00c3},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action pas106b_Initial_com[] = {
+/* Sream and Sensor specific */
+	{0xa1, 0x01, 0x0010},	/* CMOSSensorSelect */
+/* System */
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},	/* SystemControl */
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},	/* SystemControl */
+/* Picture size */
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},	/* ClockSelect */
+	{0xa0, 0x03, 0x003a},
+	{0xa0, 0x0c, 0x003b},
+	{0xa0, 0x04, 0x0038},
+	{}
+};
+
+static const struct usb_action pas106b_Initial[] = {	/* 176x144 */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},		/* ClockSetting */
+/* Sream and Sensor specific */
+	{0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT},	/* CMOSSensorSelect */
+/* Picture size */
+	{0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH},  /* FrameWidthHigh 00 */
+	{0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW},	  /* FrameWidthLow B0 */
+	{0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh 00 */
+	{0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW},  /* FrameHightLow 90 */
+/* System */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */
+/* Sream and Sensor specific */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+/* Sensor Interface */
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},  /* Compatibily Mode */
+/* Window inside sensor array */
+	{0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},	/* WinXStartLow */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* FirstYLow */
+	{0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},	/* FirstxLow */
+	{0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW},	/* WinHeightLow */
+	{0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW},	/* WinWidthLow */
+/* Init the sensor */
+	{0xaa, 0x02, 0x0004},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x09, 0x0005},
+	{0xaa, 0x0a, 0x0002},
+	{0xaa, 0x0b, 0x0002},
+	{0xaa, 0x0c, 0x0005},
+	{0xaa, 0x0d, 0x0000},
+	{0xaa, 0x0e, 0x0002},
+	{0xaa, 0x14, 0x0081},
+
+/* Other registors */
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */
+/* Frame retreiving */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},	/* AutoAdjustFPS */
+/* Gains */
+	{0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN},	/* DigitalGain */
+/* Unknown */
+	{0xa0, 0x00, 0x01ad},
+/* Sharpness */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},	/* SharpnessMode */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},	/* Sharpness05 */
+/* Other registors */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* OperationMode */
+/* Auto exposure and white balance */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},	/* AWBStatus */
+/*Dead pixels */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* EEPROMAccess */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* ClockSetting */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+/* Other registers */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* OperationMode */
+/* Auto exposure and white balance */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},	/* AWBStatus */
+/*Dead pixels */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* EEPROMAccess */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* ClockSetting */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+/* Auto correction */
+	{0xa0, 0x03, ZC3XX_R181_WINXSTART},	/* WinXstart */
+	{0xa0, 0x08, ZC3XX_R182_WINXWIDTH},	/* WinXWidth */
+	{0xa0, 0x16, ZC3XX_R183_WINXCENTER},	/* WinXCenter */
+	{0xa0, 0x03, ZC3XX_R184_WINYSTART},	/* WinYStart */
+	{0xa0, 0x05, ZC3XX_R185_WINYWIDTH},	/* WinYWidth */
+	{0xa0, 0x14, ZC3XX_R186_WINYCENTER},	/* WinYCenter */
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* ExposureLimitHigh */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},	/* ExposureLimitMid */
+	{0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW},	/* ExposureLimitLow */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* AntiFlickerHigh */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* AntiFlickerLow */
+	{0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW},	/* AntiFlickerLow */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},		/* AEBFreeze */
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},		/* AEBUnfreeze */
+/* sensor on */
+	{0xaa, 0x07, 0x00b1},
+	{0xaa, 0x05, 0x0003},
+	{0xaa, 0x04, 0x0001},
+	{0xaa, 0x03, 0x003b},
+/* Gains */
+	{0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* DigitalLimitDiff */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},	/* DigitalGainStep */
+	{0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},		/* GlobalGain */
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},		/* GlobalGain */
+/* Auto correction */
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},	/* AutoCorrectEnable */
+	{0xa1, 0x01, 0x0180},				/* AutoCorrectEnable */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* AutoCorrectEnable */
+/* Gains */
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},			/* RGain */
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},			/* GGain */
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},			/* BGain */
+	{}
+};
+
+static const struct usb_action pas106b_InitialScale[] = {	/* 352x288 */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},		/* ClockSetting */
+/* Sream and Sensor specific */
+	{0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT},	/* CMOSSensorSelect */
+/* Picture size */
+	{0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH},	/* FrameWidthHigh */
+	{0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW},		/* FrameWidthLow */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},	/* FrameHeightHigh */
+	{0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW},	/* FrameHightLow */
+/* System */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},	/* SystemOperating */
+/* Sream and Sensor specific */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */
+/* Sensor Interface */
+	{0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},	/* Compatibily Mode */
+/* Window inside sensor array */
+	{0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},	/* WinXStartLow */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* FirstYLow */
+	{0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},	/* FirstxLow */
+	{0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW},	/* WinHeightLow */
+	{0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW},	/* WinWidthLow */
+/* Init the sensor */
+	{0xaa, 0x02, 0x0004},
+	{0xaa, 0x08, 0x0000},
+	{0xaa, 0x09, 0x0005},
+	{0xaa, 0x0a, 0x0002},
+	{0xaa, 0x0b, 0x0002},
+	{0xaa, 0x0c, 0x0005},
+	{0xaa, 0x0d, 0x0000},
+	{0xaa, 0x0e, 0x0002},
+	{0xaa, 0x14, 0x0081},
+
+/* Other registors */
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */
+/* Frame retreiving */
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},	/* AutoAdjustFPS */
+/* Gains */
+	{0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN},	/* DigitalGain */
+/* Unknown */
+	{0xa0, 0x00, 0x01ad},
+/* Sharpness */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},	/* SharpnessMode */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},	/* Sharpness05 */
+/* Other registors */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* OperationMode */
+/* Auto exposure and white balance */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},	/* AWBStatus */
+	{0xa0, 0x80, ZC3XX_R18D_YTARGET},	/* ????????? */
+/*Dead pixels */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* EEPROMAccess */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* ClockSetting */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+/* Other registers */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},	/* OperationMode */
+/* Auto exposure and white balance */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},	/* AWBStatus */
+/*Dead pixels */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */
+/* EEPROM */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},	/* EEPROMAccess */
+/* JPEG control */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* ClockSetting */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x58, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf4, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf4, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf4, ZC3XX_R10D_RGB10},
+	{0xa0, 0x58, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf4, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf4, ZC3XX_R110_RGB20},
+	{0xa0, 0xf4, ZC3XX_R111_RGB21},
+	{0xa0, 0x58, ZC3XX_R112_RGB22},
+/* Auto correction */
+	{0xa0, 0x03, ZC3XX_R181_WINXSTART},	/* WinXstart */
+	{0xa0, 0x08, ZC3XX_R182_WINXWIDTH},	/* WinXWidth */
+	{0xa0, 0x16, ZC3XX_R183_WINXCENTER},	/* WinXCenter */
+	{0xa0, 0x03, ZC3XX_R184_WINYSTART},	/* WinYStart */
+	{0xa0, 0x05, ZC3XX_R185_WINYWIDTH},	/* WinYWidth */
+	{0xa0, 0x14, ZC3XX_R186_WINYCENTER},	/* WinYCenter */
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh 0 */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},  /* ExposureLimitMid */
+	{0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW},  /* ExposureLimitLow 0xb1 */
+
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},   /* AntiFlickerHigh 0x00 */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},    /* AntiFlickerLow 0x00 */
+	{0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW},    /* AntiFlickerLow 0x87 */
+
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* AEBFreeze 0x10 0x0c */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},	/* AEBUnfreeze 0x30 0x18 */
+/* sensor on */
+	{0xaa, 0x07, 0x00b1},
+	{0xaa, 0x05, 0x0003},
+	{0xaa, 0x04, 0x0001},
+	{0xaa, 0x03, 0x003b},
+/* Gains */
+	{0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* DigitalLimitDiff */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},	/* DigitalGainStep */
+	{0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},	/* GlobalGain */
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},	/* GlobalGain */
+/* Auto correction */
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},	/* AutoCorrectEnable */
+	{0xa1, 0x01, 0x0180},				/* AutoCorrectEnable */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* AutoCorrectEnable */
+/* Gains */
+	{0xa0, 0x40, ZC3XX_R116_RGAIN},		/* RGain */
+	{0xa0, 0x40, ZC3XX_R117_GGAIN},		/* GGain */
+	{0xa0, 0x40, ZC3XX_R118_BGAIN},		/* BGain */
+
+	{0xa0, 0x00, 0x0007},			/* AutoCorrectEnable */
+	{0xa0, 0xff, ZC3XX_R018_FRAMELOST},	/* Frame adjust */
+	{}
+};
+static const struct usb_action pas106b_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+	{0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,54,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,87,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* 01,8c,10,cc */
+	{0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,30,cc */
+	{0xaa, 0x03, 0x0021},			/* 00,03,21,aa */
+	{0xaa, 0x04, 0x000c},			/* 00,04,0c,aa */
+	{0xaa, 0x05, 0x0002},			/* 00,05,02,aa */
+	{0xaa, 0x07, 0x001c},			/* 00,07,1c,aa */
+	{0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */
+	{}
+};
+static const struct usb_action pas106b_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+	{0xa0, 0x2e, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,2e,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x71, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,71,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* 01,8c,10,cc */
+	{0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,30,cc */
+	{0xaa, 0x03, 0x001c},			/* 00,03,1c,aa */
+	{0xaa, 0x04, 0x0004},			/* 00,04,04,aa */
+	{0xaa, 0x05, 0x0001},			/* 00,05,01,aa */
+	{0xaa, 0x07, 0x00c4},			/* 00,07,c4,aa */
+	{0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */
+	{}
+};
+static const struct usb_action pas106b_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */
+	{0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,20,cc */
+	{0xaa, 0x03, 0x0013},			/* 00,03,13,aa */
+	{0xaa, 0x04, 0x0000},			/* 00,04,00,aa */
+	{0xaa, 0x05, 0x0001},			/* 00,05,01,aa */
+	{0xaa, 0x07, 0x0030},			/* 00,07,30,aa */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{}
+};
+
+static const struct usb_action pb03303x_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},	/* 8b -> dc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xaa, 0x01, 0x0001},
+	{0xaa, 0x06, 0x0000},
+	{0xaa, 0x08, 0x0483},
+	{0xaa, 0x01, 0x0004},
+	{0xaa, 0x08, 0x0006},
+	{0xaa, 0x02, 0x0011},
+	{0xaa, 0x03, 0x01e7},
+	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x07, 0x3002},
+	{0xaa, 0x20, 0x1100},
+	{0xaa, 0x35, 0x0050},
+	{0xaa, 0x30, 0x0005},
+	{0xaa, 0x31, 0x0000},
+	{0xaa, 0x58, 0x0078},
+	{0xaa, 0x62, 0x0411},
+	{0xaa, 0x2b, 0x0028},
+	{0xaa, 0x2c, 0x0030},
+	{0xaa, 0x2d, 0x0030},
+	{0xaa, 0x2e, 0x0028},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},
+
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x0d, 0x003a},
+	{0xa0, 0x02, 0x003b},
+	{0xa0, 0x00, 0x0038},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x05, 0x0009},
+	{0xaa, 0x09, 0x0134},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action pb03303x_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},	/* 8b -> dc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xaa, 0x01, 0x0001},
+	{0xaa, 0x06, 0x0000},
+	{0xaa, 0x08, 0x0483},
+	{0xaa, 0x01, 0x0004},
+	{0xaa, 0x08, 0x0006},
+	{0xaa, 0x02, 0x0011},
+	{0xaa, 0x03, 0x01e7},
+	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x07, 0x3002},
+	{0xaa, 0x20, 0x1100},
+	{0xaa, 0x35, 0x0050},
+	{0xaa, 0x30, 0x0005},
+	{0xaa, 0x31, 0x0000},
+	{0xaa, 0x58, 0x0078},
+	{0xaa, 0x62, 0x0411},
+	{0xaa, 0x2b, 0x0028},
+	{0xaa, 0x2c, 0x0030},
+	{0xaa, 0x2d, 0x0030},
+	{0xaa, 0x2e, 0x0028},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},
+
+	{0xa1, 0x01, 0x0002},
+
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+
+	{0xa0, 0x0d, 0x003a},
+	{0xa0, 0x02, 0x003b},
+	{0xa0, 0x00, 0x0038},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x13, ZC3XX_R120_GAMMA00},	/* gamma 4 */
+	{0xa0, 0x38, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x59, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x79, ZC3XX_R123_GAMMA03},
+	{0xa0, 0x92, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xa7, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xb9, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xc8, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xd4, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xdf, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xe7, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xee, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xf4, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xf9, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xfc, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x26, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x22, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x20, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1c, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x16, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x13, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x10, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x05, 0x0009},
+	{0xaa, 0x09, 0x0134},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xec, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x9c, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action pb0330xx_Initial[] = {
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xaa, 0x01, 0x0006},
+	{0xaa, 0x02, 0x0011},
+	{0xaa, 0x03, 0x01e7},
+	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x06, 0x0003},
+	{0xaa, 0x07, 0x3002},
+	{0xaa, 0x20, 0x1100},
+	{0xaa, 0x2f, 0xf7b0},
+	{0xaa, 0x30, 0x0005},
+	{0xaa, 0x31, 0x0000},
+	{0xaa, 0x34, 0x0100},
+	{0xaa, 0x35, 0x0060},
+	{0xaa, 0x3d, 0x068f},
+	{0xaa, 0x40, 0x01e0},
+	{0xaa, 0x58, 0x0078},
+	{0xaa, 0x62, 0x0411},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x05, 0x0066},
+	{0xaa, 0x09, 0x02b2},
+	{0xaa, 0x10, 0x0002},
+
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0007},
+/*	{0xa0, 0x30, 0x0007}, */
+/*	{0xa0, 0x00, 0x0007}, */
+	{}
+};
+
+static const struct usb_action pb0330xx_InitialScale[] = {
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* 00 */
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},	/* 10 */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xaa, 0x01, 0x0006},
+	{0xaa, 0x02, 0x0011},
+	{0xaa, 0x03, 0x01e7},
+	{0xaa, 0x04, 0x0287},
+	{0xaa, 0x06, 0x0003},
+	{0xaa, 0x07, 0x3002},
+	{0xaa, 0x20, 0x1100},
+	{0xaa, 0x2f, 0xf7b0},
+	{0xaa, 0x30, 0x0005},
+	{0xaa, 0x31, 0x0000},
+	{0xaa, 0x34, 0x0100},
+	{0xaa, 0x35, 0x0060},
+	{0xaa, 0x3d, 0x068f},
+	{0xaa, 0x40, 0x01e0},
+	{0xaa, 0x58, 0x0078},
+	{0xaa, 0x62, 0x0411},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0002},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
+	{0xa1, 0x01, 0x0091},
+	{0xa1, 0x01, 0x0095},
+	{0xa1, 0x01, 0x0096},
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x50, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf8, ZC3XX_R10B_RGB01},
+	{0xa0, 0xf8, ZC3XX_R10C_RGB02},
+	{0xa0, 0xf8, ZC3XX_R10D_RGB10},
+	{0xa0, 0x50, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf8, ZC3XX_R10F_RGB12},
+	{0xa0, 0xf8, ZC3XX_R110_RGB20},
+	{0xa0, 0xf8, ZC3XX_R111_RGB21},
+	{0xa0, 0x50, ZC3XX_R112_RGB22},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0x05, 0x0066},
+	{0xaa, 0x09, 0x02b2},
+	{0xaa, 0x10, 0x0002},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0008},
+	{0xa1, 0x01, 0x0007},
+/*	{0xa0, 0x30, 0x0007}, */
+/*	{0xa0, 0x00, 0x0007}, */
+	{}
+};
+static const struct usb_action pb0330_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,ee,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, /* 00,1d,68,cc */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */
+	{}
+};
+static const struct usb_action pb0330_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0xe5, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e5,cc */
+	{0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f0,cc */
+	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
+	{}
+};
+static const struct usb_action pb0330_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,dd,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x43, ZC3XX_R01D_HSYNC_0}, /* 00,1d,43,cc */
+	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{}
+};
+static const struct usb_action pb0330_60HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,a0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x7a, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7a,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */
+	{0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{}
+};
+static const struct usb_action pb0330_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, /* 00,1d,09,cc */
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
+	{}
+};
+static const struct usb_action pb0330_NoFlikerScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE},	/* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},	/* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0x09, ZC3XX_R01D_HSYNC_0},	/* 00,1d,09,cc */
+	{0xa0, 0x40, ZC3XX_R01E_HSYNC_1},	/* 00,1e,40,cc */
+	{0xa0, 0x90, ZC3XX_R01F_HSYNC_2},	/* 00,1f,90,cc */
+	{}
+};
+
+/* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
+static const struct usb_action PO2030_mode0[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x04, ZC3XX_R002_CLOCKSELECT},	/* 00,02,04,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */
+	{0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */
+	{0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */
+	{0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */
+	{0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */
+	{0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */
+	{0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */
+	{0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+	{0xaa, 0x8d, 0x0008},			/* 00,8d,08,aa */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},	/* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},	/* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},	/* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},	/* 01,1c,00,cc */
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},	/* 00,9c,e6,cc */
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},	/* 00,9e,86,cc */
+	{0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */
+	{0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+	{0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */
+	{0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */
+	{0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+	{0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+	{0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+	{0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+	{0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+	{0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+	{0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+	{0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+	{0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+	{0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+	{0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+	{0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+	{0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+	{0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+	{0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+	{0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+	{0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+	{0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+	{0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+	{0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+	{0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+	{0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+	{0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+	{0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+	{0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+	{0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+	{0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+	{0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+	{0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+	{0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */
+	{0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */
+	{}
+};
+
+/* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
+static const struct usb_action PO2030_mode1[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
+	{0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */
+	{0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */
+	{0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */
+	{0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */
+	{0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */
+	{0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */
+	{0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */
+	{0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+	{0xaa, 0x8d, 0x0008},			/* 00,8d,08,aa */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
+	{0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */
+	{0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+	{0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */
+	{0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */
+	{0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+	{0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+	{0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+	{0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+	{0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+	{0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+	{0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+	{0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+	{0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+	{0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+	{0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+	{0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+	{0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+	{0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+	{0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+	{0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+	{0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+	{0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+	{0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+	{0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+	{0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+	{0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+	{0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+	{0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+	{0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+	{0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+	{0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+	{0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+	{0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+	{0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */
+	{0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
+	{0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */
+	{0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */
+	{}
+};
+
+static const struct usb_action PO2030_50HZ[] = {
+	{0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+	{0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */
+	{0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */
+	{0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */
+	{0xa0, 0x05, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,05,cc */
+	{0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,35,cc */
+	{0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x85, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,85,cc */
+	{0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,58,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */
+	{0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */
+	{}
+};
+
+static const struct usb_action PO2030_60HZ[] = {
+	{0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+	{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+	{0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */
+	{0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */
+	{0xa0, 0x08, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,08,cc */
+	{0xa0, 0xae, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,ae,cc */
+	{0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x6f, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,6f,cc */
+	{0xa0, 0x20, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,20,cc */
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */
+	{0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,22,cc */
+	{0xa0, 0x88, ZC3XX_R18D_YTARGET},		/* 01,8d,88,cc */
+							/* win: 01,8d,80 */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc */
+	{}
+};
+
+static const struct usb_action PO2030_NoFliker[] = {
+	{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
+	{0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */
+	{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+	{0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */
+	{0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */
+	{0xaa, 0x46, 0x0000}, /* 00,46,00,aa */
+	{0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+	{}
+};
+
+/* TEST */
+static const struct usb_action tas5130CK_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x01, 0x003b},
+	{0xa0, 0x0e, 0x003a},
+	{0xa0, 0x01, 0x0038},
+	{0xa0, 0x0b, 0x0039},
+	{0xa0, 0x00, 0x0038},
+	{0xa0, 0x0b, 0x0039},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xE7, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x87, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2c, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x4c, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf1, ZC3XX_R10B_RGB01},
+	{0xa0, 0x03, ZC3XX_R10C_RGB02},
+	{0xa0, 0xfe, ZC3XX_R10D_RGB10},
+	{0xa0, 0x51, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf1, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0x03, ZC3XX_R111_RGB21},
+	{0xa0, 0x51, ZC3XX_R112_RGB22},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x38, ZC3XX_R120_GAMMA00},	/* gamma > 5 */
+	{0xa0, 0x51, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x6e, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x8c, ZC3XX_R123_GAMMA03},
+	{0xa0, 0xa2, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xb6, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xc8, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xd6, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xe2, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xed, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x12, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x1b, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x1d, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x15, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x12, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x0f, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x4c, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf1, ZC3XX_R10B_RGB01},
+	{0xa0, 0x03, ZC3XX_R10C_RGB02},
+	{0xa0, 0xfe, ZC3XX_R10D_RGB10},
+	{0xa0, 0x51, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf1, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0x03, ZC3XX_R111_RGB21},
+	{0xa0, 0x51, ZC3XX_R112_RGB22},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x09, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x34, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+
+static const struct usb_action tas5130CK_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x01, 0x003b},
+	{0xa0, 0x0e, 0x003a},
+	{0xa0, 0x01, 0x0038},
+	{0xa0, 0x0b, 0x0039},
+	{0xa0, 0x00, 0x0038},
+	{0xa0, 0x0b, 0x0039},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xe5, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x85, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x50, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2C, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x6c, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x4c, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf1, ZC3XX_R10B_RGB01},
+	{0xa0, 0x03, ZC3XX_R10C_RGB02},
+	{0xa0, 0xfe, ZC3XX_R10D_RGB10},
+	{0xa0, 0x51, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf1, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0x03, ZC3XX_R111_RGB21},
+	{0xa0, 0x51, ZC3XX_R112_RGB22},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+	{0xa0, 0x38, ZC3XX_R120_GAMMA00},	/* gamma > 5 */
+	{0xa0, 0x51, ZC3XX_R121_GAMMA01},
+	{0xa0, 0x6e, ZC3XX_R122_GAMMA02},
+	{0xa0, 0x8c, ZC3XX_R123_GAMMA03},
+	{0xa0, 0xa2, ZC3XX_R124_GAMMA04},
+	{0xa0, 0xb6, ZC3XX_R125_GAMMA05},
+	{0xa0, 0xc8, ZC3XX_R126_GAMMA06},
+	{0xa0, 0xd6, ZC3XX_R127_GAMMA07},
+	{0xa0, 0xe2, ZC3XX_R128_GAMMA08},
+	{0xa0, 0xed, ZC3XX_R129_GAMMA09},
+	{0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
+	{0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
+	{0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
+	{0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
+	{0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
+	{0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
+	{0xa0, 0x12, ZC3XX_R130_GAMMA10},
+	{0xa0, 0x1b, ZC3XX_R131_GAMMA11},
+	{0xa0, 0x1d, ZC3XX_R132_GAMMA12},
+	{0xa0, 0x1a, ZC3XX_R133_GAMMA13},
+	{0xa0, 0x15, ZC3XX_R134_GAMMA14},
+	{0xa0, 0x12, ZC3XX_R135_GAMMA15},
+	{0xa0, 0x0f, ZC3XX_R136_GAMMA16},
+	{0xa0, 0x0d, ZC3XX_R137_GAMMA17},
+	{0xa0, 0x0b, ZC3XX_R138_GAMMA18},
+	{0xa0, 0x09, ZC3XX_R139_GAMMA19},
+	{0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
+	{0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
+	{0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
+	{0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
+	{0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
+	{0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
+	{0xa0, 0x4c, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xf1, ZC3XX_R10B_RGB01},
+	{0xa0, 0x03, ZC3XX_R10C_RGB02},
+	{0xa0, 0xfe, ZC3XX_R10D_RGB10},
+	{0xa0, 0x51, ZC3XX_R10E_RGB11},
+	{0xa0, 0xf1, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0x03, ZC3XX_R111_RGB21},
+	{0xa0, 0x51, ZC3XX_R112_RGB22},
+	{0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0x62, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
+	{0xa0, 0xaa, ZC3XX_R093_I2CSETVALUE},
+	{0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
+	{0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x09, 0x01ad},
+	{0xa0, 0x15, 0x01ae},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x30, 0x0007},
+	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x00, 0x0007},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{}
+};
+
+static const struct usb_action tas5130cxx_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x50, ZC3XX_R002_CLOCKSELECT},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN},
+	{0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
+
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+
+	{0xa0, 0x04, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x04, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x68, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xec, ZC3XX_R10B_RGB01},
+	{0xa0, 0xec, ZC3XX_R10C_RGB02},
+	{0xa0, 0xec, ZC3XX_R10D_RGB10},
+	{0xa0, 0x68, ZC3XX_R10E_RGB11},
+	{0xa0, 0xec, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0xec, ZC3XX_R111_RGB21},
+	{0xa0, 0x68, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x018d},
+	{0xa0, 0x90, ZC3XX_R18D_YTARGET},	/* 90 */
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+
+	{0xaa, 0xa3, 0x0001},
+	{0xaa, 0xa4, 0x0077},
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW},
+
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 00 */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},	/* 03 */
+	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW},	/* e8 */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 0 */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 0 */
+	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW},	/* 7d */
+
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 08 */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 24 */
+	{0xa0, 0xf0, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
+	{0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},	/* 50 */
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action tas5130cxx_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+	{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
+
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa1, 0x01, 0x0008},
+
+	{0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+	{0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN},
+	{0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+	{0xa0, 0x05, ZC3XX_R098_WINYSTARTLOW},
+	{0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW},
+	{0xa0, 0x05, ZC3XX_R11A_FIRSTYLOW},
+	{0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW},
+	{0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
+	{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
+	{0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
+	{0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE},
+	{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
+	{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
+	{0xa0, 0x68, ZC3XX_R18D_YTARGET},
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+	{0xa0, 0x00, 0x01ad},
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
+	{0xa1, 0x01, 0x0002},
+	{0xa1, 0x01, 0x0008},
+
+	{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+	{0xa1, 0x01, 0x0008},	/* clock ? */
+	{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},	/* sharpness+ */
+	{0xa1, 0x01, 0x01c8},
+	{0xa1, 0x01, 0x01c9},
+	{0xa1, 0x01, 0x01ca},
+	{0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},	/* sharpness- */
+
+	{0xa0, 0x68, ZC3XX_R10A_RGB00},	/* matrix */
+	{0xa0, 0xec, ZC3XX_R10B_RGB01},
+	{0xa0, 0xec, ZC3XX_R10C_RGB02},
+	{0xa0, 0xec, ZC3XX_R10D_RGB10},
+	{0xa0, 0x68, ZC3XX_R10E_RGB11},
+	{0xa0, 0xec, ZC3XX_R10F_RGB12},
+	{0xa0, 0xec, ZC3XX_R110_RGB20},
+	{0xa0, 0xec, ZC3XX_R111_RGB21},
+	{0xa0, 0x68, ZC3XX_R112_RGB22},
+
+	{0xa1, 0x01, 0x018d},
+	{0xa0, 0x90, ZC3XX_R18D_YTARGET},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+	{0xaa, 0xa3, 0x0001},
+	{0xaa, 0xa4, 0x0063},
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH},
+	{0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW},
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+	{0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW},
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
+	{0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+	{0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+	{0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF},
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+	{0xa0, 0xd3, ZC3XX_R01D_HSYNC_0},
+	{0xa0, 0xda, ZC3XX_R01E_HSYNC_1},
+	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2},
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH},
+	{0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW},
+	{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
+	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
+	{0xa1, 0x01, 0x0180},
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+	{}
+};
+static const struct usb_action tas5130cxx_50HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */
+	{0xa0, 0x38, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,38,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */
+	{0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */
+	{0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{}
+};
+static const struct usb_action tas5130cxx_50HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
+	{0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */
+	{0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */
+	{0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{}
+};
+static const struct usb_action tas5130cxx_60HZ[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */
+	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{}
+};
+static const struct usb_action tas5130cxx_60HZScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+	{0xa0, 0xe8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,e8,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */
+	{0xa0, 0x14, ZC3XX_R18C_AEFREEZE}, /* 01,8c,14,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */
+	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,26,cc */
+	{0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */
+	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */
+	{}
+};
+static const struct usb_action tas5130cxx_NoFliker[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,01,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
+	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+	{}
+};
+
+static const struct usb_action tas5130cxx_NoFlikerScale[] = {
+	{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+	{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+	{0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */
+	{0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */
+	{0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
+	{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,03,cc */
+	{0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */
+	{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
+	{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+	{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
+	{0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+	{0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */
+	{0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */
+	{0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
+	{0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */
+	{}
+};
+
+static const struct usb_action tas5130c_vf0250_Initial[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},		/* 00,00,01,cc, */
+	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},		/* 00,08,02,cc, */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},	/* 00,10,01,cc, */
+	{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},		/* 00,02,00,cc,
+							 * 0<->10 */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},	/* 00,03,02,cc, */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},		/* 00,04,80,cc, */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},	/* 00,05,01,cc, */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},	/* 00,06,e0,cc, */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},		/* 00,8b,98,cc, */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},	/* 00,01,01,cc, */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,03,cc, */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,01,cc, */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},		/* 00,98,00,cc, */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},		/* 00,9a,00,cc, */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},		/* 01,1a,00,cc, */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},		/* 01,1c,00,cc, */
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},		/* 00,9c,e6,cc,
+							 * 6<->8 */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},		/* 00,9e,86,cc,
+							 * 6<->8 */
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},		/* 00,87,10,cc, */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},		/* 00,8b,98,cc, */
+	{0xaa, 0x1b, 0x0024},		/* 00,1b,24,aa, */
+	{0xdd, 0x00, 0x0080},		/* 00,00,80,dd, */
+	{0xaa, 0x1b, 0x0000},		/* 00,1b,00,aa, */
+	{0xaa, 0x13, 0x0002},		/* 00,13,02,aa, */
+	{0xaa, 0x15, 0x0004},		/* 00,15,04,aa */
+	{0xaa, 0x01, 0x0000},
+	{0xaa, 0x01, 0x0000},
+	{0xaa, 0x1a, 0x0000},		/* 00,1a,00,aa, */
+	{0xaa, 0x1c, 0x0017},		/* 00,1c,17,aa, */
+	{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},		/* 00,86,82,cc, */
+	{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},		/* 00,87,83,cc, */
+	{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},		/* 00,88,84,cc, */
+	{0xaa, 0x05, 0x0010},		/* 00,05,10,aa, */
+	{0xaa, 0x0a, 0x0000},		/* 00,0a,00,aa, */
+	{0xaa, 0x0b, 0x00a0},		/* 00,0b,a0,aa, */
+	{0xaa, 0x0c, 0x0000},		/* 00,0c,00,aa, */
+	{0xaa, 0x0d, 0x00a0},		/* 00,0d,a0,aa, */
+	{0xaa, 0x0e, 0x0000},		/* 00,0e,00,aa, */
+	{0xaa, 0x0f, 0x00a0},		/* 00,0f,a0,aa, */
+	{0xaa, 0x10, 0x0000},		/* 00,10,00,aa, */
+	{0xaa, 0x11, 0x00a0},		/* 00,11,a0,aa, */
+	{0xa0, 0x00, 0x0039},
+	{0xa1, 0x01, 0x0037},
+	{0xaa, 0x16, 0x0001},		/* 00,16,01,aa, */
+	{0xaa, 0x17, 0x00e8},		/* 00,17,e6,aa, (e6 -> e8) */
+	{0xaa, 0x18, 0x0002},		/* 00,18,02,aa, */
+	{0xaa, 0x19, 0x0088},		/* 00,19,86,aa, */
+	{0xaa, 0x20, 0x0020},		/* 00,20,20,aa, */
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},	/* 01,01,b7,cc, */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,05,cc, */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},		/* 01,00,0d,cc, */
+	{0xa0, 0x76, ZC3XX_R189_AWBSTATUS},		/* 01,89,76,cc, */
+	{0xa0, 0x09, 0x01ad},				/* 01,ad,09,cc, */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},		/* 01,c5,03,cc, */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},		/* 01,cb,13,cc, */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},	/* 02,50,08,cc, */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},		/* 03,01,08,cc, */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},		/* 01,a8,60,cc, */
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},			/* 01,16,61,cc, */
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},			/* 01,18,65,cc */
+	{}
+};
+
+static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+	{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},		/* 00,00,01,cc, */
+	{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},		/* 00,08,02,cc, */
+	{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},	/* 00,10,01,cc, */
+	{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},		/* 00,02,10,cc, */
+	{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},	/* 00,03,02,cc, */
+	{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},		/* 00,04,80,cc, */
+	{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},	/* 00,05,01,cc, */
+	{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},	/* 00,06,e0,cc, */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},		/* 00,8b,98,cc, */
+	{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},	/* 00,01,01,cc, */
+	{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,03,cc, */
+	{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,01,cc, */
+	{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},		/* 00,98,00,cc, */
+	{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},		/* 00,9a,00,cc, */
+	{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},		/* 01,1a,00,cc, */
+	{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},		/* 01,1c,00,cc, */
+	{0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},		/* 00,9c,e8,cc,
+							 * 8<->6 */
+	{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},		/* 00,9e,88,cc,
+							 * 8<->6 */
+	{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},		/* 00,87,10,cc, */
+	{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},		/* 00,8b,98,cc, */
+	{0xaa, 0x1b, 0x0024},		/* 00,1b,24,aa, */
+	{0xdd, 0x00, 0x0080},		/* 00,00,80,dd, */
+	{0xaa, 0x1b, 0x0000},		/* 00,1b,00,aa, */
+	{0xaa, 0x13, 0x0002},		/* 00,13,02,aa, */
+	{0xaa, 0x15, 0x0004},		/* 00,15,04,aa */
+	{0xaa, 0x01, 0x0000},
+	{0xaa, 0x01, 0x0000},
+	{0xaa, 0x1a, 0x0000},		/* 00,1a,00,aa, */
+	{0xaa, 0x1c, 0x0017},		/* 00,1c,17,aa, */
+	{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},	/* 00,86,82,cc, */
+	{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},	/* 00,87,83,cc, */
+	{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},	/* 00,88,84,cc, */
+	{0xaa, 0x05, 0x0010},		/* 00,05,10,aa, */
+	{0xaa, 0x0a, 0x0000},		/* 00,0a,00,aa, */
+	{0xaa, 0x0b, 0x00a0},		/* 00,0b,a0,aa, */
+	{0xaa, 0x0c, 0x0000},		/* 00,0c,00,aa, */
+	{0xaa, 0x0d, 0x00a0},		/* 00,0d,a0,aa, */
+	{0xaa, 0x0e, 0x0000},		/* 00,0e,00,aa, */
+	{0xaa, 0x0f, 0x00a0},		/* 00,0f,a0,aa, */
+	{0xaa, 0x10, 0x0000},		/* 00,10,00,aa, */
+	{0xaa, 0x11, 0x00a0},		/* 00,11,a0,aa, */
+	{0xa0, 0x00, 0x0039},
+	{0xa1, 0x01, 0x0037},
+	{0xaa, 0x16, 0x0001},		/* 00,16,01,aa, */
+	{0xaa, 0x17, 0x00e8},		/* 00,17,e6,aa (e6 -> e8) */
+	{0xaa, 0x18, 0x0002},		/* 00,18,02,aa, */
+	{0xaa, 0x19, 0x0088},		/* 00,19,88,aa, */
+	{0xaa, 0x20, 0x0020},		/* 00,20,20,aa, */
+	{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},	/* 01,01,b7,cc, */
+	{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},	/* 00,12,05,cc, */
+	{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},		/* 01,00,0d,cc, */
+	{0xa0, 0x76, ZC3XX_R189_AWBSTATUS},		/* 01,89,76,cc, */
+	{0xa0, 0x09, 0x01ad},				/* 01,ad,09,cc, */
+	{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},		/* 01,c5,03,cc, */
+	{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},		/* 01,cb,13,cc, */
+	{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},	/* 02,50,08,cc, */
+	{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},		/* 03,01,08,cc, */
+	{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},		/* 01,a8,60,cc, */
+	{0xa0, 0x61, ZC3XX_R116_RGAIN},		/* 01,16,61,cc, */
+	{0xa0, 0x65, ZC3XX_R118_BGAIN},		/* 01,18,65,cc */
+	{}
+};
+/* "50HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZ[] = {
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0001},		/* 00,83,01,aa */
+	{0xaa, 0x84, 0x00aa},		/* 00,84,aa,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc, */
+	{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,0d,cc, */
+	{0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,50,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc, */
+	{0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,47,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,8c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,8f,15,cc, */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,a9,10,cc, */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,24,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,1d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,1e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,1f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,20,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc, */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc, */
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},		/* 01,8d,78,cc */
+	{}
+};
+
+/* "50HZScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0003},		/* 00,83,03,aa */
+	{0xaa, 0x84, 0x0054},		/* 00,84,54,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc, */
+	{0xa0, 0x0d, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,0d,cc, */
+	{0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,50,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc, */
+	{0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,8e,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,8c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,8f,15,cc, */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,a9,10,cc, */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,24,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,1d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,1e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,1f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,20,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc, */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc, */
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},		/* 01,8d,78,cc */
+	{}
+};
+
+/* "60HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_60HZ[] = {
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0001},		/* 00,83,01,aa */
+	{0xaa, 0x84, 0x0062},		/* 00,84,62,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc, */
+	{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,05,cc, */
+	{0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,88,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc, */
+	{0xa0, 0x3b, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,3b,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,8c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,8f,15,cc, */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,a9,10,cc, */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,aa,24,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,1d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,1e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,1f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,20,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc, */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc, */
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},		/* 01,8d,78,cc */
+	{}
+};
+
+/* "60HZScale" light frequency banding ilter */
+static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0002},		/* 00,83,02,aa */
+	{0xaa, 0x84, 0x00c4},		/* 00,84,c4,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc, */
+	{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,1,0b,cc, */
+	{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,2,10,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,5,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,6,00,cc, */
+	{0xa0, 0x76, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,7,76,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,f,15,cc, */
+	{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},	/* 01,9,10,cc, */
+	{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},	/* 01,a,24,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,0,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,d,58,cc, */
+	{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,42,cc, */
+	{0xa0, 0x78, ZC3XX_R18D_YTARGET},		/* 01,d,78,cc */
+	{}
+};
+
+/* "NoFliker" light frequency banding flter */
+static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+	{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE},		/* 01,00,0c,cc, */
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0000},		/* 00,83,00,aa */
+	{0xaa, 0x84, 0x0020},		/* 00,84,20,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,0,00,cc, */
+	{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,05,cc, */
+	{0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,88,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc, */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,10,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,8c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,8f,15,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,1d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,1e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,1f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,20,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc, */
+	{0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,03,cc */
+	{}
+};
+
+/* "NoFlikerScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+	{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE},		/* 01,00,0c,cc, */
+	{0xaa, 0x82, 0x0000},		/* 00,82,00,aa */
+	{0xaa, 0x83, 0x0000},		/* 00,83,00,aa */
+	{0xaa, 0x84, 0x0020},		/* 00,84,20,aa */
+	{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},	/* 01,90,00,cc, */
+	{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},	/* 01,91,0b,cc, */
+	{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW},	/* 01,92,10,cc, */
+	{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},	/* 01,95,00,cc, */
+	{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},	/* 01,96,00,cc, */
+	{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW},	/* 01,97,10,cc, */
+	{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},		/* 01,8c,0e,cc, */
+	{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},		/* 01,8f,15,cc, */
+	{0xa0, 0x62, ZC3XX_R01D_HSYNC_0},		/* 00,1d,62,cc, */
+	{0xa0, 0x90, ZC3XX_R01E_HSYNC_1},		/* 00,1e,90,cc, */
+	{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},		/* 00,1f,c8,cc, */
+	{0xa0, 0xff, ZC3XX_R020_HSYNC_3},		/* 00,20,ff,cc, */
+	{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},		/* 01,1d,58,cc, */
+	{0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE},	/* 01,80,03,cc */
+	{}
+};
+
+static int reg_r_i(struct gspca_dev *gspca_dev,
+		__u16 index)
+{
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0xa1,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0x01,			/* value */
+			index, gspca_dev->usb_buf, 1,
+			500);
+	return gspca_dev->usb_buf[0];
+}
+
+static int reg_r(struct gspca_dev *gspca_dev,
+		__u16 index)
+{
+	int ret;
+
+	ret = reg_r_i(gspca_dev, index);
+	PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
+	return ret;
+}
+
+static void reg_w_i(struct usb_device *dev,
+			__u8 value,
+			__u16 index)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0xa0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			__u8 value,
+			__u16 index)
+{
+	PDEBUG(D_USBO, "reg w %02x -> [%04x]", value, index);
+	reg_w_i(dev, value, index);
+}
+
+static __u16 i2c_read(struct gspca_dev *gspca_dev,
+			__u8 reg)
+{
+	__u8 retbyte;
+	__u8 retval[2];
+
+	reg_w_i(gspca_dev->dev, reg, 0x92);
+	reg_w_i(gspca_dev->dev, 0x02, 0x90);		/* <- read command */
+	msleep(25);
+	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	retval[0] = reg_r_i(gspca_dev, 0x0095);		/* read Lowbyte */
+	retval[1] = reg_r_i(gspca_dev, 0x0096);		/* read Hightbyte */
+	PDEBUG(D_USBO, "i2c r [%02x] -> (%02x) %02x%02x",
+			reg, retbyte, retval[1], retval[0]);
+	return (retval[1] << 8) | retval[0];
+}
+
+static __u8 i2c_write(struct gspca_dev *gspca_dev,
+			__u8 reg,
+			__u8 valL,
+			__u8 valH)
+{
+	__u8 retbyte;
+
+	reg_w_i(gspca_dev->dev, reg, 0x92);
+	reg_w_i(gspca_dev->dev, valL, 0x93);
+	reg_w_i(gspca_dev->dev, valH, 0x94);
+	reg_w_i(gspca_dev->dev, 0x01, 0x90);		/* <- write command */
+	msleep(5);
+	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	PDEBUG(D_USBO, "i2c w [%02x] %02x%02x (%02x)",
+			reg, valH, valL, retbyte);
+	return retbyte;
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+			const struct usb_action *action)
+{
+	while (action->req) {
+		switch (action->req) {
+		case 0xa0:	/* write register */
+			reg_w(gspca_dev->dev, action->val, action->idx);
+			break;
+		case 0xa1:	/* read status */
+			reg_r(gspca_dev, action->idx);
+			break;
+		case 0xaa:
+			i2c_write(gspca_dev,
+				  action->val,			/* reg */
+				  action->idx & 0xff,		/* valL */
+				  action->idx >> 8);		/* valH */
+			break;
+		default:
+/*		case 0xdd:	 * delay */
+			msleep(action->val / 64 + 10);
+			break;
+		}
+		action++;
+/*		msleep(1); */
+	}
+}
+
+static void setmatrix(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	const __u8 *matrix;
+	static const __u8 gc0305_matrix[9] =
+		{0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
+	static const __u8 ov7620_matrix[9] =
+		{0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
+	static const __u8 po2030_matrix[9] =
+		{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
+
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+		matrix = gc0305_matrix;
+		break;
+	case SENSOR_MC501CB:
+		return;		/* no matrix? */
+	case SENSOR_OV7620:
+/*	case SENSOR_OV7648: */
+		matrix = ov7620_matrix;
+		break;
+	case SENSOR_PO2030:
+		matrix = po2030_matrix;
+		break;
+	case SENSOR_TAS5130C_VF0250:	/* no matrix? */
+		return;
+	default:		/* matrix already loaded */
+		return;
+	}
+	for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++)
+		reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 brightness;
+
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PO2030:
+		return;
+	}
+/*fixme: is it really write to 011d and 018d for all other sensors? */
+	brightness = sd->brightness;
+	reg_w(gspca_dev->dev, brightness, 0x011d);
+	if (brightness < 0x70)
+		brightness += 0x10;
+	else
+		brightness = 0x80;
+	reg_w(gspca_dev->dev, brightness, 0x018d);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int sharpness;
+	static const __u8 sharpness_tb[][2] = {
+		{0x02, 0x03},
+		{0x04, 0x07},
+		{0x08, 0x0f},
+		{0x10, 0x1e}
+	};
+
+	sharpness = sd->sharpness;
+	reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
+	reg_r(gspca_dev, 0x01c8);
+	reg_r(gspca_dev, 0x01c9);
+	reg_r(gspca_dev, 0x01ca);
+	reg_w(dev, sharpness_tb[sharpness][1], 0x01cb);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	const __u8 *Tgamma, *Tgradient;
+	int g, i, k;
+	static const __u8 kgamma_tb[16] =	/* delta for contrast */
+		{0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08,
+		 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+	static const __u8 kgrad_tb[16] =
+		{0x1b, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
+		 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04};
+	static const __u8 Tgamma_1[16] =
+		{0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f,
+		 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff};
+	static const __u8 Tgradient_1[16] =
+		{0x00, 0x01, 0x05, 0x0b, 0x10, 0x15, 0x18, 0x1a,
+		 0x1a, 0x18, 0x16, 0x14, 0x12, 0x0f, 0x0d, 0x06};
+	static const __u8 Tgamma_2[16] =
+		{0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c,
+		 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff};
+	static const __u8 Tgradient_2[16] =
+		{0x05, 0x0f, 0x16, 0x1a, 0x19, 0x19, 0x17, 0x15,
+		 0x12, 0x10, 0x0e, 0x0b, 0x09, 0x08, 0x06, 0x03};
+	static const __u8 Tgamma_3[16] =
+		{0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac,
+		 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff};
+	static const __u8 Tgradient_3[16] =
+		{0x0c, 0x16, 0x1b, 0x1c, 0x19, 0x18, 0x15, 0x12,
+		 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x05, 0x03};
+	static const __u8 Tgamma_4[16] =
+		{0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+		 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff};
+	static const __u8 Tgradient_4[16] =
+		{0x26, 0x22, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0d,
+		 0x0b, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02};
+	static const __u8 Tgamma_5[16] =
+		{0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2,
+		 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff};
+	static const __u8 Tgradient_5[16] =
+		{0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
+		 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
+	static const __u8 Tgamma_6[16] =		/* ?? was gamma 5 */
+		{0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
+		 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
+	static const __u8 Tgradient_6[16] =
+		{0x18, 0x20, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0e,
+		 0x0b, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01};
+	static const __u8 *gamma_tb[] = {
+		NULL, Tgamma_1, Tgamma_2,
+		Tgamma_3, Tgamma_4, Tgamma_5, Tgamma_6
+	};
+	static const __u8 *gradient_tb[] = {
+		NULL, Tgradient_1, Tgradient_2,
+		Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
+	};
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	__u8 v[16];
+#endif
+
+	Tgamma = gamma_tb[sd->gamma];
+	Tgradient = gradient_tb[sd->gamma];
+
+	k = (sd->contrast - 128)		/* -128 / 128 */
+			* Tgamma[0];
+	PDEBUG(D_CONF, "gamma:%d contrast:%d gamma coeff: %d/128",
+		sd->gamma, sd->contrast, k);
+	for (i = 0; i < 16; i++) {
+		g = Tgamma[i] + kgamma_tb[i] * k / 128;
+		if (g > 0xff)
+			g = 0xff;
+		else if (g <= 0)
+			g = 1;
+		reg_w(dev, g, 0x0120 + i);	/* gamma */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+		if (gspca_debug & D_CONF)
+			v[i] = g;
+#endif
+	}
+	PDEBUG(D_CONF, "tb: %02x %02x %02x %02x %02x %02x %02x %02x",
+		v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+	PDEBUG(D_CONF, "    %02x %02x %02x %02x %02x %02x %02x %02x",
+		v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+	for (i = 0; i < 16; i++) {
+		g = Tgradient[i] - kgrad_tb[i] * k / 128;
+		if (g > 0xff)
+			g = 0xff;
+		else if (g <= 0) {
+			if (i != 15)
+				g = 0;
+			else
+				g = 1;
+		}
+		reg_w(dev, g, 0x0130 + i);	/* gradient */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+		if (gspca_debug & D_CONF)
+			v[i] = g;
+#endif
+	}
+	PDEBUG(D_CONF, "    %02x %02x %02x %02x %02x %02x %02x %02x",
+		v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+	PDEBUG(D_CONF, "    %02x %02x %02x %02x %02x %02x %02x %02x",
+		v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 quality;
+	__u8 frxt;
+
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PO2030:
+		return;
+	}
+/*fixme: is it really 0008 0007 0018 for all other sensors? */
+	quality = sd->qindex;
+	reg_w(dev, quality, 0x0008);
+	frxt = 0x30;
+	reg_w(dev, frxt, 0x0007);
+	switch (quality) {
+	case 0:
+	case 1:
+	case 2:
+		frxt = 0xff;
+		break;
+	case 3:
+		frxt = 0xf0;
+		break;
+	case 4:
+		frxt = 0xe0;
+		break;
+	case 5:
+		frxt = 0x20;
+		break;
+	}
+	reg_w(dev, frxt, 0x0018);
+}
+
+/* Matches the sensor's internal frame rate to the lighting frequency.
+ * Valid frequencies are:
+ *	50Hz, for European and Asian lighting (default)
+ *	60Hz, for American lighting
+ *	0 = No Fliker (for outdoore usage)
+ * Returns: 0 for success
+ */
+static int setlightfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, mode;
+	const struct usb_action *zc3_freq;
+	static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
+/* SENSOR_CS2102 0 */
+		{cs2102_NoFliker, cs2102_NoFlikerScale,
+		 cs2102_50HZ, cs2102_50HZScale,
+		 cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_CS2102K 1 */
+		{cs2102_NoFliker, cs2102_NoFlikerScale,
+		 cs2102_50HZ, cs2102_50HZScale,
+		 cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_GC0305 2 */
+		{gc0305_NoFliker, gc0305_NoFliker,
+		 gc0305_50HZ, gc0305_50HZ,
+		 gc0305_60HZ, gc0305_60HZ},
+/* SENSOR_HDCS2020 3 */
+		{NULL, NULL,
+		 NULL, NULL,
+		 NULL, NULL},
+/* SENSOR_HDCS2020b 4 */
+		{hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+		 hdcs2020b_50HZ, hdcs2020b_50HZ,
+		 hdcs2020b_60HZ, hdcs2020b_60HZ},
+/* SENSOR_HV7131B 5 */
+		{NULL, NULL,
+		 NULL, NULL,
+		 NULL, NULL},
+/* SENSOR_HV7131C 6 */
+		{NULL, NULL,
+		 NULL, NULL,
+		 NULL, NULL},
+/* SENSOR_ICM105A 7 */
+		{icm105a_NoFliker, icm105a_NoFlikerScale,
+		 icm105a_50HZ, icm105a_50HZScale,
+		 icm105a_60HZ, icm105a_60HZScale},
+/* SENSOR_MC501CB 8 */
+		{MC501CB_NoFliker, MC501CB_NoFlikerScale,
+		 MC501CB_50HZ, MC501CB_50HZScale,
+		 MC501CB_60HZ, MC501CB_60HZScale},
+/* SENSOR_OV7620 9 */
+		{OV7620_NoFliker, OV7620_NoFliker,
+		 OV7620_50HZ, OV7620_50HZ,
+		 OV7620_60HZ, OV7620_60HZ},
+/* SENSOR_OV7630C 10 */
+		{NULL, NULL,
+		 NULL, NULL,
+		 NULL, NULL},
+/* SENSOR_PAS106 11 */
+		{pas106b_NoFliker, pas106b_NoFliker,
+		 pas106b_50HZ, pas106b_50HZ,
+		 pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PB0330 12 */
+		{pb0330_NoFliker, pb0330_NoFlikerScale,
+		 pb0330_50HZ, pb0330_50HZScale,
+		 pb0330_60HZ, pb0330_60HZScale},
+/* SENSOR_PO2030 13 */
+		{PO2030_NoFliker, PO2030_NoFliker,
+		 PO2030_50HZ, PO2030_50HZ,
+		 PO2030_60HZ, PO2030_60HZ},
+/* SENSOR_TAS5130CK 14 */
+		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
+		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130CXX 15 */
+		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
+		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130C_VF0250 16 */
+		{tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+		 tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+		 tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
+	};
+
+	i = sd->lightfreq * 2;
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	if (!mode)
+		i++;			/* 640x480 */
+	zc3_freq = freq_tb[(int) sd->sensor][i];
+	if (zc3_freq != NULL) {
+		usb_exchange(gspca_dev, zc3_freq);
+		switch (sd->sensor) {
+		case SENSOR_GC0305:
+			if (mode			/* if 320x240 */
+			    && sd->lightfreq == 1)	/* and 50Hz */
+				reg_w(gspca_dev->dev, 0x85, 0x018d);
+						/* win: 0x80, 0x018d */
+			break;
+		case SENSOR_OV7620:
+			if (!mode) {			/* if 640x480 */
+				if (sd->lightfreq != 0)	/* and 50 or 60 Hz */
+					reg_w(gspca_dev->dev, 0x40, 0x0002);
+				else
+					reg_w(gspca_dev->dev, 0x44, 0x0002);
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 autoval;
+
+	if (sd->autogain)
+		autoval = 0x42;
+	else
+		autoval = 0x02;
+	reg_w(gspca_dev->dev, autoval, 0x0180);
+}
+
+static void send_unknown(struct usb_device *dev, int sensor)
+{
+	reg_w(dev, 0x01, 0x0000);		/* led off */
+	switch (sensor) {
+	case SENSOR_PAS106:
+		reg_w(dev, 0x03, 0x003a);
+		reg_w(dev, 0x0c, 0x003b);
+		reg_w(dev, 0x08, 0x0038);
+		break;
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PB0330:
+	case SENSOR_PO2030:
+		reg_w(dev, 0x0d, 0x003a);
+		reg_w(dev, 0x02, 0x003b);
+		reg_w(dev, 0x00, 0x0038);
+		break;
+	}
+}
+
+/* start probe 2 wires */
+static void start_2wr_probe(struct usb_device *dev, int sensor)
+{
+	reg_w(dev, 0x01, 0x0000);
+	reg_w(dev, sensor, 0x0010);
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0x03, 0x0012);
+	reg_w(dev, 0x01, 0x0012);
+/*	msleep(2); */
+}
+
+static int sif_probe(struct gspca_dev *gspca_dev)
+{
+	__u16 checkword;
+
+	start_2wr_probe(gspca_dev->dev, 0x0f);		/* PAS106 */
+	reg_w(gspca_dev->dev, 0x08, 0x008d);
+	msleep(150);
+	checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4)
+			| ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4);
+	PDEBUG(D_PROBE, "probe sif 0x%04x", checkword);
+	if (checkword == 0x0007) {
+		send_unknown(gspca_dev->dev, SENSOR_PAS106);
+		return 0x0f;			/* PAS106 */
+	}
+	return -1;
+}
+
+static int vga_2wr_probe(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 retbyte;
+	__u16 checkword;
+
+	start_2wr_probe(dev, 0x00);		/* HV7131B */
+	i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x01);
+	if (retbyte != 0)
+		return 0x00;			/* HV7131B */
+
+	start_2wr_probe(dev, 0x04);		/* CS2102 */
+	i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x01);
+	if (retbyte != 0)
+		return 0x04;			/* CS2102 */
+
+	start_2wr_probe(dev, 0x06);		/* OmniVision */
+	reg_w(dev, 0x08, 0x8d);
+	i2c_write(gspca_dev, 0x11, 0xaa, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x11);
+	if (retbyte != 0) {
+		/* (should have returned 0xaa) --> Omnivision? */
+		/* reg_r 0x10 -> 0x06 -->  */
+		goto ov_check;
+	}
+
+	start_2wr_probe(dev, 0x08);		/* HDCS2020 */
+	i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x15);
+	if (retbyte != 0)
+		return 0x08;			/* HDCS2020 */
+
+	start_2wr_probe(dev, 0x0a);		/* PB0330 */
+	i2c_write(gspca_dev, 0x07, 0xaa, 0xaa);
+	retbyte = i2c_read(gspca_dev, 0x07);
+	if (retbyte != 0)
+		return 0x0a;			/* PB0330 */
+	retbyte = i2c_read(gspca_dev, 0x03);
+	if (retbyte != 0)
+		return 0x0a;			/* PB0330 ?? */
+	retbyte = i2c_read(gspca_dev, 0x04);
+	if (retbyte != 0)
+		return 0x0a;			/* PB0330 ?? */
+
+	start_2wr_probe(dev, 0x0c);		/* ICM105A */
+	i2c_write(gspca_dev, 0x01, 0x11, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x01);
+	if (retbyte != 0)
+		return 0x0c;			/* ICM105A */
+
+	start_2wr_probe(dev, 0x0e);		/* PAS202BCB */
+	reg_w(dev, 0x08, 0x8d);
+	i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
+	msleep(500);
+	retbyte = i2c_read(gspca_dev, 0x03);
+	if (retbyte != 0)
+		return 0x0e;			/* PAS202BCB */
+
+	start_2wr_probe(dev, 0x02);		/* ?? */
+	i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
+	retbyte = i2c_read(gspca_dev, 0x01);
+	if (retbyte != 0)
+		return 0x02;			/* ?? */
+ov_check:
+	reg_r(gspca_dev, 0x0010);		/* ?? */
+	reg_r(gspca_dev, 0x0010);
+
+	reg_w(dev, 0x01, 0x0000);
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0x06, 0x0010);		/* OmniVision */
+	reg_w(dev, 0xa1, 0x008b);
+	reg_w(dev, 0x08, 0x008d);
+	msleep(500);
+	reg_w(dev, 0x01, 0x0012);
+	i2c_write(gspca_dev, 0x12, 0x80, 0x00);	/* sensor reset */
+	retbyte = i2c_read(gspca_dev, 0x0a);
+	checkword = retbyte << 8;
+	retbyte = i2c_read(gspca_dev, 0x0b);
+	checkword |= retbyte;
+	PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword);
+	switch (checkword) {
+	case 0x7631:				/* OV7630C */
+		reg_w(dev, 0x06, 0x0010);
+		break;
+	case 0x7620:				/* OV7620 */
+	case 0x7648:				/* OV7648 */
+		break;
+	default:
+		return -1;			/* not OmniVision */
+	}
+	return checkword;
+}
+
+struct sensor_by_chipset_revision {
+	__u16 revision;
+	__u8 internal_sensor_id;
+};
+static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
+	{0xc001, 0x13},		/* MI0360 */
+	{0xe001, 0x13},
+	{0x8001, 0x13},
+	{0x8000, 0x14},		/* CS2102K */
+	{0x8400, 0x15},		/* TAS5130K */
+	{0, 0}
+};
+
+static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+	__u8 retbyte;
+	__u16 checkword;
+
+/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
+	reg_w(dev, 0x02, 0x0010);
+	reg_r(gspca_dev, 0x10);
+	reg_w(dev, 0x01, 0x0000);
+	reg_w(dev, 0x00, 0x0010);
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0x91, 0x008b);
+	reg_w(dev, 0x03, 0x0012);
+	reg_w(dev, 0x01, 0x0012);
+	reg_w(dev, 0x05, 0x0012);
+	retbyte = i2c_read(gspca_dev, 0x14);
+	if (retbyte != 0)
+		return 0x11;			/* HV7131R */
+	retbyte = i2c_read(gspca_dev, 0x15);
+	if (retbyte != 0)
+		return 0x11;			/* HV7131R */
+	retbyte = i2c_read(gspca_dev, 0x16);
+	if (retbyte != 0)
+		return 0x11;			/* HV7131R */
+
+	reg_w(dev, 0x02, 0x0010);
+	retbyte = reg_r(gspca_dev, 0x000b);
+	checkword = retbyte << 8;
+	retbyte = reg_r(gspca_dev, 0x000a);
+	checkword |= retbyte;
+	PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword);
+	reg_r(gspca_dev, 0x0010);
+	/* this is tested only once anyway */
+	i = 0;
+	while (chipset_revision_sensor[i].revision) {
+		if (chipset_revision_sensor[i].revision == checkword) {
+			sd->chip_revision = checkword;
+			send_unknown(dev, SENSOR_PB0330);
+			return chipset_revision_sensor[i].internal_sensor_id;
+		}
+		i++;
+	}
+
+	reg_w(dev, 0x01, 0x0000);
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0xdd, 0x008b);
+	reg_w(dev, 0x0a, 0x0010);
+	reg_w(dev, 0x03, 0x0012);
+	reg_w(dev, 0x01, 0x0012);
+	retbyte = i2c_read(gspca_dev, 0x00);
+	if (retbyte != 0) {
+		PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+		return 0x0a;			/* ?? */
+	}
+
+	reg_w(dev, 0x01, 0x0000);
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0x98, 0x008b);
+	reg_w(dev, 0x01, 0x0010);
+	reg_w(dev, 0x03, 0x0012);
+	msleep(2);
+	reg_w(dev, 0x01, 0x0012);
+	retbyte = i2c_read(gspca_dev, 0x00);
+	if (retbyte != 0) {
+		PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte);
+		send_unknown(dev, SENSOR_GC0305);
+		return retbyte;		/* 0x29 = gc0305 - should continue? */
+	}
+
+	reg_w(dev, 0x01, 0x0000);	/* check OmniVision */
+	reg_w(dev, 0x01, 0x0001);
+	reg_w(dev, 0xa1, 0x008b);
+	reg_w(dev, 0x08, 0x008d);
+	reg_w(dev, 0x06, 0x0010);
+	reg_w(dev, 0x01, 0x0012);
+	reg_w(dev, 0x05, 0x0012);
+	if (i2c_read(gspca_dev, 0x1c) == 0x7f	/* OV7610 - manufacturer ID */
+	    && i2c_read(gspca_dev, 0x1d) == 0xa2) {
+		send_unknown(dev, SENSOR_OV7620);
+		return 0x06;		/* OmniVision confirm ? */
+	}
+
+	reg_w(dev, 0x01, 0x00);
+	reg_w(dev, 0x00, 0x02);
+	reg_w(dev, 0x01, 0x10);
+	reg_w(dev, 0x01, 0x01);
+	reg_w(dev, 0xee, 0x8b);
+	reg_w(dev, 0x03, 0x12);
+/*	msleep(150); */
+	reg_w(dev, 0x01, 0x12);
+	reg_w(dev, 0x05, 0x12);
+	retbyte = i2c_read(gspca_dev, 0x00);		/* ID 0 */
+	checkword = retbyte << 8;
+	retbyte = i2c_read(gspca_dev, 0x01);		/* ID 1 */
+	checkword |= retbyte;
+	PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword);
+	if (checkword == 0x2030) {
+		retbyte = i2c_read(gspca_dev, 0x02);	/* revision number */
+		PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+		send_unknown(dev, SENSOR_PO2030);
+		return checkword;
+	}
+
+	reg_w(dev, 0x01, 0x00);
+	reg_w(dev, 0x0a, 0x10);
+	reg_w(dev, 0xd3, 0x8b);
+	reg_w(dev, 0x01, 0x01);
+	reg_w(dev, 0x03, 0x12);
+	reg_w(dev, 0x01, 0x12);
+	reg_w(dev, 0x05, 0x01);
+	reg_w(dev, 0xd3, 0x8b);
+	retbyte = i2c_read(gspca_dev, 0x01);
+	if (retbyte != 0) {
+		PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+		return 0x0a;			/* ?? */
+	}
+	return -1;
+}
+
+static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int sensor, sensor2;
+
+	switch (sd->sensor) {
+	case SENSOR_MC501CB:
+	case SENSOR_TAS5130C_VF0250:
+		return -1;		/* don't probe */
+	}
+	sensor = vga_2wr_probe(gspca_dev);
+	if (sensor >= 0) {
+		if (sensor < 0x7600)
+			return sensor;
+		/* next probe is needed for OmniVision ? */
+	}
+	sensor2 = vga_3wr_probe(gspca_dev);
+	if (sensor2 >= 0) {
+		if (sensor >= 0)
+			return sensor;
+		return sensor2;
+	}
+	return sif_probe(gspca_dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	int sensor;
+	int vga = 1;		/* 1: vga, 0: sif */
+	static const __u8 gamma[SENSOR_MAX] = {
+		5,	/* SENSOR_CS2102 0 */
+		5,	/* SENSOR_CS2102K 1 */
+		4,	/* SENSOR_GC0305 2 */
+		4,	/* SENSOR_HDCS2020 3 */
+		4,	/* SENSOR_HDCS2020b 4 */
+		4,	/* SENSOR_HV7131B 5 */
+		4,	/* SENSOR_HV7131C 6 */
+		4,	/* SENSOR_ICM105A 7 */
+		4,	/* SENSOR_MC501CB 8 */
+		3,	/* SENSOR_OV7620 9 */
+		4,	/* SENSOR_OV7630C 10 */
+		4,	/* SENSOR_PAS106 11 */
+		4,	/* SENSOR_PB0330 12 */
+		4,	/* SENSOR_PO2030 13 */
+		4,	/* SENSOR_TAS5130CK 14 */
+		4,	/* SENSOR_TAS5130CXX 15 */
+		3,	/* SENSOR_TAS5130C_VF0250 16 */
+	};
+
+	/* define some sensors from the vendor/product */
+	sd->sharpness = 2;
+	switch (id->idVendor) {
+	case 0x041e:				/* Creative */
+		switch (id->idProduct) {
+		case 0x4051:			/* zc301 chips */
+		case 0x4053:
+			sd->sensor = SENSOR_TAS5130C_VF0250;
+			break;
+		}
+		break;
+	case 0x046d:				/* Logitech Labtec */
+		switch (id->idProduct) {
+		case 0x08dd:
+			sd->sensor = SENSOR_MC501CB;
+			break;
+		}
+		break;
+	case 0x0ac8:				/* Vimicro z-star */
+		switch (id->idProduct) {
+		case 0x305b:
+			sd->sensor = SENSOR_TAS5130C_VF0250;
+			break;
+		}
+		break;
+	}
+	sensor = zcxx_probeSensor(gspca_dev);
+	if (sensor >= 0)
+		PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
+	if ((unsigned) force_sensor < SENSOR_MAX) {
+		sd->sensor = force_sensor;
+		PDEBUG(D_PROBE, "sensor forced to %d", force_sensor);
+	} else {
+		switch (sensor) {
+		case -1:
+			switch (sd->sensor) {
+			case SENSOR_MC501CB:
+				PDEBUG(D_PROBE, "Sensor MC501CB");
+				break;
+			case SENSOR_TAS5130C_VF0250:
+				PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
+				break;
+			default:
+				PDEBUG(D_PROBE,
+					"Sensor UNKNOW_0 force Tas5130");
+				sd->sensor = SENSOR_TAS5130CXX;
+			}
+			break;
+		case 0:
+			PDEBUG(D_PROBE, "Find Sensor HV7131B");
+			sd->sensor = SENSOR_HV7131B;
+			break;
+		case 0x04:
+			PDEBUG(D_PROBE, "Find Sensor CS2102");
+			sd->sensor = SENSOR_CS2102;
+			break;
+		case 0x08:
+			PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)");
+			sd->sensor = SENSOR_HDCS2020b;
+			break;
+		case 0x0a:
+			PDEBUG(D_PROBE,
+				"Find Sensor PB0330. Chip revision %x",
+				sd->chip_revision);
+			sd->sensor = SENSOR_PB0330;
+			break;
+		case 0x0c:
+			PDEBUG(D_PROBE, "Find Sensor ICM105A");
+			sd->sensor = SENSOR_ICM105A;
+			break;
+		case 0x0e:
+			PDEBUG(D_PROBE, "Find Sensor HDCS2020");
+			sd->sensor = SENSOR_HDCS2020;
+			sd->sharpness = 1;
+			break;
+		case 0x0f:
+			PDEBUG(D_PROBE, "Find Sensor PAS106");
+			sd->sensor = SENSOR_PAS106;
+			vga = 0;		/* SIF */
+			break;
+		case 0x10:
+		case 0x12:
+			PDEBUG(D_PROBE, "Find Sensor TAS5130");
+			sd->sensor = SENSOR_TAS5130CXX;
+			break;
+		case 0x11:
+			PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
+			sd->sensor = SENSOR_HV7131C;
+			break;
+		case 0x13:
+			PDEBUG(D_PROBE,
+				"Find Sensor MI0360. Chip revision %x",
+				sd->chip_revision);
+			sd->sensor = SENSOR_PB0330;
+			break;
+		case 0x14:
+			PDEBUG(D_PROBE,
+				"Find Sensor CS2102K?. Chip revision %x",
+				sd->chip_revision);
+			sd->sensor = SENSOR_CS2102K;
+			break;
+		case 0x15:
+			PDEBUG(D_PROBE,
+				"Find Sensor TAS5130CK?. Chip revision %x",
+				sd->chip_revision);
+			sd->sensor = SENSOR_TAS5130CK;
+			break;
+		case 0x29:
+			PDEBUG(D_PROBE, "Find Sensor GC0305");
+			sd->sensor = SENSOR_GC0305;
+			break;
+		case 0x2030:
+			PDEBUG(D_PROBE, "Find Sensor PO2030");
+			sd->sensor = SENSOR_PO2030;
+			sd->sharpness = 0;		/* from win traces */
+			break;
+		case 0x7620:
+			PDEBUG(D_PROBE, "Find Sensor OV7620");
+			sd->sensor = SENSOR_OV7620;
+			break;
+		case 0x7648:
+			PDEBUG(D_PROBE, "Find Sensor OV7648");
+			sd->sensor = SENSOR_OV7620;	/* same sensor (?) */
+			break;
+		default:
+			PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor);
+			return -EINVAL;
+		}
+	}
+	if (sensor < 0x20) {
+		if (sensor == -1 || sensor == 0x10 || sensor == 0x12)
+			reg_w(gspca_dev->dev, 0x02, 0x0010);
+		else
+			reg_w(gspca_dev->dev, sensor & 0x0f, 0x0010);
+		reg_r(gspca_dev, 0x0010);
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+/*fixme:test*/
+	gspca_dev->nbalt--;
+	if (vga) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = ARRAY_SIZE(vga_mode);
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = ARRAY_SIZE(sif_mode);
+	}
+	sd->qindex = 1;
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->gamma = gamma[(int) sd->sensor];
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+
+	/* switch the led off */
+	reg_w(gspca_dev->dev, 0x01, 0x0000);
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev->dev, 0x01, 0x0000);
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	const struct usb_action *zc3_init;
+	int mode;
+	static const struct usb_action *init_tb[SENSOR_MAX][2] = {
+		{cs2102_InitialScale, cs2102_Initial},		/* 0 */
+		{cs2102K_InitialScale, cs2102K_Initial},	/* 1 */
+		{gc0305_Initial, gc0305_InitialScale},		/* 2 */
+		{hdcs2020xx_InitialScale, hdcs2020xx_Initial},	/* 3 */
+		{hdcs2020xb_InitialScale, hdcs2020xb_Initial},	/* 4 */
+		{hv7131bxx_InitialScale, hv7131bxx_Initial},	/* 5 */
+		{hv7131cxx_InitialScale, hv7131cxx_Initial},	/* 6 */
+		{icm105axx_InitialScale, icm105axx_Initial},	/* 7 */
+		{MC501CB_InitialScale, MC501CB_Initial},	/* 9 */
+		{OV7620_mode0, OV7620_mode1},			/* 9 */
+		{ov7630c_InitialScale, ov7630c_Initial},	/* 10 */
+		{pas106b_InitialScale, pas106b_Initial},	/* 11 */
+		{pb0330xx_InitialScale, pb0330xx_Initial},	/* 12 */
+/* or		{pb03303x_InitialScale, pb03303x_Initial}, */
+		{PO2030_mode0, PO2030_mode1},			/* 13 */
+		{tas5130CK_InitialScale, tas5130CK_Initial},	/* 14 */
+		{tas5130cxx_InitialScale, tas5130cxx_Initial},	/* 15 */
+		{tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
+								/* 16 */
+	};
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	zc3_init = init_tb[(int) sd->sensor][mode];
+	switch (sd->sensor) {
+	case SENSOR_HV7131B:
+	case SENSOR_HV7131C:
+		zcxx_probeSensor(gspca_dev);
+		break;
+	case SENSOR_PAS106:
+		usb_exchange(gspca_dev, pas106b_Initial_com);
+		break;
+	case SENSOR_PB0330:
+		if (mode) {
+			if (sd->chip_revision == 0xc001
+			    || sd->chip_revision == 0xe001
+			    || sd->chip_revision == 0x8001)
+				zc3_init = pb03303x_Initial;
+		} else {
+			if (sd->chip_revision == 0xc001
+			    || sd->chip_revision == 0xe001
+			    || sd->chip_revision == 0x8001)
+				zc3_init = pb03303x_InitialScale;
+		}
+		break;
+	}
+	usb_exchange(gspca_dev, zc3_init);
+
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PO2030:
+		msleep(100);			/* ?? */
+		reg_r(gspca_dev, 0x0002);	/* --> 0x40 */
+		reg_w(dev, 0x09, 0x01ad);	/* (from win traces) */
+		reg_w(dev, 0x15, 0x01ae);
+		reg_w(dev, 0x0d, 0x003a);
+		reg_w(dev, 0x02, 0x003b);
+		reg_w(dev, 0x00, 0x0038);
+		break;
+	}
+
+	setmatrix(gspca_dev);
+	setbrightness(gspca_dev);
+	switch (sd->sensor) {
+	case SENSOR_OV7620:
+		reg_r(gspca_dev, 0x0008);
+		reg_w(dev, 0x00, 0x0008);
+		break;
+	case SENSOR_GC0305:
+		reg_r(gspca_dev, 0x0008);
+		/* fall thru */
+	case SENSOR_PO2030:
+		reg_w(dev, 0x03, 0x0008);
+		break;
+	}
+	setsharpness(gspca_dev);
+
+	/* set the gamma tables when not set */
+	switch (sd->sensor) {
+	case SENSOR_CS2102:		/* gamma set in xxx_Initial */
+	case SENSOR_CS2102K:
+	case SENSOR_HDCS2020:
+	case SENSOR_HDCS2020b:
+	case SENSOR_PB0330:		/* pb with chip_revision - see above */
+	case SENSOR_OV7630C:
+	case SENSOR_TAS5130CK:
+		break;
+	default:
+		setcontrast(gspca_dev);
+		break;
+	}
+	setmatrix(gspca_dev);			/* one more time? */
+	switch (sd->sensor) {
+	case SENSOR_OV7620:
+		reg_r(gspca_dev, 0x0180);	/* from win */
+		reg_w(dev, 0x00, 0x0180);
+		break;
+	default:
+		setquality(gspca_dev);
+		break;
+	}
+	setlightfreq(gspca_dev);
+
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+		reg_w(dev, 0x09, 0x01ad);	/* (from win traces) */
+		reg_w(dev, 0x15, 0x01ae);
+		sd->autogain = 0;
+		break;
+	case SENSOR_PO2030:
+		reg_w(dev, 0x40, 0x0117);	/* (from win traces) */
+		reg_r(gspca_dev, 0x0180);
+		break;
+	}
+
+	setautogain(gspca_dev);
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+/*		setlightfreq(gspca_dev);	?? (end: 80 -> [18d]) */
+		reg_w(dev, 0x09, 0x01ad);	/* (from win traces) */
+		reg_w(dev, 0x15, 0x01ae);
+		reg_w(dev, 0x40, 0x0180);
+		reg_w(dev, 0x40, 0x0117);
+		reg_r(gspca_dev, 0x0180);
+		sd->autogain = 1;
+		setautogain(gspca_dev);
+		break;
+	case SENSOR_OV7620:
+		i2c_read(gspca_dev, 0x13);	/*fixme: returns 0xa3 */
+		i2c_write(gspca_dev, 0x13, 0xa3, 0x00);
+					 /*fixme: returned value to send? */
+		reg_w(dev, 0x40, 0x0117);	/* (from win traces) */
+		reg_r(gspca_dev, 0x0180);
+		setautogain(gspca_dev);
+		msleep(500);
+		break;
+	case SENSOR_PO2030:
+		msleep(500);
+		reg_r(gspca_dev, 0x0008);
+		reg_r(gspca_dev, 0x0007);
+		reg_w(dev, 0x00, 0x0007);	/* (from win traces) */
+		reg_w(dev, 0x02, 0x0008);
+		break;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	send_unknown(gspca_dev->dev, sd->sensor);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,
+			__u8 *data,
+			int len)
+{
+
+	if (data[0] == 0xff && data[1] == 0xd8) {	/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame,
+				((struct sd *) gspca_dev)->qindex,
+				0x21);
+		/* remove the webcam's header:
+		 * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
+		 *	- 'ss ss' is the frame sequence number (BE)
+		 * 	- 'ww ww' and 'hh hh' are the window dimensions (BE)
+		 *	- 'pp pp' is the packet sequence number (BE)
+		 */
+		data += 18;
+		len -= 18;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gamma = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gamma;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->sharpness = val;
+	if (gspca_dev->streaming)
+		setsharpness(gspca_dev);
+	return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->sharpness;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy((char *) menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy((char *) menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy((char *) menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")},
+	{USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")},
+	{USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")},
+	{USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")},
+#endif
+	{USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")},
+	{USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")},
+	{USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")},
+	{USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")},
+#endif
+	{USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")},
+	{USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")},
+	{USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")},
+	{USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")},
+#endif
+	{USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")},
+	{USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")},
+	{USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")},
+	{USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")},
+	{USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")},
+	{USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")},
+	{USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")},
+	{USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")},
+	{USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")},
+	{USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")},
+	{USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")},
+#endif
+	{USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")},
+	{USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")},
+	{USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")},
+	{USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")},
+	{USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")},
+	{USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")},
+	{USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")},
+	{USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")},
+	{USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")},
+	{USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")},
+	{USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")},
+	{USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")},
+	{USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")},
+#endif
+	{USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")},
+	{USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")},
+	{USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")},
+#endif
+	{USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")},
+#ifndef CONFIG_USB_ZC0301
+	{USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")},
+	{USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")},
+	{USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")},
+#endif
+	{}			/* end of entry */
+};
+#undef DVNAME
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+/* USB driver */
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(force_sensor, int, 0644);
+MODULE_PARM_DESC(force_sensor,
+	"Force sensor. Only for experts!!!");
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 7b65f5e..a30254b 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -194,88 +194,6 @@
 	return 1;
 }
 
-/* Common (grey or coloured) pinnacle PCTV remote handling
- *
- */
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
-			    int parity_offset, int marker, int code_modulo)
-{
-	unsigned char b[4];
-	unsigned int start = 0,parity = 0,code = 0;
-
-	/* poll IR chip */
-	if (4 != i2c_master_recv(&ir->c,b,4)) {
-		dprintk(2,"read error\n");
-		return -EIO;
-	}
-
-	for (start = 0; start < ARRAY_SIZE(b); start++) {
-		if (b[start] == marker) {
-			code=b[(start+parity_offset+1)%4];
-			parity=b[(start+parity_offset)%4];
-		}
-	}
-
-	/* Empty Request */
-	if (parity==0)
-		return 0;
-
-	/* Repeating... */
-	if (ir->old == parity)
-		return 0;
-
-	ir->old = parity;
-
-	/* drop special codes when a key is held down a long time for the grey controller
-	   In this case, the second bit of the code is asserted */
-	if (marker == 0xfe && (code & 0x40))
-		return 0;
-
-	code %= code_modulo;
-
-	*ir_raw = code;
-	*ir_key = code;
-
-	dprintk(1,"Pinnacle PCTV key %02x\n", code);
-
-	return 1;
-}
-
-/* The grey pinnacle PCTV remote
- *
- *  There are one issue with this remote:
- *   - I2c packet does not change when the same key is pressed quickly. The workaround
- *     is to hold down each key for about half a second, so that another code is generated
- *     in the i2c packet, and the function can distinguish key presses.
- *
- * Sylvain Pasche <sylvain.pasche@gmail.com>
- */
-int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-
-	return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
-}
-
-EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
-
-
-/* The new pinnacle PCTV remote (with the colored buttons)
- *
- * Ricardo Cerqueira <v4l@cerqueira.org>
- */
-int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-	/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
-	 *
-	 * this is the only value that results in 42 unique
-	 * codes < 128
-	 */
-
-	return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
-}
-
-EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
-
 /* ----------------------------------------------------------------------- */
 
 static void ir_key_poll(struct IR_i2c *ir)
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 4fb8fae..4e05f91 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,7 +40,7 @@
 #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
 				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
 
-#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM)
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
 
 /* usual i2c tuner addresses to probe */
 static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
@@ -300,7 +300,7 @@
 	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
 	.tuners = {
 		/* The PAL tuner is confirmed */
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg600,
@@ -341,7 +341,7 @@
 			      .lang1 = 0x0004, .lang2  = 0x0000, .both   = 0x0008 },
 	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg160,
@@ -377,7 +377,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_pg600,
@@ -418,7 +418,7 @@
 	   on the country/region setting of the user to decide which tuner
 	   is available. */
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
 			.tuner = TUNER_PHILIPS_FM1236_MK3 },
 		{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
@@ -492,7 +492,7 @@
 	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
 			  .composite = 0x0010, .svideo = 0x0020 },
 	.tuners = {
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_tg5000tv,
 	.i2c = &ivtv_i2c_std,
@@ -523,7 +523,7 @@
 		{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
 	},
 	.tuners = {
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_va2000,
 	.i2c = &ivtv_i2c_std,
@@ -567,7 +567,7 @@
 	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
 			     .f44100 = 0x4000, .f48000 = 0x8000 },
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_cx23416gyc,
@@ -599,7 +599,7 @@
 	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
 			     .f44100 = 0x4000, .f48000 = 0x8000 },
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.i2c = &ivtv_i2c_std,
@@ -629,7 +629,7 @@
 	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
 			     .f44100 = 0x4000, .f48000 = 0x8000 },
 	.tuners = {
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.i2c = &ivtv_i2c_std,
@@ -669,7 +669,7 @@
 	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
 	.tuners = {
 		/* This card has the Panasonic VP27 tuner */
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx,
 	.i2c = &ivtv_i2c_std,
@@ -706,7 +706,7 @@
 	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
 	.tuners = {
 		/* This card has the Panasonic VP27 tuner */
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx2e,
 	.i2c = &ivtv_i2c_std,
@@ -741,7 +741,7 @@
 	.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
 	.tuners = {
 		/* This card has a Philips FQ1216ME MK3 tuner */
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd,
 	.i2c = &ivtv_i2c_std,
@@ -780,7 +780,7 @@
 	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
 	.tuners = {
 		/* This card has a Philips FQ1216ME MK5 tuner */
-		{ .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd2,
 	.i2c = &ivtv_i2c_std,
@@ -858,7 +858,7 @@
 	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
 			       .composite = 0x0010, .svideo = 0x0020},
 	.tuners = {
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_dctmvtvp1,
 	.i2c = &ivtv_i2c_std,
@@ -923,7 +923,6 @@
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
-	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
 	.xceive_pin = 12,
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -959,7 +958,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
 	},
 	/* enable line-in */
-	.gpio_init = { .direction = 0xe400, .initial_value = 0x4400 },
+	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
 	.xceive_pin = 10,
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -1001,7 +1000,7 @@
 	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
 	.tuners = {
 		/* This card has a Partsnic PTI-5NF05 tuner */
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
 	},
 	.pci_list = ivtv_pci_aver_pvr150,
 	.i2c = &ivtv_i2c_radio,
@@ -1069,7 +1068,7 @@
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
 	.tuners = {
-		{ .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_asus_falcon2,
 	.i2c = &ivtv_i2c_std,
@@ -1102,7 +1101,7 @@
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
 	/* enable line-in + reset tuner */
-	.gpio_init = { .direction = 0xe400, .initial_value = 0x4000 },
+	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
 	.xceive_pin = 10,
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -1111,6 +1110,41 @@
 	.i2c = &ivtv_i2c_std,
 };
 
+/* ------------------------------------------------------------------------- */
+
+/* Buffalo PC-MV5L/PCI cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_buffalo = {
+	.type = IVTV_CARD_BUFFALO_MV5L,
+	.name = "Buffalo PC-MV5L/PCI",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+			CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.xceive_pin = 12,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.pci_list = ivtv_pci_buffalo,
+	.i2c = &ivtv_i2c_std,
+};
+
 static const struct ivtv_card *ivtv_card_list[] = {
 	&ivtv_card_pvr250,
 	&ivtv_card_pvr350,
@@ -1137,6 +1171,7 @@
 	&ivtv_card_aver_pvr150,
 	&ivtv_card_aver_ezmaker,
 	&ivtv_card_aver_m104,
+	&ivtv_card_buffalo,
 
 	/* Variations of standard cards but with the same PCI IDs.
 	   These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 748485d..381af1b 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -49,7 +49,8 @@
 #define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
 #define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
 #define IVTV_CARD_AVER_M104          24 /* AverMedia M104 miniPCI card */
-#define IVTV_CARD_LAST 		     24
+#define IVTV_CARD_BUFFALO_MV5L       25 /* Buffalo PC-MV5L/PCI card */
+#define IVTV_CARD_LAST 		     25
 
 /* Variants of existing cards but with the same PCI IDs. The driver
    detects these based on other device information.
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index c7e449f..48e103b 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -47,11 +47,11 @@
 	NULL
 };
 
-static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
-{
-	const char *name;
 
-	IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
+int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	const char *name;
 
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	if (qctrl->id == 0)
@@ -87,21 +87,35 @@
 	return 0;
 }
 
-static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu)
+int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
 {
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 	struct v4l2_queryctrl qctrl;
 
 	qctrl.id = qmenu->id;
-	ivtv_queryctrl(itv, &qctrl);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+	ivtv_queryctrl(file, fh, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+			cx2341x_ctrl_get_menu(&itv->params, qmenu->id));
+}
+
+static int ivtv_try_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_control *vctrl)
+{
+	struct v4l2_queryctrl qctrl;
+	const char **menu_items = NULL;
+	int err;
+
+	qctrl.id = vctrl->id;
+	err = ivtv_queryctrl(file, fh, &qctrl);
+	if (err)
+		return err;
+	if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+		menu_items = v4l2_ctrl_get_menu(qctrl.id);
+	return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
 }
 
 static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 {
-	s32 v = vctrl->value;
-
-	IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
-
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
@@ -119,7 +133,7 @@
 		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
 
 	default:
-		IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -127,8 +141,6 @@
 
 static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 {
-	IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
 	switch (vctrl->id) {
 		/* Standard V4L2 controls */
 	case V4L2_CID_BRIGHTNESS:
@@ -145,7 +157,7 @@
 	case V4L2_CID_AUDIO_LOUDNESS:
 		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
 	default:
-		IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -191,119 +203,106 @@
 	return 0;
 }
 
-int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
+int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 {
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 	struct v4l2_control ctrl;
 
-	switch (cmd) {
-	case VIDIOC_QUERYMENU:
-		IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
-		return ivtv_querymenu(itv, arg);
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
 
-	case VIDIOC_QUERYCTRL:
-		return ivtv_queryctrl(itv, arg);
-
-	case VIDIOC_S_CTRL:
-		return ivtv_s_ctrl(itv, arg);
-
-	case VIDIOC_G_CTRL:
-		return ivtv_g_ctrl(itv, arg);
-
-	case VIDIOC_S_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
-
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = ivtv_s_ctrl(itv, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = ivtv_g_ctrl(itv, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
-			return err;
 		}
-		IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-			static u32 freqs[3] = { 44100, 48000, 32000 };
-			struct cx2341x_mpeg_params p = itv->params;
-			int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
-			unsigned idx;
+		return err;
+	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS);
+	return -EINVAL;
+}
 
-			if (err)
-				return err;
+int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_control ctrl;
 
-			if (p.video_encoding != itv->params.video_encoding) {
-				int is_mpeg1 = p.video_encoding ==
-						V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
-				struct v4l2_format fmt;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
 
-				/* fix videodecoder resolution */
-				fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-				fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
-				fmt.fmt.pix.height = itv->params.height;
-				itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
+		for (i = 0; i < c->count; i++) {
+			ctrl.id = c->controls[i].id;
+			ctrl.value = c->controls[i].value;
+			err = ivtv_s_ctrl(itv, &ctrl);
+			c->controls[i].value = ctrl.value;
+			if (err) {
+				c->error_idx = i;
+				break;
 			}
-			err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
-			if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) {
-				err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
-			}
-			itv->params = p;
-			itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-			idx = p.audio_properties & 0x03;
-			/* The audio clock of the digitizer must match the codec sample
-			   rate otherwise you get some very strange effects. */
-			if (idx < sizeof(freqs))
-			    ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
-			return err;
 		}
-		return -EINVAL;
+		return err;
 	}
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+		static u32 freqs[3] = { 44100, 48000, 32000 };
+		struct cx2341x_mpeg_params p = itv->params;
+		int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS);
+		unsigned idx;
 
-	case VIDIOC_G_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
-
-		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-			int i;
-			int err = 0;
-
-			for (i = 0; i < c->count; i++) {
-				ctrl.id = c->controls[i].id;
-				ctrl.value = c->controls[i].value;
-				err = ivtv_g_ctrl(itv, &ctrl);
-				c->controls[i].value = ctrl.value;
-				if (err) {
-					c->error_idx = i;
-					break;
-				}
-			}
+		if (err)
 			return err;
+
+		if (p.video_encoding != itv->params.video_encoding) {
+			int is_mpeg1 = p.video_encoding ==
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+			struct v4l2_format fmt;
+
+			/* fix videodecoder resolution */
+			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
+			fmt.fmt.pix.height = itv->params.height;
+			itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
 		}
-		IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
-		return -EINVAL;
+		err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
+		if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
+			err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
+		itv->params = p;
+		itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+		idx = p.audio_properties & 0x03;
+		/* The audio clock of the digitizer must match the codec sample
+		   rate otherwise you get some very strange effects. */
+		if (idx < sizeof(freqs))
+			ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
+		return err;
 	}
+	return -EINVAL;
+}
 
-	case VIDIOC_TRY_EXT_CTRLS:
-	{
-		struct v4l2_ext_controls *c = arg;
+int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-		IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
-		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
-		return -EINVAL;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+		int i;
+		int err = 0;
+
+		for (i = 0; i < c->count; i++) {
+			err = ivtv_try_ctrl(file, fh, &c->controls[i]);
+			if (err) {
+				c->error_idx = i;
+				break;
+			}
+		}
+		return err;
 	}
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
+	if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+		return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS);
+	return -EINVAL;
 }
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index bb8a6a5..1c7721e 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -21,6 +21,10 @@
 #ifndef IVTV_CONTROLS_H
 #define IVTV_CONTROLS_H
 
-int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 797e636..41fd792 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -191,6 +191,7 @@
 		 "\t\t\t23 = AverMedia PVR-150 Plus\n"
 		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
 		 "\t\t\t25 = AverMedia M104 (not yet working)\n"
+		 "\t\t\t26 = Buffalo PC-MV5L/PCI\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -1019,7 +1020,7 @@
 	ivtv_cards[ivtv_cards_active] = itv;
 	itv->dev = dev;
 	itv->num = ivtv_cards_active++;
-	snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
+	snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num);
 	IVTV_INFO("Initializing card #%d\n", itv->num);
 
 	spin_unlock(&ivtv_cards_lock);
@@ -1127,6 +1128,12 @@
 	/* if no tuner was found, then pick the first tuner in the card list */
 	if (itv->options.tuner == -1 && itv->card->tuners[0].std) {
 		itv->std = itv->card->tuners[0].std;
+		if (itv->std & V4L2_STD_PAL)
+			itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+		else if (itv->std & V4L2_STD_NTSC)
+			itv->std = V4L2_STD_NTSC_M;
+		else if (itv->std & V4L2_STD_SECAM)
+			itv->std = V4L2_STD_SECAM_L;
 		itv->options.tuner = itv->card->tuners[0].tuner;
 	}
 	if (itv->options.radio == -1)
@@ -1261,9 +1268,13 @@
 int ivtv_init_on_first_open(struct ivtv *itv)
 {
 	struct v4l2_frequency vf;
+	/* Needed to call ioctls later */
+	struct ivtv_open_id fh;
 	int fw_retry_count = 3;
 	int video_input;
 
+	fh.itv = itv;
+
 	if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
 		return -ENXIO;
 
@@ -1311,18 +1322,18 @@
 
 	video_input = itv->active_input;
 	itv->active_input++;	/* Force update of input */
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+	ivtv_s_input(NULL, &fh, video_input);
 
 	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
 	   in one place. */
 	itv->std++;		/* Force full standard initialization */
 	itv->std_out = itv->std;
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+	ivtv_s_frequency(NULL, &fh, &vf);
 
 	if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
 		ivtv_init_mpeg_decoder(itv);
 	}
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+	ivtv_s_std(NULL, &fh, &itv->tuner_std);
 
 	/* On a cx23416 this seems to be able to enable DMA to the chip? */
 	if (!itv->has_cx23415)
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 9d23b1e..a08bb33 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -635,7 +635,6 @@
 	spinlock_t lock;                /* lock access to this struct */
 	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
 
-
 	/* Streams */
 	int stream_buf_size[IVTV_MAX_STREAMS];          /* stream buffer size */
 	struct ivtv_stream streams[IVTV_MAX_STREAMS]; 	/* stream data */
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index db813e0..7ec5c99 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -582,6 +582,19 @@
 	ivtv_queue_init(&q);
 	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 
+	/* Start decoder (returns 0 if already started) */
+	mutex_lock(&itv->serialize_lock);
+	rc = ivtv_start_decoding(id, itv->speed);
+	mutex_unlock(&itv->serialize_lock);
+	if (rc) {
+		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
+
+		/* failure, clean up */
+		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return rc;
+	}
+
 retry:
 	/* If possible, just DMA the entire frame - Check the data transfer size
 	since we may get here before the stream has been fully set-up */
@@ -664,18 +677,6 @@
 		ivtv_enqueue(s, buf, &s->q_full);
 	}
 
-	/* Start decoder (returns 0 if already started) */
-	mutex_lock(&itv->serialize_lock);
-	rc = ivtv_start_decoding(id, itv->speed);
-	mutex_unlock(&itv->serialize_lock);
-	if (rc) {
-		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
-
-		/* failure, clean up */
-		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
-		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
-		return rc;
-	}
 	if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
 		if (s->q_full.length >= itv->dma_data_req_size) {
 			int got_sig;
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index d8ac09f..bc22905 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -146,15 +146,20 @@
 
 void ivtv_gpio_init(struct ivtv *itv)
 {
-	if (itv->card->gpio_init.direction == 0)
+	u16 pin = 0;
+
+	if (itv->card->xceive_pin)
+		pin = 1 << itv->card->xceive_pin;
+
+	if ((itv->card->gpio_init.direction | pin) == 0)
 		return;
 
 	IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
 		   read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
 
 	/* init output data then direction */
-	write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT);
-	write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR);
+	write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+	write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
 }
 
 static struct v4l2_queryctrl gpio_ctrl_mute = {
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 32129f3..af15423 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -75,10 +75,6 @@
 #define IVTV_REG_I2C_GETSCL_OFFSET 0x7008
 #define IVTV_REG_I2C_GETSDA_OFFSET 0x700c
 
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif /* I2C_ADAP_CLASS_TV_ANALOG */
-
 #define IVTV_CS53L32A_I2C_ADDR		0x11
 #define IVTV_M52790_I2C_ADDR		0x48
 #define IVTV_CX25840_I2C_ADDR 		0x44
@@ -139,7 +135,7 @@
 static const char * const hw_devicenames[] = {
 	"cx25840",
 	"saa7115",
-	"saa7127",
+	"saa7127_auto",	/* saa7127 or saa7129 */
 	"msp3400",
 	"tuner",
 	"wm8775",
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 26cc0f6..52e00a7 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -128,37 +128,6 @@
 	return set;
 }
 
-static const struct {
-	v4l2_std_id  std;
-	char        *name;
-} enum_stds[] = {
-	{ V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
-	{ V4L2_STD_PAL_DK,    "PAL-DK"    },
-	{ V4L2_STD_PAL_I,     "PAL-I"     },
-	{ V4L2_STD_PAL_M,     "PAL-M"     },
-	{ V4L2_STD_PAL_N,     "PAL-N"     },
-	{ V4L2_STD_PAL_Nc,    "PAL-Nc"    },
-	{ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
-	{ V4L2_STD_SECAM_DK,  "SECAM-DK"  },
-	{ V4L2_STD_SECAM_L,   "SECAM-L"   },
-	{ V4L2_STD_SECAM_LC,  "SECAM-L'"  },
-	{ V4L2_STD_NTSC_M,    "NTSC-M"    },
-	{ V4L2_STD_NTSC_M_JP, "NTSC-J"    },
-	{ V4L2_STD_NTSC_M_KR, "NTSC-K"    },
-};
-
-static const struct v4l2_standard ivtv_std_60hz =
-{
-	.frameperiod = {.numerator = 1001, .denominator = 30000},
-	.framelines = 525,
-};
-
-static const struct v4l2_standard ivtv_std_50hz =
-{
-	.frameperiod = {.numerator = 1, .denominator = 25},
-	.framelines = 625,
-};
-
 void ivtv_set_osd_alpha(struct ivtv *itv)
 {
 	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
@@ -345,6 +314,380 @@
 	return 0;
 }
 
+static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+		return -EINVAL;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	if (itv->is_60hz) {
+		vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+	} else {
+		vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+		vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
+	}
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	pixfmt->width = itv->params.width;
+	pixfmt->height = itv->params.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+		pixfmt->sizeimage =
+			pixfmt->height * pixfmt->width +
+			pixfmt->height * (pixfmt->width / 2);
+		pixfmt->bytesperline = 720;
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+	vbifmt->sampling_rate = 27000000;
+	vbifmt->offset = 248;
+	vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4;
+	vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+	vbifmt->start[0] = itv->vbi.start[0];
+	vbifmt->start[1] = itv->vbi.start[1];
+	vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count;
+	vbifmt->flags = 0;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	return 0;
+}
+
+static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+
+	if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
+			V4L2_SLICED_VBI_525;
+		ivtv_expand_service_set(vbifmt, itv->is_50hz);
+		return 0;
+	}
+
+	itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	pixfmt->width = itv->main_rect.width;
+	pixfmt->height = itv->main_rect.height;
+	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pixfmt->field = V4L2_FIELD_INTERLACED;
+	pixfmt->priv = 0;
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+		case IVTV_YUV_MODE_INTERLACED:
+			pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+				V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
+			break;
+		case IVTV_YUV_MODE_PROGRESSIVE:
+			pixfmt->field = V4L2_FIELD_NONE;
+			break;
+		default:
+			pixfmt->field = V4L2_FIELD_ANY;
+			break;
+		}
+		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+		pixfmt->bytesperline = 720;
+		pixfmt->width = itv->yuv_info.v4l2_src_w;
+		pixfmt->height = itv->yuv_info.v4l2_src_h;
+		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+		pixfmt->sizeimage =
+			1080 * ((pixfmt->height + 31) & ~31);
+	} else {
+		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+		pixfmt->sizeimage = 128 * 1024;
+		pixfmt->bytesperline = 0;
+	}
+	return 0;
+}
+
+static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_window *winfmt = &fmt->fmt.win;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	winfmt->chromakey = itv->osd_chroma_key;
+	winfmt->global_alpha = itv->osd_global_alpha;
+	winfmt->field = V4L2_FIELD_INTERLACED;
+	winfmt->clips = NULL;
+	winfmt->clipcount = 0;
+	winfmt->bitmap = NULL;
+	winfmt->w.top = winfmt->w.left = 0;
+	winfmt->w.width = itv->osd_rect.width;
+	winfmt->w.height = itv->osd_rect.height;
+	return 0;
+}
+
+static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+
+	w = min(w, 720);
+	w = max(w, 1);
+	h = min(h, itv->is_50hz ? 576 : 480);
+	h = max(h, 2);
+	ivtv_g_fmt_vid_cap(file, fh, fmt);
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	return 0;
+}
+
+static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+	if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
+		return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	/* set sliced VBI capture format */
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	vbifmt->reserved[0] = 0;
+	vbifmt->reserved[1] = 0;
+
+	if (vbifmt->service_set)
+		ivtv_expand_service_set(vbifmt, itv->is_50hz);
+	check_service_set(vbifmt, itv->is_50hz);
+	vbifmt->service_set = ivtv_get_service_set(vbifmt);
+	return 0;
+}
+
+static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	s32 w, h;
+	int field;
+	int ret;
+
+	w = fmt->fmt.pix.width;
+	h = fmt->fmt.pix.height;
+	field = fmt->fmt.pix.field;
+	ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+	fmt->fmt.pix.width = w;
+	fmt->fmt.pix.height = h;
+	if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		fmt->fmt.pix.field = field;
+		if (fmt->fmt.pix.width < 2)
+			fmt->fmt.pix.width = 2;
+		if (fmt->fmt.pix.width > 720)
+			fmt->fmt.pix.width = 720;
+		if (fmt->fmt.pix.height < 2)
+			fmt->fmt.pix.height = 2;
+		if (fmt->fmt.pix.height > 576)
+			fmt->fmt.pix.height = 576;
+	}
+	return ret;
+}
+
+static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	u32 chromakey = fmt->fmt.win.chromakey;
+	u8 global_alpha = fmt->fmt.win.global_alpha;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+	ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
+	fmt->fmt.win.chromakey = chromakey;
+	fmt->fmt.win.global_alpha = global_alpha;
+	return 0;
+}
+
+static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct cx2341x_mpeg_params *p = &itv->params;
+	int w = fmt->fmt.pix.width;
+	int h = fmt->fmt.pix.height;
+	int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+
+	if (p->width == w && p->height == h)
+		return 0;
+
+	if (atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+
+	p->width = w;
+	p->height = h;
+	if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+		fmt->fmt.pix.width /= 2;
+	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	return ivtv_g_fmt_vid_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	itv->vbi.sliced_in->service_set = 0;
+	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
+		return ret;
+
+	if (check_service_set(vbifmt, itv->is_50hz) == 0)
+		return -EINVAL;
+	if (atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+	return 0;
+}
+
+static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
+
+	if (ret)
+		return ret;
+
+	if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
+		return 0;
+
+	/* Return now if we already have some frame data */
+	if (yi->stream_size)
+		return -EBUSY;
+
+	yi->v4l2_src_w = fmt->fmt.pix.width;
+	yi->v4l2_src_h = fmt->fmt.pix.height;
+
+	switch (fmt->fmt.pix.field) {
+	case V4L2_FIELD_NONE:
+		yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+		break;
+	case V4L2_FIELD_ANY:
+		yi->lace_mode = IVTV_YUV_MODE_AUTO;
+		break;
+	case V4L2_FIELD_INTERLACED_BT:
+		yi->lace_mode =
+			IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+		break;
+	case V4L2_FIELD_INTERLACED_TB:
+	default:
+		yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+		break;
+	}
+	yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+		itv->dma_data_req_size =
+			1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+	/* Force update of yuv registers */
+	yi->yuv_forced_update = 1;
+	return 0;
+}
+
+static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
+
+	if (ret == 0) {
+		itv->osd_chroma_key = fmt->fmt.win.chromakey;
+		itv->osd_global_alpha = fmt->fmt.win.global_alpha;
+		ivtv_set_osd_alpha(itv);
+	}
+	return ret;
+}
+
+static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+			chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+		return 0;
+	}
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
+	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+		return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
+	return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 {
 	struct v4l2_register *regs = arg;
@@ -364,1054 +707,826 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&ivtv_cards_lock, flags);
-	if (cmd == VIDIOC_DBG_G_REGISTER) {
+	if (cmd == VIDIOC_DBG_G_REGISTER)
 		regs->val = readl(regs->reg + reg_start);
-	} else {
+	else
 		writel(regs->val, regs->reg + reg_start);
-	}
 	spin_unlock_irqrestore(&ivtv_cards_lock, flags);
 	return 0;
 }
 
-static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt)
+static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg)
 {
-	switch (fmt->type) {
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		fmt->fmt.pix.width = itv->main_rect.width;
-		fmt->fmt.pix.height = itv->main_rect.height;
-		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
-			case IVTV_YUV_MODE_INTERLACED:
-				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
-					V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
-				break;
-			case IVTV_YUV_MODE_PROGRESSIVE:
-				fmt->fmt.pix.field = V4L2_FIELD_NONE;
-				break;
-			default:
-				fmt->fmt.pix.field = V4L2_FIELD_ANY;
-				break;
-			}
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-			fmt->fmt.pix.bytesperline = 720;
-			fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
-			fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
-			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-			fmt->fmt.pix.sizeimage =
-				1080 * ((fmt->fmt.pix.height + 31) & ~31);
-		} else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-			fmt->fmt.pix.sizeimage =
-				fmt->fmt.pix.height * fmt->fmt.pix.width +
-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-		} else {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-			fmt->fmt.pix.sizeimage = 128 * 1024;
-		}
-		break;
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		fmt->fmt.pix.width = itv->params.width;
-		fmt->fmt.pix.height = itv->params.height;
-		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-		if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
-				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
-			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
-			fmt->fmt.pix.sizeimage =
-				fmt->fmt.pix.height * fmt->fmt.pix.width +
-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-		} else {
-			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
-			fmt->fmt.pix.sizeimage = 128 * 1024;
-		}
-		break;
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+	return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+}
 
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		fmt->fmt.win.chromakey = itv->osd_chroma_key;
-		fmt->fmt.win.global_alpha = itv->osd_global_alpha;
-		break;
+static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		fmt->fmt.vbi.sampling_rate = 27000000;
-		fmt->fmt.vbi.offset = 248;
-		fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
-		fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-		fmt->fmt.vbi.start[0] = itv->vbi.start[0];
-		fmt->fmt.vbi.start[1] = itv->vbi.start[1];
-		fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
-		break;
+	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
+	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+		return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+	return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+}
+#endif
 
-	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-	{
-		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-		if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
-			return -EINVAL;
-		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
-		if (itv->is_60hz) {
-			vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-			vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
-		} else {
-			vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
-			vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
-		}
-		vbifmt->service_set = ivtv_get_service_set(vbifmt);
-		break;
-	}
+	*p = v4l2_prio_max(&itv->prio);
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-	{
-		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-
-		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
-
-		if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
-			vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
-						 V4L2_SLICED_VBI_525;
-			ivtv_expand_service_set(vbifmt, itv->is_50hz);
-			break;
-		}
-
-		itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
-		vbifmt->service_set = ivtv_get_service_set(vbifmt);
-		break;
-	}
-	case V4L2_BUF_TYPE_VBI_OUTPUT:
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
 
-static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
-		struct v4l2_format *fmt, int set_fmt)
+static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
 {
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+	return v4l2_prio_change(&itv->prio, &id->prio, prio);
+}
+
+static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+	strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+	strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
+	vcap->version = IVTV_DRIVER_VERSION; 	    /* version */
+	vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
+	return 0;
+}
+
+static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	return ivtv_get_audio_input(itv, vin->index, vin);
+}
+
+static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	vin->index = itv->audio_input;
+	return ivtv_get_audio_input(itv, vin->index, vin);
+}
+
+static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	if (vout->index >= itv->nof_audio_inputs)
+		return -EINVAL;
+
+	itv->audio_input = vout->index;
+	ivtv_audio_set_io(itv);
+
+	return 0;
+}
+
+static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	/* set it to defaults from our table */
+	return ivtv_get_audio_output(itv, vin->index, vin);
+}
+
+static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	vin->index = 0;
+	return ivtv_get_audio_output(itv, vin->index, vin);
+}
+
+static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	return ivtv_get_audio_output(itv, vout->index, vout);
+}
+
+static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	/* set it to defaults from our table */
+	return ivtv_get_input(itv, vin->index, vin);
+}
+
+static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	return ivtv_get_output(itv, vout->index, vout);
+}
+
+static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
 	struct yuv_playback_info *yi = &itv->yuv_info;
-	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-	u16 set;
+	int streamtype;
 
-	if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-		struct v4l2_rect r;
-		int field;
+	streamtype = id->type;
 
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		field = fmt->fmt.pix.field;
-		r.top = 0;
-		r.left = 0;
-		r.width = fmt->fmt.pix.width;
-		r.height = fmt->fmt.pix.height;
-		ivtv_get_fmt(itv, streamtype, fmt);
-		fmt->fmt.pix.width = r.width;
-		fmt->fmt.pix.height = r.height;
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+	cropcap->bounds.top = cropcap->bounds.left = 0;
+	cropcap->bounds.width = 720;
+	if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		cropcap->bounds.height = itv->is_50hz ? 576 : 480;
+		cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+	} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+		if (yi->track_osd) {
+			cropcap->bounds.width = yi->osd_full_w;
+			cropcap->bounds.height = yi->osd_full_h;
+		} else {
+			cropcap->bounds.width = 720;
+			cropcap->bounds.height =
+					itv->is_out_50hz ? 576 : 480;
+		}
+		cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+	} else {
+		cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
+		cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+		cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+	}
+	cropcap->defrect = cropcap->bounds;
+	return 0;
+}
+
+static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int streamtype;
+
+	streamtype = id->type;
+
+	if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
+		printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
+		/* Should be replaced */
+		/* v4l_printk_ioctl(VIDIOC_S_CROP); */
+	}
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
 		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			fmt->fmt.pix.field = field;
-			if (fmt->fmt.pix.width < 2)
-				fmt->fmt.pix.width = 2;
-			if (fmt->fmt.pix.width > 720)
-				fmt->fmt.pix.width = 720;
-			if (fmt->fmt.pix.height < 2)
-				fmt->fmt.pix.height = 2;
-			if (fmt->fmt.pix.height > 576)
-				fmt->fmt.pix.height = 576;
-		}
-		if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			/* Return now if we already have some frame data */
-			if (yi->stream_size)
-				return -EBUSY;
-
-			yi->v4l2_src_w = r.width;
-			yi->v4l2_src_h = r.height;
-
-			switch (field) {
-			case V4L2_FIELD_NONE:
-				yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
-				break;
-			case V4L2_FIELD_ANY:
-				yi->lace_mode = IVTV_YUV_MODE_AUTO;
-				break;
-			case V4L2_FIELD_INTERLACED_BT:
-				yi->lace_mode =
-				     IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
-				break;
-			case V4L2_FIELD_INTERLACED_TB:
-			default:
-				yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
-				break;
+			yi->main_rect = crop->c;
+			return 0;
+		} else {
+			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+				crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+				itv->main_rect = crop->c;
+				return 0;
 			}
-			yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
-
-			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
-				itv->dma_data_req_size =
-					   1080 * ((yi->v4l2_src_h + 31) & ~31);
-
-			/* Force update of yuv registers */
-			yi->yuv_forced_update = 1;
-			return 0;
 		}
-		return 0;
+		return -EINVAL;
 	}
+	return -EINVAL;
+}
 
-	if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		if (set_fmt) {
-			itv->osd_chroma_key = fmt->fmt.win.chromakey;
-			itv->osd_global_alpha = fmt->fmt.win.global_alpha;
-			ivtv_set_osd_alpha(itv);
-		}
-		return 0;
-	}
+static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	int streamtype;
 
-	/* set window size */
-	if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		struct cx2341x_mpeg_params *p = &itv->params;
-		int w = fmt->fmt.pix.width;
-		int h = fmt->fmt.pix.height;
+	streamtype = id->type;
 
-		if (w > 720) w = 720;
-		else if (w < 1) w = 1;
-		if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480);
-		else if (h < 2) h = 2;
-		ivtv_get_fmt(itv, streamtype, fmt);
-		fmt->fmt.pix.width = w;
-		fmt->fmt.pix.height = h;
-
-		if (!set_fmt || (p->width == w && p->height == h))
-			return 0;
-		if (atomic_read(&itv->capturing) > 0)
-			return -EBUSY;
-
-		p->width = w;
-		p->height = h;
-		if (w != 720 || h != (itv->is_50hz ? 576 : 480))
-			p->video_temporal_filter = 0;
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+			crop->c = yi->main_rect;
 		else
-			p->video_temporal_filter = 8;
-		if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
-			fmt->fmt.pix.width /= 2;
-		itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
-		return ivtv_get_fmt(itv, streamtype, fmt);
-	}
-
-	/* set raw VBI format */
-	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (set_fmt && atomic_read(&itv->capturing) > 0) {
-			return -EBUSY;
-		}
-		if (set_fmt) {
-			itv->vbi.sliced_in->service_set = 0;
-			itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
-		}
-		return ivtv_get_fmt(itv, streamtype, fmt);
-	}
-
-	/* set sliced VBI output
-	   In principle the user could request that only certain
-	   VBI types are output and that the others are ignored.
-	   I.e., suppress CC in the even fields or only output
-	   WSS and no VPS. Currently though there is no choice. */
-	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
-		return ivtv_get_fmt(itv, streamtype, fmt);
-
-	/* any else but sliced VBI capture is an error */
-	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-		return -EINVAL;
-
-	if (streamtype == IVTV_DEC_STREAM_TYPE_VBI)
-		return ivtv_get_fmt(itv, streamtype, fmt);
-
-	/* set sliced VBI capture format */
-	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
-	memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
-
-	if (vbifmt->service_set)
-		ivtv_expand_service_set(vbifmt, itv->is_50hz);
-	set = check_service_set(vbifmt, itv->is_50hz);
-	vbifmt->service_set = ivtv_get_service_set(vbifmt);
-
-	if (!set_fmt)
+			crop->c = itv->main_rect;
 		return 0;
-	if (set == 0)
+	}
+	return -EINVAL;
+}
+
+static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG,
+		  { 0, 0, 0, 0 }
+		}
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 1)
 		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
+}
+
+static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+		  { 0, 0, 0, 0 }
+		},
+		{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+		  "MPEG", V4L2_PIX_FMT_MPEG,
+		  { 0, 0, 0, 0 }
+		}
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	if (fmt->index > 1)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+
+	return 0;
+}
+
+static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	*i = itv->active_input;
+
+	return 0;
+}
+
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	if (inp < 0 || inp >= itv->nof_inputs)
+		return -EINVAL;
+
+	if (inp == itv->active_input) {
+		IVTV_DEBUG_INFO("Input unchanged\n");
+		return 0;
+	}
+
 	if (atomic_read(&itv->capturing) > 0) {
 		return -EBUSY;
 	}
-	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
-	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+
+	IVTV_DEBUG_INFO("Changing input from %d to %d\n",
+			itv->active_input, inp);
+
+	itv->active_input = inp;
+	/* Set the audio input to whatever is appropriate for the
+	   input type. */
+	itv->audio_input = itv->card->video_inputs[inp].audio_index;
+
+	/* prevent others from messing with the streams until
+	   we're finished changing inputs. */
+	ivtv_mute(itv);
+	ivtv_video_set_io(itv);
+	ivtv_audio_set_io(itv);
+	ivtv_unmute(itv);
+
 	return 0;
 }
 
-static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
 {
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
-	struct ivtv *itv = id->itv;
-	struct v4l2_register *reg = arg;
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-	switch (cmd) {
-	/* ioctls to allow direct access to the encoder registers for testing */
-	case VIDIOC_DBG_G_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return ivtv_itvc(itv, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-		return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
-	case VIDIOC_DBG_S_REGISTER:
-		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return ivtv_itvc(itv, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-		return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
-	case VIDIOC_G_CHIP_IDENT: {
-		struct v4l2_chip_ident *chip = arg;
-
-		chip->ident = V4L2_IDENT_NONE;
-		chip->revision = 0;
-		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-			if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
-				chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
-			return 0;
-		}
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
-		if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-			return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 		return -EINVAL;
-	}
 
-	case VIDIOC_INT_S_AUDIO_ROUTING: {
-		struct v4l2_routing *route = arg;
+	*i = itv->active_output;
 
-		ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
-		break;
-	}
-
-	case VIDIOC_INT_RESET: {
-		u32 val = *(u32 *)arg;
-
-		if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
-			ivtv_reset_ir_gpio(itv);
-		}
-		if (val & 0x02) {
-			itv->video_dec_func(itv, cmd, NULL);
-		}
-		break;
-	}
-
-	default:
-		return -EINVAL;
-	}
 	return 0;
 }
 
-int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
 {
-	struct ivtv_open_id *id = NULL;
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_routing route;
+
+	if (outp >= itv->card->nof_outputs)
+		return -EINVAL;
+
+	if (outp == itv->active_output) {
+		IVTV_DEBUG_INFO("Output unchanged\n");
+		return 0;
+	}
+	IVTV_DEBUG_INFO("Changing output from %d to %d\n",
+		   itv->active_output, outp);
+
+	itv->active_output = outp;
+	route.input = SAA7127_INPUT_TYPE_NORMAL;
+	route.output = itv->card->video_outputs[outp].video_output;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	return 0;
+}
+
+static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
+	return 0;
+}
+
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	ivtv_mute(itv);
+	IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+	ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
+	ivtv_unmute(itv);
+	return 0;
+}
+
+static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	*std = itv->std;
+	return 0;
+}
+
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 	struct yuv_playback_info *yi = &itv->yuv_info;
+
+	if ((*std & V4L2_STD_ALL) == 0)
+		return -EINVAL;
+
+	if (*std == itv->std)
+		return 0;
+
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+	    atomic_read(&itv->capturing) > 0 ||
+	    atomic_read(&itv->decoding) > 0) {
+		/* Switching standard would turn off the radio or mess
+		   with already running streams, prevent that by
+		   returning EBUSY. */
+		return -EBUSY;
+	}
+
+	itv->std = *std;
+	itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+	itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
+	itv->params.width = 720;
+	itv->params.height = itv->is_50hz ? 576 : 480;
+	itv->vbi.count = itv->is_50hz ? 18 : 12;
+	itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
+	itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
+
+	if (itv->hw_flags & IVTV_HW_CX25840)
+		itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
+
+	IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
+
+	/* Tuner */
+	ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		/* set display standard */
+		itv->std_out = *std;
+		itv->is_out_60hz = itv->is_60hz;
+		itv->is_out_50hz = itv->is_50hz;
+		ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+		ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+		itv->main_rect.left = itv->main_rect.top = 0;
+		itv->main_rect.width = 720;
+		itv->main_rect.height = itv->params.height;
+		ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+			720, itv->main_rect.height, 0, 0);
+		yi->main_rect = itv->main_rect;
+		if (!itv->osd_info) {
+			yi->osd_full_w = 720;
+			yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
+		}
+	}
+	return 0;
+}
+
+static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+
+	return 0;
+}
+
+static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+		strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_RADIO;
+	} else {
+		strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
+		vt->type = V4L2_TUNER_ANALOG_TV;
+	}
+
+	return 0;
+}
+
+static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+	int f, l;
+
+	if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+		for (f = 0; f < 2; f++) {
+			for (l = 0; l < 24; l++) {
+				if (valid_service_line(f, l, itv->is_50hz))
+					cap->service_lines[f][l] = set;
+			}
+		}
+		return 0;
+	}
+	if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+		if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+			return -EINVAL;
+		if (itv->is_60hz) {
+			cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+			cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+		} else {
+			cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+			cap->service_lines[0][16] = V4L2_SLICED_VPS;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	struct v4l2_enc_idx_entry *e = idx->entry;
+	int entries;
+	int i;
+
+	entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+				IVTV_MAX_PGM_INDEX;
+	if (entries > V4L2_ENC_IDX_ENTRIES)
+		entries = V4L2_ENC_IDX_ENTRIES;
+	idx->entries = 0;
+	for (i = 0; i < entries; i++) {
+		*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+		if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+			idx->entries++;
+			e++;
+		}
+	}
+	itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
+	return 0;
+}
+
+static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return ivtv_start_capture(id);
+
+	case V4L2_ENC_CMD_STOP:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+		return 0;
+
+	case V4L2_ENC_CMD_PAUSE:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+
+		if (!atomic_read(&itv->capturing))
+			return -EPERM;
+		if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			return 0;
+
+		ivtv_mute(itv);
+		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
+		break;
+
+	case V4L2_ENC_CMD_RESUME:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+
+		if (!atomic_read(&itv->capturing))
+			return -EPERM;
+
+		if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			return 0;
+
+		ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+		ivtv_unmute(itv);
+		break;
+	default:
+		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+	switch (enc->cmd) {
+	case V4L2_ENC_CMD_START:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+		enc->flags = 0;
+		return 0;
+
+	case V4L2_ENC_CMD_STOP:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+		return 0;
+
+	case V4L2_ENC_CMD_PAUSE:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+		enc->flags = 0;
+		return 0;
+
+	case V4L2_ENC_CMD_RESUME:
+		IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+		enc->flags = 0;
+		return 0;
+	default:
+		IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+		return -EINVAL;
+	}
+}
+
+static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 	u32 data[CX2341X_MBOX_MAX_DATA];
-	int streamtype = 0;
+	struct yuv_playback_info *yi = &itv->yuv_info;
 
-	if (filp) {
-		id = (struct ivtv_open_id *)filp->private_data;
-		streamtype = id->type;
-	}
+	int pixfmt;
+	static u32 pixel_format[16] = {
+		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+		V4L2_PIX_FMT_RGB565,
+		V4L2_PIX_FMT_RGB555,
+		V4L2_PIX_FMT_RGB444,
+		V4L2_PIX_FMT_RGB32,
+		0,
+		0,
+		0,
+		V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+		V4L2_PIX_FMT_YUV565,
+		V4L2_PIX_FMT_YUV555,
+		V4L2_PIX_FMT_YUV444,
+		V4L2_PIX_FMT_YUV32,
+		0,
+		0,
+		0,
+	};
 
-	switch (cmd) {
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+		return -EINVAL;
+	if (!itv->osd_video_pbase)
+		return -EINVAL;
 
-		*p = v4l2_prio_max(&itv->prio);
-		break;
-	}
+	fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
+		V4L2_FBUF_CAP_GLOBAL_ALPHA;
 
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+	data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+	pixfmt = (data[0] >> 3) & 0xf;
 
-		return v4l2_prio_change(&itv->prio, &id->prio, *prio);
-	}
+	fb->fmt.pixelformat = pixel_format[pixfmt];
+	fb->fmt.width = itv->osd_rect.width;
+	fb->fmt.height = itv->osd_rect.height;
+	fb->fmt.field = V4L2_FIELD_INTERLACED;
+	fb->fmt.bytesperline = fb->fmt.width;
+	fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	fb->fmt.field = V4L2_FIELD_INTERLACED;
+	fb->fmt.priv = 0;
+	if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
+		fb->fmt.bytesperline *= 2;
+	if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
+	    fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32)
+		fb->fmt.bytesperline *= 2;
+	fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height;
+	fb->base = (void *)itv->osd_video_pbase;
+	fb->flags = 0;
 
-	case VIDIOC_QUERYCAP:{
-		struct v4l2_capability *vcap = arg;
+	if (itv->osd_chroma_key_state)
+		fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
 
-		memset(vcap, 0, sizeof(*vcap));
-		strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
-		strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
-		strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
-		vcap->version = IVTV_DRIVER_VERSION; 	    /* version */
-		vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
+	if (itv->osd_global_alpha_state)
+		fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
 
-		/* reserved.. must set to 0! */
-		vcap->reserved[0] = vcap->reserved[1] =
-			vcap->reserved[2] = vcap->reserved[3] = 0;
-		break;
-	}
+	pixfmt &= 7;
 
-	case VIDIOC_ENUMAUDIO:{
-		struct v4l2_audio *vin = arg;
-
-		return ivtv_get_audio_input(itv, vin->index, vin);
-	}
-
-	case VIDIOC_G_AUDIO:{
-		struct v4l2_audio *vin = arg;
-
-		vin->index = itv->audio_input;
-		return ivtv_get_audio_input(itv, vin->index, vin);
-	}
-
-	case VIDIOC_S_AUDIO:{
-		struct v4l2_audio *vout = arg;
-
-		if (vout->index >= itv->nof_audio_inputs)
-			return -EINVAL;
-		itv->audio_input = vout->index;
-		ivtv_audio_set_io(itv);
-		break;
-	}
-
-	case VIDIOC_ENUMAUDOUT:{
-		struct v4l2_audioout *vin = arg;
-
-		/* set it to defaults from our table */
-		return ivtv_get_audio_output(itv, vin->index, vin);
-	}
-
-	case VIDIOC_G_AUDOUT:{
-		struct v4l2_audioout *vin = arg;
-
-		vin->index = 0;
-		return ivtv_get_audio_output(itv, vin->index, vin);
-	}
-
-	case VIDIOC_S_AUDOUT:{
-		struct v4l2_audioout *vout = arg;
-
-		return ivtv_get_audio_output(itv, vout->index, vout);
-	}
-
-	case VIDIOC_ENUMINPUT:{
-		struct v4l2_input *vin = arg;
-
-		/* set it to defaults from our table */
-		return ivtv_get_input(itv, vin->index, vin);
-	}
-
-	case VIDIOC_ENUMOUTPUT:{
-		struct v4l2_output *vout = arg;
-
-		return ivtv_get_output(itv, vout->index, vout);
-	}
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT: {
-		struct v4l2_format *fmt = arg;
-
-		return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT);
-	}
-
-	case VIDIOC_G_FMT: {
-		struct v4l2_format *fmt = arg;
-		int type = fmt->type;
-
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->type = type;
-		return ivtv_get_fmt(itv, id->type, fmt);
-	}
-
-	case VIDIOC_CROPCAP: {
-		struct v4l2_cropcap *cropcap = arg;
-
-		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-			return -EINVAL;
-		cropcap->bounds.top = cropcap->bounds.left = 0;
-		cropcap->bounds.width = 720;
-		if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			cropcap->bounds.height = itv->is_50hz ? 576 : 480;
-			cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
-			cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
-		} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			if (yi->track_osd) {
-				cropcap->bounds.width = yi->osd_full_w;
-				cropcap->bounds.height = yi->osd_full_h;
-			} else {
-				cropcap->bounds.width = 720;
-				cropcap->bounds.height =
-						itv->is_out_50hz ? 576 : 480;
-			}
-			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
-		} else {
-			cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
-			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
-			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
-		}
-		cropcap->defrect = cropcap->bounds;
+	/* no local alpha for RGB565 or unknown formats */
+	if (pixfmt == 1 || pixfmt > 4)
 		return 0;
-	}
 
-	case VIDIOC_S_CROP: {
-		struct v4l2_crop *crop = arg;
+	/* 16-bit formats have inverted local alpha */
+	if (pixfmt == 2 || pixfmt == 3)
+		fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+	else
+		fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
 
-		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-				yi->main_rect = crop->c;
-				return 0;
-			} else {
-				if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-					crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
-					itv->main_rect = crop->c;
-					return 0;
-				}
-			}
-			return -EINVAL;
-		}
-		return -EINVAL;
-	}
-
-	case VIDIOC_G_CROP: {
-		struct v4l2_crop *crop = arg;
-
-		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
-				crop->c = yi->main_rect;
-			else
-				crop->c = itv->main_rect;
-			return 0;
-		}
-		return -EINVAL;
-	}
-
-	case VIDIOC_ENUM_FMT: {
-		static struct v4l2_fmtdesc formats[] = {
-			{ 0, 0, 0,
-			  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
-			  { 0, 0, 0, 0 }
-			},
-			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
-			  "MPEG", V4L2_PIX_FMT_MPEG,
-			  { 0, 0, 0, 0 }
-			}
-		};
-		struct v4l2_fmtdesc *fmt = arg;
-		enum v4l2_buf_type type = fmt->type;
-
-		switch (type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-				return -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-		}
-		if (fmt->index > 1)
-			return -EINVAL;
-		*fmt = formats[fmt->index];
-		fmt->type = type;
-		return 0;
-	}
-
-	case VIDIOC_G_INPUT:{
-		*(int *)arg = itv->active_input;
-		break;
-	}
-
-	case VIDIOC_S_INPUT:{
-		int inp = *(int *)arg;
-
-		if (inp < 0 || inp >= itv->nof_inputs)
-			return -EINVAL;
-
-		if (inp == itv->active_input) {
-			IVTV_DEBUG_INFO("Input unchanged\n");
-			break;
-		}
-		if (atomic_read(&itv->capturing) > 0) {
-			return -EBUSY;
-		}
-		IVTV_DEBUG_INFO("Changing input from %d to %d\n",
-				itv->active_input, inp);
-
-		itv->active_input = inp;
-		/* Set the audio input to whatever is appropriate for the
-		   input type. */
-		itv->audio_input = itv->card->video_inputs[inp].audio_index;
-
-		/* prevent others from messing with the streams until
-		   we're finished changing inputs. */
-		ivtv_mute(itv);
-		ivtv_video_set_io(itv);
-		ivtv_audio_set_io(itv);
-		ivtv_unmute(itv);
-		break;
-	}
-
-	case VIDIOC_G_OUTPUT:{
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-			return -EINVAL;
-		*(int *)arg = itv->active_output;
-		break;
-	}
-
-	case VIDIOC_S_OUTPUT:{
-		int outp = *(int *)arg;
-		struct v4l2_routing route;
-
-		if (outp >= itv->card->nof_outputs)
-			return -EINVAL;
-
-		if (outp == itv->active_output) {
-			IVTV_DEBUG_INFO("Output unchanged\n");
-			break;
-		}
-		IVTV_DEBUG_INFO("Changing output from %d to %d\n",
-			   itv->active_output, outp);
-
-		itv->active_output = outp;
-		route.input = SAA7127_INPUT_TYPE_NORMAL;
-		route.output = itv->card->video_outputs[outp].video_output;
-		ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-		break;
-	}
-
-	case VIDIOC_G_FREQUENCY:{
-		struct v4l2_frequency *vf = arg;
-
-		if (vf->tuner != 0)
-			return -EINVAL;
-		ivtv_call_i2c_clients(itv, cmd, arg);
-		break;
-	}
-
-	case VIDIOC_S_FREQUENCY:{
-		struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
-
-		if (vf.tuner != 0)
-			return -EINVAL;
-
-		ivtv_mute(itv);
-		IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
-		ivtv_call_i2c_clients(itv, cmd, &vf);
-		ivtv_unmute(itv);
-		break;
-	}
-
-	case VIDIOC_ENUMSTD:{
-		struct v4l2_standard *vs = arg;
-		int idx = vs->index;
-
-		if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
-			return -EINVAL;
-
-		*vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
-				ivtv_std_60hz : ivtv_std_50hz;
-		vs->index = idx;
-		vs->id = enum_stds[idx].std;
-		strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
-		break;
-	}
-
-	case VIDIOC_G_STD:{
-		*(v4l2_std_id *) arg = itv->std;
-		break;
-	}
-
-	case VIDIOC_S_STD: {
-		v4l2_std_id std = *(v4l2_std_id *) arg;
-
-		if ((std & V4L2_STD_ALL) == 0)
-			return -EINVAL;
-
-		if (std == itv->std)
-			break;
-
-		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
-		    atomic_read(&itv->capturing) > 0 ||
-		    atomic_read(&itv->decoding) > 0) {
-			/* Switching standard would turn off the radio or mess
-			   with already running streams, prevent that by
-			   returning EBUSY. */
-			return -EBUSY;
-		}
-
-		itv->std = std;
-		itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
-		itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
-		itv->params.width = 720;
-		itv->params.height = itv->is_50hz ? 576 : 480;
-		itv->vbi.count = itv->is_50hz ? 18 : 12;
-		itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
-		itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
-		if (itv->hw_flags & IVTV_HW_CX25840) {
-			itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
-		}
-		IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
-
-		/* Tuner */
-		ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
-
-		if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
-			/* set display standard */
-			itv->std_out = std;
-			itv->is_out_60hz = itv->is_60hz;
-			itv->is_out_50hz = itv->is_50hz;
-			ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
-			ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
-			itv->main_rect.left = itv->main_rect.top = 0;
-			itv->main_rect.width = 720;
-			itv->main_rect.height = itv->params.height;
-			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-				720, itv->main_rect.height, 0, 0);
-			yi->main_rect = itv->main_rect;
-			if (!itv->osd_info) {
-				yi->osd_full_w = 720;
-				yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
-			}
-		}
-		break;
-	}
-
-	case VIDIOC_S_TUNER: {	/* Setting tuner can only set audio mode */
-		struct v4l2_tuner *vt = arg;
-
-		if (vt->index != 0)
-			return -EINVAL;
-
-		ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
-		break;
-	}
-
-	case VIDIOC_G_TUNER: {
-		struct v4l2_tuner *vt = arg;
-
-		if (vt->index != 0)
-			return -EINVAL;
-
-		memset(vt, 0, sizeof(*vt));
-		ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
-
-		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-			strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_RADIO;
-		} else {
-			strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
-			vt->type = V4L2_TUNER_ANALOG_TV;
-		}
-		break;
-	}
-
-	case VIDIOC_G_SLICED_VBI_CAP: {
-		struct v4l2_sliced_vbi_cap *cap = arg;
-		int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
-		int f, l;
-		enum v4l2_buf_type type = cap->type;
-
-		memset(cap, 0, sizeof(*cap));
-		cap->type = type;
-		if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-			for (f = 0; f < 2; f++) {
-				for (l = 0; l < 24; l++) {
-					if (valid_service_line(f, l, itv->is_50hz)) {
-						cap->service_lines[f][l] = set;
-					}
-				}
-			}
-			return 0;
-		}
-		if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
-			if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
-				return -EINVAL;
-			if (itv->is_60hz) {
-				cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-				cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
-			} else {
-				cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
-				cap->service_lines[0][16] = V4L2_SLICED_VPS;
-			}
-			return 0;
-		}
-		return -EINVAL;
-	}
-
-	case VIDIOC_G_ENC_INDEX: {
-		struct v4l2_enc_idx *idx = arg;
-		struct v4l2_enc_idx_entry *e = idx->entry;
-		int entries;
-		int i;
-
-		entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
-					IVTV_MAX_PGM_INDEX;
-		if (entries > V4L2_ENC_IDX_ENTRIES)
-			entries = V4L2_ENC_IDX_ENTRIES;
-		idx->entries = 0;
-		for (i = 0; i < entries; i++) {
-			*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
-			if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
-				idx->entries++;
-				e++;
-			}
-		}
-		itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
-		break;
-	}
-
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD: {
-		struct v4l2_encoder_cmd *enc = arg;
-		int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
-		memset(&enc->raw, 0, sizeof(enc->raw));
-		switch (enc->cmd) {
-		case V4L2_ENC_CMD_START:
-			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
-			enc->flags = 0;
-			if (try)
-				return 0;
-			return ivtv_start_capture(id);
-
-		case V4L2_ENC_CMD_STOP:
-			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
-			enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
-			if (try)
-				return 0;
-			ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
-			return 0;
-
-		case V4L2_ENC_CMD_PAUSE:
-			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&itv->capturing))
-				return -EPERM;
-			if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
-				return 0;
-			ivtv_mute(itv);
-			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
-			break;
-
-		case V4L2_ENC_CMD_RESUME:
-			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
-			enc->flags = 0;
-			if (try)
-				return 0;
-			if (!atomic_read(&itv->capturing))
-				return -EPERM;
-			if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
-				return 0;
-			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
-			ivtv_unmute(itv);
-			break;
-		default:
-			IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
-			return -EINVAL;
-		}
-		break;
-	}
-
-	case VIDIOC_G_FBUF: {
-		struct v4l2_framebuffer *fb = arg;
-		int pixfmt;
-		static u32 pixel_format[16] = {
-			V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
-			V4L2_PIX_FMT_RGB565,
-			V4L2_PIX_FMT_RGB555,
-			V4L2_PIX_FMT_RGB444,
-			V4L2_PIX_FMT_RGB32,
-			0,
-			0,
-			0,
-			V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
-			V4L2_PIX_FMT_YUV565,
-			V4L2_PIX_FMT_YUV555,
-			V4L2_PIX_FMT_YUV444,
-			V4L2_PIX_FMT_YUV32,
-			0,
-			0,
-			0,
-		};
-
-		memset(fb, 0, sizeof(*fb));
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-			return -EINVAL;
-		fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
-			V4L2_FBUF_CAP_GLOBAL_ALPHA;
-		ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
-		data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
-		pixfmt = (data[0] >> 3) & 0xf;
-		fb->fmt.pixelformat = pixel_format[pixfmt];
-		fb->fmt.width = itv->osd_rect.width;
-		fb->fmt.height = itv->osd_rect.height;
-		fb->base = (void *)itv->osd_video_pbase;
-		if (itv->osd_chroma_key_state)
-			fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
-		if (itv->osd_global_alpha_state)
-			fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
-		pixfmt &= 7;
-		/* no local alpha for RGB565 or unknown formats */
-		if (pixfmt == 1 || pixfmt > 4)
-			break;
+	if (itv->osd_local_alpha_state) {
 		/* 16-bit formats have inverted local alpha */
 		if (pixfmt == 2 || pixfmt == 3)
-			fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+			fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
 		else
-			fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
-		if (itv->osd_local_alpha_state) {
-			/* 16-bit formats have inverted local alpha */
-			if (pixfmt == 2 || pixfmt == 3)
-				fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
-			else
-				fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
-		}
-		if (yi->track_osd)
-			fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
-		break;
+			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
 	}
+	if (yi->track_osd)
+		fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
 
-	case VIDIOC_S_FBUF: {
-		struct v4l2_framebuffer *fb = arg;
+	return 0;
+}
 
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-			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|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
-		itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
-		ivtv_set_osd_alpha(itv);
-		yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
-		break;
-	}
+static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
 
-	case VIDIOC_OVERLAY: {
-		int *on = arg;
-
-		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-			return -EINVAL;
-		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
-		break;
-	}
-
-	case VIDIOC_LOG_STATUS:
-	{
-		int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
-		struct v4l2_input vidin;
-		struct v4l2_audio audin;
-		int i;
-
-		IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
-		IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
-		if (itv->hw_flags & IVTV_HW_TVEEPROM) {
-			struct tveeprom tv;
-
-			ivtv_read_eeprom(itv, &tv);
-		}
-		ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
-		ivtv_get_input(itv, itv->active_input, &vidin);
-		ivtv_get_audio_input(itv, itv->audio_input, &audin);
-		IVTV_INFO("Video Input:  %s\n", vidin.name);
-		IVTV_INFO("Audio Input:  %s%s\n", audin.name,
-			(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
-		if (has_output) {
-			struct v4l2_output vidout;
-			struct v4l2_audioout audout;
-			int mode = itv->output_mode;
-			static const char * const output_modes[5] = {
-				"None",
-				"MPEG Streaming",
-				"YUV Streaming",
-				"YUV Frames",
-				"Passthrough",
-			};
-			static const char * const audio_modes[5] = {
-				"Stereo",
-				"Left",
-				"Right",
-				"Mono",
-				"Swapped"
-			};
-			static const char * const alpha_mode[4] = {
-				"None",
-				"Global",
-				"Local",
-				"Global and Local"
-			};
-			static const char * const pixel_format[16] = {
-				"ARGB Indexed",
-				"RGB 5:6:5",
-				"ARGB 1:5:5:5",
-				"ARGB 1:4:4:4",
-				"ARGB 8:8:8:8",
-				"5",
-				"6",
-				"7",
-				"AYUV Indexed",
-				"YUV 5:6:5",
-				"AYUV 1:5:5:5",
-				"AYUV 1:4:4:4",
-				"AYUV 8:8:8:8",
-				"13",
-				"14",
-				"15",
-			};
-
-			ivtv_get_output(itv, itv->active_output, &vidout);
-			ivtv_get_audio_output(itv, 0, &audout);
-			IVTV_INFO("Video Output: %s\n", vidout.name);
-			IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
-				audio_modes[itv->audio_stereo_mode],
-				audio_modes[itv->audio_bilingual_mode]);
-			if (mode < 0 || mode > OUT_PASSTHROUGH)
-				mode = OUT_NONE;
-			IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
-			ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
-			data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
-			IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
-				data[0] & 1 ? "On" : "Off",
-				alpha_mode[(data[0] >> 1) & 0x3],
-				pixel_format[(data[0] >> 3) & 0xf]);
-		}
-		IVTV_INFO("Tuner:  %s\n",
-			test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
-		cx2341x_log_status(&itv->params, itv->name);
-		IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
-		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
-			struct ivtv_stream *s = &itv->streams[i];
-
-			if (s->v4l2dev == NULL || s->buffers == 0)
-				continue;
-			IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
-					(s->buffers - s->q_free.buffers) * 100 / s->buffers,
-					(s->buffers * s->buf_size) / 1024, s->buffers);
-		}
-		IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
-		IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
-		break;
-	}
-
-	default:
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
 		return -EINVAL;
+	if (!itv->osd_video_pbase)
+		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|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+	itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+	ivtv_set_osd_alpha(itv);
+	yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+	return ivtv_g_fbuf(file, fh, fb);
+}
+
+static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
+{
+	struct ivtv_open_id *id = fh;
+	struct ivtv *itv = id->itv;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+		return -EINVAL;
+
+	ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
+
+	return 0;
+}
+
+static int ivtv_log_status(struct file *file, void *fh)
+{
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
+	struct v4l2_input vidin;
+	struct v4l2_audio audin;
+	int i;
+
+	IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
+	IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
+	if (itv->hw_flags & IVTV_HW_TVEEPROM) {
+		struct tveeprom tv;
+
+		ivtv_read_eeprom(itv, &tv);
 	}
+	ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+	ivtv_get_input(itv, itv->active_input, &vidin);
+	ivtv_get_audio_input(itv, itv->audio_input, &audin);
+	IVTV_INFO("Video Input:  %s\n", vidin.name);
+	IVTV_INFO("Audio Input:  %s%s\n", audin.name,
+		(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
+	if (has_output) {
+		struct v4l2_output vidout;
+		struct v4l2_audioout audout;
+		int mode = itv->output_mode;
+		static const char * const output_modes[5] = {
+			"None",
+			"MPEG Streaming",
+			"YUV Streaming",
+			"YUV Frames",
+			"Passthrough",
+		};
+		static const char * const audio_modes[5] = {
+			"Stereo",
+			"Left",
+			"Right",
+			"Mono",
+			"Swapped"
+		};
+		static const char * const alpha_mode[4] = {
+			"None",
+			"Global",
+			"Local",
+			"Global and Local"
+		};
+		static const char * const pixel_format[16] = {
+			"ARGB Indexed",
+			"RGB 5:6:5",
+			"ARGB 1:5:5:5",
+			"ARGB 1:4:4:4",
+			"ARGB 8:8:8:8",
+			"5",
+			"6",
+			"7",
+			"AYUV Indexed",
+			"YUV 5:6:5",
+			"AYUV 1:5:5:5",
+			"AYUV 1:4:4:4",
+			"AYUV 8:8:8:8",
+			"13",
+			"14",
+			"15",
+		};
+
+		ivtv_get_output(itv, itv->active_output, &vidout);
+		ivtv_get_audio_output(itv, 0, &audout);
+		IVTV_INFO("Video Output: %s\n", vidout.name);
+		IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+			audio_modes[itv->audio_stereo_mode],
+			audio_modes[itv->audio_bilingual_mode]);
+		if (mode < 0 || mode > OUT_PASSTHROUGH)
+			mode = OUT_NONE;
+		IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
+		ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+		data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+		IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
+			data[0] & 1 ? "On" : "Off",
+			alpha_mode[(data[0] >> 1) & 0x3],
+			pixel_format[(data[0] >> 3) & 0xf]);
+	}
+	IVTV_INFO("Tuner:  %s\n",
+		test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+	cx2341x_log_status(&itv->params, itv->name);
+	IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
+	for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		if (s->v4l2dev == NULL || s->buffers == 0)
+			continue;
+		IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+				(s->buffers - s->q_free.buffers) * 100 / s->buffers,
+				(s->buffers * s->buf_size) / 1024, s->buffers);
+	}
+
+	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
+	IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
+
 	return 0;
 }
 
@@ -1433,7 +1548,7 @@
 			return -EINVAL;
 		if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
 			return 0;
-		if (ivtv_claim_stream(id, id->type)) {
+		if (ivtv_start_decoding(id, id->type)) {
 			return -EBUSY;
 		}
 		if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
@@ -1607,121 +1722,30 @@
 	return 0;
 }
 
-static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
-			      unsigned int cmd, void *arg)
+static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
 {
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
-	struct ivtv *itv = id->itv;
-	int ret;
+	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
-	/* check priority */
 	switch (cmd) {
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_OUTPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_S_FMT:
-	case VIDIOC_S_CROP:
-	case VIDIOC_S_AUDIO:
-	case VIDIOC_S_AUDOUT:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_S_FBUF:
-	case VIDIOC_OVERLAY:
-		ret = v4l2_prio_check(&itv->prio, &id->prio);
-		if (ret)
-			return ret;
+	case VIDIOC_INT_S_AUDIO_ROUTING: {
+		struct v4l2_routing *route = arg;
+
+		ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+		break;
 	}
 
-	switch (cmd) {
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-	case VIDIOC_G_CHIP_IDENT:
-	case VIDIOC_INT_S_AUDIO_ROUTING:
-	case VIDIOC_INT_RESET:
-		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-			v4l_printk_ioctl(cmd);
-			printk("\n");
-		}
-		return ivtv_debug_ioctls(filp, cmd, arg);
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
 
-	case VIDIOC_G_PRIORITY:
-	case VIDIOC_S_PRIORITY:
-	case VIDIOC_QUERYCAP:
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_ENUMOUTPUT:
-	case VIDIOC_G_OUTPUT:
-	case VIDIOC_S_OUTPUT:
-	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_ENUM_FMT:
-	case VIDIOC_CROPCAP:
-	case VIDIOC_G_CROP:
-	case VIDIOC_S_CROP:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_G_TUNER:
-	case VIDIOC_ENUMAUDIO:
-	case VIDIOC_S_AUDIO:
-	case VIDIOC_G_AUDIO:
-	case VIDIOC_ENUMAUDOUT:
-	case VIDIOC_S_AUDOUT:
-	case VIDIOC_G_AUDOUT:
-	case VIDIOC_G_SLICED_VBI_CAP:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_G_ENC_INDEX:
-	case VIDIOC_ENCODER_CMD:
-	case VIDIOC_TRY_ENCODER_CMD:
-	case VIDIOC_G_FBUF:
-	case VIDIOC_S_FBUF:
-	case VIDIOC_OVERLAY:
-		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-			v4l_printk_ioctl(cmd);
-			printk("\n");
-		}
-		return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
+		if ((val == 0 && itv->options.newi2c) || (val & 0x01))
+			ivtv_reset_ir_gpio(itv);
+		if (val & 0x02)
+			itv->video_dec_func(itv, cmd, NULL);
+		break;
+	}
 
-	case VIDIOC_QUERYMENU:
-	case VIDIOC_QUERYCTRL:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_EXT_CTRLS:
-	case VIDIOC_G_EXT_CTRLS:
-	case VIDIOC_TRY_EXT_CTRLS:
-		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-			v4l_printk_ioctl(cmd);
-			printk("\n");
-		}
-		return ivtv_control_ioctls(itv, cmd, arg);
-
-	case IVTV_IOC_DMA_FRAME:
-	case VIDEO_GET_PTS:
-	case VIDEO_GET_FRAME_COUNT:
-	case VIDEO_GET_EVENT:
-	case VIDEO_PLAY:
-	case VIDEO_STOP:
-	case VIDEO_FREEZE:
-	case VIDEO_CONTINUE:
-	case VIDEO_COMMAND:
-	case VIDEO_TRY_COMMAND:
-		return ivtv_decoder_ioctls(filp, cmd, arg);
-
-	case 0x00005401:	/* Handle isatty() calls */
-		return -EINVAL;
 	default:
-		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
-						   ivtv_v4l2_do_ioctl);
+		return -EINVAL;
 	}
 	return 0;
 }
@@ -1729,7 +1753,11 @@
 static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
 		unsigned int cmd, unsigned long arg)
 {
-	/* Filter dvb ioctls that cannot be handled by video_usercopy */
+	struct video_device *vfd = video_devdata(filp);
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	int ret;
+
+	/* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
 	switch (cmd) {
 	case VIDEO_SELECT_SOURCE:
 		IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
@@ -1758,10 +1786,47 @@
 		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
 		return 0;
 
+	case IVTV_IOC_DMA_FRAME:
+	case VIDEO_GET_PTS:
+	case VIDEO_GET_FRAME_COUNT:
+	case VIDEO_GET_EVENT:
+	case VIDEO_PLAY:
+	case VIDEO_STOP:
+	case VIDEO_FREEZE:
+	case VIDEO_CONTINUE:
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND:
+		return ivtv_decoder_ioctls(filp, cmd, (void *)arg);
+
 	default:
 		break;
 	}
-	return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
+
+	/* check priority */
+	switch (cmd) {
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_OUTPUT:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_FREQUENCY:
+	case VIDIOC_S_FMT:
+	case VIDIOC_S_CROP:
+	case VIDIOC_S_AUDIO:
+	case VIDIOC_S_AUDOUT:
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_S_FBUF:
+	case VIDIOC_OVERLAY:
+		ret = v4l2_prio_check(&itv->prio, &id->prio);
+		if (ret)
+			return ret;
+	}
+
+	if (ivtv_debug & IVTV_DBGFLG_IOCTL)
+		vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+	ret = video_ioctl2(inode, filp, cmd, arg);
+	vfd->debug = 0;
+	return ret;
 }
 
 int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
@@ -1776,3 +1841,70 @@
 	mutex_unlock(&itv->serialize_lock);
 	return res;
 }
+
+void ivtv_set_funcs(struct video_device *vdev)
+{
+	vdev->vidioc_querycap     	    = ivtv_querycap;
+	vdev->vidioc_g_priority   	    = ivtv_g_priority;
+	vdev->vidioc_s_priority   	    = ivtv_s_priority;
+	vdev->vidioc_s_audio      	    = ivtv_s_audio;
+	vdev->vidioc_g_audio      	    = ivtv_g_audio;
+	vdev->vidioc_enumaudio   	    = ivtv_enumaudio;
+	vdev->vidioc_s_audout     	    = ivtv_s_audout;
+	vdev->vidioc_g_audout     	    = ivtv_g_audout;
+	vdev->vidioc_enum_input   	    = ivtv_enum_input;
+	vdev->vidioc_enum_output   	    = ivtv_enum_output;
+	vdev->vidioc_enumaudout   	    = ivtv_enumaudout;
+	vdev->vidioc_cropcap       	    = ivtv_cropcap;
+	vdev->vidioc_s_crop       	    = ivtv_s_crop;
+	vdev->vidioc_g_crop       	    = ivtv_g_crop;
+	vdev->vidioc_g_input      	    = ivtv_g_input;
+	vdev->vidioc_s_input      	    = ivtv_s_input;
+	vdev->vidioc_g_output     	    = ivtv_g_output;
+	vdev->vidioc_s_output     	    = ivtv_s_output;
+	vdev->vidioc_g_frequency 	    = ivtv_g_frequency;
+	vdev->vidioc_s_frequency  	    = ivtv_s_frequency;
+	vdev->vidioc_s_tuner      	    = ivtv_s_tuner;
+	vdev->vidioc_g_tuner      	    = ivtv_g_tuner;
+	vdev->vidioc_g_enc_index 	    = ivtv_g_enc_index;
+	vdev->vidioc_g_fbuf		    = ivtv_g_fbuf;
+	vdev->vidioc_s_fbuf		    = ivtv_s_fbuf;
+	vdev->vidioc_g_std 		    = ivtv_g_std;
+	vdev->vidioc_s_std 		    = ivtv_s_std;
+	vdev->vidioc_overlay		    = ivtv_overlay;
+	vdev->vidioc_log_status		    = ivtv_log_status;
+	vdev->vidioc_enum_fmt_vid_cap 	    = ivtv_enum_fmt_vid_cap;
+	vdev->vidioc_encoder_cmd  	    = ivtv_encoder_cmd;
+	vdev->vidioc_try_encoder_cmd 	    = ivtv_try_encoder_cmd;
+	vdev->vidioc_enum_fmt_vid_out       = ivtv_enum_fmt_vid_out;
+	vdev->vidioc_g_fmt_vid_cap  	    = ivtv_g_fmt_vid_cap;
+	vdev->vidioc_g_fmt_vbi_cap	    = ivtv_g_fmt_vbi_cap;
+	vdev->vidioc_g_fmt_sliced_vbi_cap   = ivtv_g_fmt_sliced_vbi_cap;
+	vdev->vidioc_g_fmt_vid_out          = ivtv_g_fmt_vid_out;
+	vdev->vidioc_g_fmt_vid_out_overlay  = ivtv_g_fmt_vid_out_overlay;
+	vdev->vidioc_g_fmt_sliced_vbi_out   = ivtv_g_fmt_sliced_vbi_out;
+	vdev->vidioc_s_fmt_vid_cap  	    = ivtv_s_fmt_vid_cap;
+	vdev->vidioc_s_fmt_vbi_cap 	    = ivtv_s_fmt_vbi_cap;
+	vdev->vidioc_s_fmt_sliced_vbi_cap   = ivtv_s_fmt_sliced_vbi_cap;
+	vdev->vidioc_s_fmt_vid_out          = ivtv_s_fmt_vid_out;
+	vdev->vidioc_s_fmt_vid_out_overlay  = ivtv_s_fmt_vid_out_overlay;
+	vdev->vidioc_s_fmt_sliced_vbi_out   = ivtv_s_fmt_sliced_vbi_out;
+	vdev->vidioc_try_fmt_vid_cap  	    = ivtv_try_fmt_vid_cap;
+	vdev->vidioc_try_fmt_vbi_cap	    = ivtv_try_fmt_vbi_cap;
+	vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap;
+	vdev->vidioc_try_fmt_vid_out        = ivtv_try_fmt_vid_out;
+	vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay;
+	vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out;
+	vdev->vidioc_g_sliced_vbi_cap 	    = ivtv_g_sliced_vbi_cap;
+	vdev->vidioc_g_chip_ident 	    = ivtv_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	vdev->vidioc_g_register 	    = ivtv_g_register;
+	vdev->vidioc_s_register 	    = ivtv_s_register;
+#endif
+	vdev->vidioc_default 		    = ivtv_default;
+	vdev->vidioc_queryctrl 		    = ivtv_queryctrl;
+	vdev->vidioc_querymenu 		    = ivtv_querymenu;
+	vdev->vidioc_g_ext_ctrls    	    = ivtv_g_ext_ctrls;
+	vdev->vidioc_s_ext_ctrls    	    = ivtv_s_ext_ctrls;
+	vdev->vidioc_try_ext_ctrls    	    = ivtv_try_ext_ctrls;
+}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index 4e67f0e..7018858 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -24,10 +24,13 @@
 u16 ivtv_service2vbi(int type);
 void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
 u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-		    unsigned long arg);
-int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
 void ivtv_set_osd_alpha(struct ivtv *itv);
 int ivtv_set_speed(struct ivtv *itv, int speed);
+void ivtv_set_funcs(struct video_device *vdev);
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index c854285..f8883b4 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -220,7 +220,8 @@
 	s->v4l2dev->dev = &itv->dev->dev;
 	s->v4l2dev->fops = ivtv_stream_info[type].fops;
 	s->v4l2dev->release = video_device_release;
-
+	s->v4l2dev->tvnorms = V4L2_STD_ALL;
+	ivtv_set_funcs(s->v4l2dev);
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 73be154..bdfda48 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -367,6 +367,88 @@
 	return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
 }
 
+static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
+		     size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	void *dst;
+	int err = 0;
+	unsigned long total_size;
+	struct ivtv *itv = (struct ivtv *) info->par;
+	unsigned long dma_offset =
+			IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
+	unsigned long dma_size;
+	u16 lead = 0, tail = 0;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EFBIG;
+
+	if (count > total_size) {
+		err = -EFBIG;
+		count = total_size;
+	}
+
+	if (count + p > total_size) {
+		if (!err)
+			err = -ENOSPC;
+
+		count = total_size - p;
+	}
+
+	dst = (void __force *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	if (!access_ok(VERIFY_READ, buf, count)) {
+		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+			(unsigned long)buf);
+		err = -EFAULT;
+	}
+
+	if (!err) {
+		/* If transfer size > threshold and both src/dst
+		addresses are aligned, use DMA */
+		if (count >= 4096 &&
+		    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
+			/* Odd address = can't DMA. Align */
+			if ((unsigned long)dst & 3) {
+				lead = 4 - ((unsigned long)dst & 3);
+				memcpy(dst, buf, lead);
+				buf += lead;
+				dst += lead;
+			}
+			/* DMA resolution is 32 bits */
+			if ((count - lead) & 3)
+				tail = (count - lead) & 3;
+			/* DMA the data */
+			dma_size = count - lead - tail;
+			err = ivtvfb_prep_dec_dma_to_device(itv,
+			       p + lead + dma_offset, (void *)buf, dma_size);
+			dst += dma_size;
+			buf += dma_size;
+			/* Copy any leftover data */
+			if (tail)
+				memcpy(dst, buf, tail);
+		} else {
+			memcpy(dst, buf, count);
+		}
+	}
+
+	if  (!err)
+		*ppos += count;
+
+	return (err) ? err : count;
+}
+
 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	DEFINE_WAIT(wait);
@@ -708,6 +790,9 @@
 	else
 		var->pixclock = pixclock;
 
+	itv->osd_rect.width = var->xres;
+	itv->osd_rect.height = var->yres;
+
 	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
 		      var->xres, var->yres,
 		      var->xres_virtual, var->yres_virtual,
@@ -824,6 +909,7 @@
 
 static struct fb_ops ivtvfb_ops = {
 	.owner = THIS_MODULE,
+	.fb_write       = ivtvfb_write,
 	.fb_check_var   = ivtvfb_check_var,
 	.fb_set_par     = ivtvfb_set_par,
 	.fb_setcolreg   = ivtvfb_setcolreg,
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 8e0160d..39bf6b1 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -171,4 +171,3 @@
 	.remove = m52790_remove,
 	.id_table = m52790_id,
 };
-
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index e7ccbc8..2fb5854 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1253,7 +1253,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
 				struct v4l2_fmtdesc *f)
 {
 	if (f->index > 1)
@@ -1283,7 +1283,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap(struct file *file, void *fh,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
 				struct v4l2_format *f)
 {
 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1316,7 +1316,8 @@
 	return 0;
 }
 
-static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+				    struct v4l2_format *f)
 {
 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1346,7 +1347,8 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+				    struct v4l2_format *f)
 {
 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1709,10 +1711,10 @@
 	.vidioc_queryctrl	= vidioc_queryctrl,
 	.vidioc_s_ctrl		= vidioc_s_ctrl,
 	.vidioc_g_ctrl		= vidioc_g_ctrl,
-	.vidioc_enum_fmt_cap	= vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap	= vidioc_try_fmt_cap,
-	.vidioc_g_fmt_cap	= vidioc_g_fmt_cap,
-	.vidioc_s_fmt_cap	= vidioc_s_fmt_cap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
 	.vidioc_reqbufs		= vidioc_reqbufs,
 	.vidioc_querybuf	= vidioc_querybuf,
 	.vidioc_qbuf		= vidioc_qbuf,
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 310dbab..5691e01 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -110,6 +110,7 @@
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END };
+
 I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
@@ -333,7 +334,6 @@
 
 /* ------------------------------------------------------------------------ */
 
-
 static void msp_wake_thread(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
@@ -1004,7 +1004,6 @@
 	.id_table = msp_id,
 };
 
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 7f55685..1622f70 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -480,7 +480,6 @@
 	struct msp3400c_carrier_detect *cd;
 	int count, max1, max2, val1, val2, val, i;
 
-
 	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
 	set_freezable();
 	for (;;) {
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 1658fe5..b31ba4e 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -815,7 +815,6 @@
 
 	return 0;
 }
-
 static const struct i2c_device_id mt9v022_id[] = {
 	{ "mt9v022", 0 },
 	{ }
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index d7bfd30..ea032f5 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -682,17 +682,17 @@
 	for (index = 0; index < N_OV7670_FMTS; index++)
 		if (ov7670_formats[index].pixelformat == pix->pixelformat)
 			break;
-	if (index >= N_OV7670_FMTS)
-		return -EINVAL;
+	if (index >= N_OV7670_FMTS) {
+		/* default to first format */
+		index = 0;
+		pix->pixelformat = ov7670_formats[0].pixelformat;
+	}
 	if (ret_fmt != NULL)
 		*ret_fmt = ov7670_formats + index;
 	/*
 	 * Fields: the OV devices claim to be progressive.
 	 */
-	if (pix->field == V4L2_FIELD_ANY)
-		pix->field = V4L2_FIELD_NONE;
-	else if (pix->field != V4L2_FIELD_NONE)
-		return -EINVAL;
+	pix->field = V4L2_FIELD_NONE;
 	/*
 	 * Round requested image size down to the nearest
 	 * we support, but not below the smallest.
@@ -833,7 +833,7 @@
 		int matrix[CMATRIX_LEN])
 {
 	int i, ret;
-	unsigned char signbits;
+	unsigned char signbits = 0;
 
 	/*
 	 * Weird crap seems to exist in the upper part of
@@ -1009,7 +1009,7 @@
 
 static int ov7670_t_brightness(struct i2c_client *client, int value)
 {
-	unsigned char com8, v;
+	unsigned char com8 = 0, v;
 	int ret;
 
 	ov7670_read(client, REG_COM8, &com8);
@@ -1022,7 +1022,7 @@
 
 static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
 {
-	unsigned char v;
+	unsigned char v = 0;
 	int ret = ov7670_read(client, REG_BRIGHT, &v);
 
 	*value = ov7670_sm_to_abs(v);
@@ -1036,7 +1036,7 @@
 
 static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
 {
-	unsigned char v;
+	unsigned char v = 0;
 	int ret = ov7670_read(client, REG_CONTRAS, &v);
 
 	*value = v;
@@ -1046,7 +1046,7 @@
 static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
 {
 	int ret;
-	unsigned char v;
+	unsigned char v = 0;
 
 	ret = ov7670_read(client, REG_MVFP, &v);
 	*value = (v & MVFP_MIRROR) == MVFP_MIRROR;
@@ -1056,7 +1056,7 @@
 
 static int ov7670_t_hflip(struct i2c_client *client, int value)
 {
-	unsigned char v;
+	unsigned char v = 0;
 	int ret;
 
 	ret = ov7670_read(client, REG_MVFP, &v);
@@ -1074,7 +1074,7 @@
 static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
 {
 	int ret;
-	unsigned char v;
+	unsigned char v = 0;
 
 	ret = ov7670_read(client, REG_MVFP, &v);
 	*value = (v & MVFP_FLIP) == MVFP_FLIP;
@@ -1084,7 +1084,7 @@
 
 static int ov7670_t_vflip(struct i2c_client *client, int value)
 {
-	unsigned char v;
+	unsigned char v = 0;
 	int ret;
 
 	ret = ov7670_read(client, REG_MVFP, &v);
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 8063e33..065c245 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -297,7 +297,6 @@
 	switch (adap->id) {
 	case I2C_HW_SMBUS_OV511:
 	case I2C_HW_SMBUS_OV518:
-	case I2C_HW_SMBUS_OVFX2:
 	case I2C_HW_SMBUS_W9968CF:
 		PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
 		break;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 8d859cc..cdedaa5 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
index 536339b..ac54eed 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 73dcb1c..7c19ff7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -1,5 +1,4 @@
 /*
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
index 745e270..6180129 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -1,5 +1,4 @@
 /*
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 91a42f2..0764fbf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
index c168005..0371ae6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 29d5059..895859e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
index 54b2844..66abf77 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index 707d2d9..be79249 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -1,5 +1,4 @@
 /*
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index b53121c..ca892fb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
index 990b02d..e24ff59 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 5bf6d8f..5d036e7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2007 Mike Isely <isely@pobox.com>
  *
@@ -182,7 +181,7 @@
 	return 0;
 }
 
-struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+static struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
 	.frontend_attach = pvr2_lgdt3303_attach,
 	.tuner_attach    = pvr2_lgh06xf_attach,
 };
@@ -242,7 +241,7 @@
 	return 0;
 }
 
-struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
 	.frontend_attach = pvr2_lgdt3302_attach,
 	.tuner_attach    = pvr2_fcv1236d_attach,
 };
@@ -315,7 +314,7 @@
 	return 0;
 }
 
-struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+static struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
 	.frontend_attach = pvr2_tda10048_attach,
 	.tuner_attach    = pvr2_73xxx_tda18271_8295_attach,
 };
@@ -418,12 +417,12 @@
 	return 0;
 }
 
-struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+static struct pvr2_dvb_props pvr2_750xx_dvb_props = {
 	.frontend_attach = pvr2_s5h1409_attach,
 	.tuner_attach    = pvr2_tda18271_8295_attach,
 };
 
-struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+static struct pvr2_dvb_props pvr2_751xx_dvb_props = {
 	.frontend_attach = pvr2_s5h1411_attach,
 	.tuner_attach    = pvr2_tda18271_8295_attach,
 };
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index d016f8b6..e23ce1d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 5ef0059..299afa4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
index 8424297..cca3216 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index c46d367..a1252d6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
index 54caf2e..232fefb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
index abaada3..b58369e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index a3fe251..657f861 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 0a86888..a5217a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
@@ -40,6 +39,23 @@
 #define TV_MIN_FREQ     55250000L
 #define TV_MAX_FREQ    850000000L
 
+/* This defines a minimum interval that the decoder must remain quiet
+   before we are allowed to start it running. */
+#define TIME_MSEC_DECODER_WAIT 50
+
+/* This defines a minimum interval that the encoder must remain quiet
+   before we are allowed to configure it.  I had this originally set to
+   50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that
+   things work better when it's set to 100msec. */
+#define TIME_MSEC_ENCODER_WAIT 100
+
+/* This defines the minimum interval that the encoder must successfully run
+   before we consider that the encoder has run at least once since its
+   firmware has been loaded.  This measurement is in important for cases
+   where we can't do something until we know that the encoder has been run
+   at least once. */
+#define TIME_MSEC_ENCODER_OK 250
+
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
 static DEFINE_MUTEX(pvr2_unit_mtx);
 
@@ -67,6 +83,16 @@
 module_param_array(tolerance,    int, NULL, 0444);
 MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
 
+/* US Broadcast channel 7 (175.25 MHz) */
+static int default_tv_freq    = 175250000L;
+/* 104.3 MHz, a usable FM station for my area */
+static int default_radio_freq = 104300000L;
+
+module_param_named(tv_freq, default_tv_freq, int, 0444);
+MODULE_PARM_DESC(tv_freq, "specify initial television frequency");
+module_param_named(radio_freq, default_radio_freq, int, 0444);
+MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
+
 #define PVR2_CTL_WRITE_ENDPOINT  0x01
 #define PVR2_CTL_READ_ENDPOINT   0x81
 
@@ -1701,10 +1727,8 @@
 	   are, but I set them to something usable in the Chicago area just
 	   to make driver testing a little easier. */
 
-	/* US Broadcast channel 7 (175.25 MHz) */
-	hdw->freqValTelevision = 175250000L;
-	/* 104.3 MHz, a usable FM station for my area */
-	hdw->freqValRadio = 104300000L;
+	hdw->freqValTelevision = default_tv_freq;
+	hdw->freqValRadio = default_radio_freq;
 
 	// Do not use pvr2_reset_ctl_endpoints() here.  It is not
 	// thread-safe against the normal pvr2_send_request() mechanism.
@@ -1989,7 +2013,8 @@
 		case V4L2_CTRL_TYPE_MENU:
 			ciptr->type = pvr2_ctl_enum;
 			ciptr->def.type_enum.value_names =
-				cx2341x_ctrl_get_menu(ciptr->v4l_id);
+				cx2341x_ctrl_get_menu(&hdw->enc_ctl_state,
+								ciptr->v4l_id);
 			for (cnt1 = 0;
 			     ciptr->def.type_enum.value_names[cnt1] != NULL;
 			     cnt1++) { }
@@ -2428,22 +2453,38 @@
 	struct pvr2_ctrl *cptr;
 	int disruptive_change;
 
-	/* When video standard changes, reset the hres and vres values -
-	   but if the user has pending changes there, then let the changes
-	   take priority. */
+	/* Handle some required side effects when the video standard is
+	   changed.... */
 	if (hdw->std_dirty) {
-		/* Rewrite the vertical resolution to be appropriate to the
-		   video standard that has been selected. */
 		int nvres;
+		int gop_size;
 		if (hdw->std_mask_cur & V4L2_STD_525_60) {
 			nvres = 480;
+			gop_size = 15;
 		} else {
 			nvres = 576;
+			gop_size = 12;
 		}
+		/* Rewrite the vertical resolution to be appropriate to the
+		   video standard that has been selected. */
 		if (nvres != hdw->res_ver_val) {
 			hdw->res_ver_val = nvres;
 			hdw->res_ver_dirty = !0;
 		}
+		/* Rewrite the GOP size to be appropriate to the video
+		   standard that has been selected. */
+		if (gop_size != hdw->enc_ctl_state.video_gop_size) {
+			struct v4l2_ext_controls cs;
+			struct v4l2_ext_control c1;
+			memset(&cs, 0, sizeof(cs));
+			memset(&c1, 0, sizeof(c1));
+			cs.controls = &c1;
+			cs.count = 1;
+			c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+			c1.value = gop_size;
+			cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,
+					  VIDIOC_S_EXT_CTRLS);
+		}
 	}
 
 	if (hdw->input_dirty && hdw->state_pathway_ok &&
@@ -3421,7 +3462,7 @@
 }
 
 
-void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
+static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
 {
 	/* change some GPIO data
 	 *
@@ -3601,7 +3642,9 @@
 				   the encoder. */
 				if (!hdw->state_encoder_waitok) {
 					hdw->encoder_wait_timer.expires =
-						jiffies + (HZ*50/1000);
+						jiffies +
+						(HZ * TIME_MSEC_ENCODER_WAIT
+						 / 1000);
 					add_timer(&hdw->encoder_wait_timer);
 				}
 			}
@@ -3725,7 +3768,7 @@
 		hdw->state_encoder_run = !0;
 		if (!hdw->state_encoder_runok) {
 			hdw->encoder_run_timer.expires =
-				jiffies + (HZ*250/1000);
+				jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000);
 			add_timer(&hdw->encoder_run_timer);
 		}
 	}
@@ -3800,7 +3843,9 @@
 				   but before we did the pending check. */
 				if (!hdw->state_decoder_quiescent) {
 					hdw->quiescent_timer.expires =
-						jiffies + (HZ*50/1000);
+						jiffies +
+						(HZ * TIME_MSEC_DECODER_WAIT
+						 / 1000);
 					add_timer(&hdw->quiescent_timer);
 				}
 			}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 20295e0..c04956d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 4977376..ccdb429 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index c650e02..55f04a0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index c838df6..7fa3868 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 793c89a..9d3c18b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index bd0807b..6ef7a1c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 7aff8b7..20b6ae0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
index 42fcf82..afb7e87 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index c572212..05a1376 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
index 1d362f8..100e078 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 332aced..ad0d98c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index fdc5a2b..ca9f83a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h
index 07c3993..a35c53d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 0ff7a83..46a8c39 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
@@ -71,6 +70,7 @@
 	struct device_attribute attr_val;
 	struct device_attribute attr_custom;
 	struct pvr2_ctrl *cptr;
+	int ctl_id;
 	struct pvr2_sysfs *chptr;
 	struct pvr2_sysfs_ctl_item *item_next;
 	struct attribute *attr_gen[7];
@@ -83,38 +83,29 @@
 	struct class class;
 };
 
-static ssize_t show_name(int id,struct device *class_dev,char *buf)
+static ssize_t show_name(struct device *class_dev,
+			 struct device_attribute *attr,
+			 char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	const char *name;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-
-	name = pvr2_ctrl_get_desc(cptr);
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
-
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name);
+	name = pvr2_ctrl_get_desc(cip->cptr);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",
+			 cip->chptr, cip->ctl_id, name);
 	if (!name) return -EINVAL;
-
-	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+	return scnprintf(buf, PAGE_SIZE, "%s\n", name);
 }
 
-static ssize_t show_type(int id,struct device *class_dev,char *buf)
+static ssize_t show_type(struct device *class_dev,
+			 struct device_attribute *attr,
+			 char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	const char *name;
 	enum pvr2_ctl_type tp;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-
-	tp = pvr2_ctrl_get_type(cptr);
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type);
+	tp = pvr2_ctrl_get_type(cip->cptr);
 	switch (tp) {
 	case pvr2_ctl_int: name = "integer"; break;
 	case pvr2_ctl_enum: name = "enum"; break;
@@ -122,403 +113,178 @@
 	case pvr2_ctl_bool: name = "boolean"; break;
 	default: name = "?"; break;
 	}
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
-
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",
+			 cip->chptr, cip->ctl_id, name);
 	if (!name) return -EINVAL;
-
-	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+	return scnprintf(buf, PAGE_SIZE, "%s\n", name);
 }
 
-static ssize_t show_min(int id,struct device *class_dev,char *buf)
+static ssize_t show_min(struct device *class_dev,
+			struct device_attribute *attr,
+			char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	long val;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-	val = pvr2_ctrl_get_min(cptr);
-
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
-
-	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min);
+	val = pvr2_ctrl_get_min(cip->cptr);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",
+			 cip->chptr, cip->ctl_id, val);
+	return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
 }
 
-static ssize_t show_max(int id,struct device *class_dev,char *buf)
+static ssize_t show_max(struct device *class_dev,
+			struct device_attribute *attr,
+			char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	long val;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-	val = pvr2_ctrl_get_max(cptr);
-
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
-
-	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max);
+	val = pvr2_ctrl_get_max(cip->cptr);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",
+			 cip->chptr, cip->ctl_id, val);
+	return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
 }
 
-static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
+static ssize_t show_val_norm(struct device *class_dev,
+			     struct device_attribute *attr,
+			     char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
-	int val,ret;
+	struct pvr2_sysfs_ctl_item *cip;
+	int val;
+	int ret;
 	unsigned int cnt = 0;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-
-	ret = pvr2_ctrl_get_value(cptr,&val);
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
+	ret = pvr2_ctrl_get_value(cip->cptr, &val);
 	if (ret < 0) return ret;
-
-	ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
-				     buf,PAGE_SIZE-1,&cnt);
-
+	ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,
+				     buf, PAGE_SIZE - 1, &cnt);
 	pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
-			 sfp,id,cnt,buf,val);
+			 cip->chptr, cip->ctl_id, cnt, buf, val);
 	buf[cnt] = '\n';
 	return cnt+1;
 }
 
-static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
+static ssize_t show_val_custom(struct device *class_dev,
+			       struct device_attribute *attr,
+			       char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
-	int val,ret;
+	struct pvr2_sysfs_ctl_item *cip;
+	int val;
+	int ret;
 	unsigned int cnt = 0;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-
-	ret = pvr2_ctrl_get_value(cptr,&val);
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
+	ret = pvr2_ctrl_get_value(cip->cptr, &val);
 	if (ret < 0) return ret;
-
-	ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
-					    buf,PAGE_SIZE-1,&cnt);
-
+	ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val,
+					    buf, PAGE_SIZE - 1, &cnt);
 	pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
-			 sfp,id,cnt,buf,val);
+			 cip->chptr, cip->ctl_id, cnt, buf, val);
 	buf[cnt] = '\n';
 	return cnt+1;
 }
 
-static ssize_t show_enum(int id,struct device *class_dev,char *buf)
+static ssize_t show_enum(struct device *class_dev,
+			 struct device_attribute *attr,
+			 char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	long val;
-	unsigned int bcnt,ccnt,ecnt;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-	ecnt = pvr2_ctrl_get_cnt(cptr);
+	unsigned int bcnt, ccnt, ecnt;
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum);
+	ecnt = pvr2_ctrl_get_cnt(cip->cptr);
 	bcnt = 0;
 	for (val = 0; val < ecnt; val++) {
-		pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+		pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt,
+				      PAGE_SIZE - bcnt, &ccnt);
 		if (!ccnt) continue;
 		bcnt += ccnt;
 		if (bcnt >= PAGE_SIZE) break;
 		buf[bcnt] = '\n';
 		bcnt++;
 	}
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",
+			 cip->chptr, cip->ctl_id);
 	return bcnt;
 }
 
-static ssize_t show_bits(int id,struct device *class_dev,char *buf)
+static ssize_t show_bits(struct device *class_dev,
+			 struct device_attribute *attr,
+			 char *buf)
 {
-	struct pvr2_ctrl *cptr;
-	struct pvr2_sysfs *sfp;
-	int valid_bits,msk;
-	unsigned int bcnt,ccnt;
-
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
-	if (!sfp) return -EINVAL;
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
-	if (!cptr) return -EINVAL;
-	valid_bits = pvr2_ctrl_get_mask(cptr);
+	struct pvr2_sysfs_ctl_item *cip;
+	int valid_bits, msk;
+	unsigned int bcnt, ccnt;
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits);
+	valid_bits = pvr2_ctrl_get_mask(cip->cptr);
 	bcnt = 0;
 	for (msk = 1; valid_bits; msk <<= 1) {
 		if (!(msk & valid_bits)) continue;
 		valid_bits &= ~msk;
-		pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+		pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt,
+				      PAGE_SIZE - bcnt, &ccnt);
 		bcnt += ccnt;
 		if (bcnt >= PAGE_SIZE) break;
 		buf[bcnt] = '\n';
 		bcnt++;
 	}
-	pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+	pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",
+			 cip->chptr, cip->ctl_id);
 	return bcnt;
 }
 
-static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl,
 			 const char *buf,unsigned int count)
 {
-	struct pvr2_ctrl *cptr;
 	int ret;
 	int mask,val;
-
-	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (customfl) {
-		ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+		ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count,
+						    &mask, &val);
 	} else {
-		ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
+		ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count,
+					     &mask, &val);
 	}
 	if (ret < 0) return ret;
-	ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
-	pvr2_hdw_commit_ctl(sfp->channel.hdw);
+	ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val);
+	pvr2_hdw_commit_ctl(cip->chptr->channel.hdw);
 	return ret;
 }
 
-static ssize_t store_val_norm(int id,struct device *class_dev,
-			     const char *buf,size_t count)
+static ssize_t store_val_norm(struct device *class_dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
 {
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	int ret;
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
 	pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",
-			 sfp,id,(int)count,buf);
-	ret = store_val_any(id,0,sfp,buf,count);
+			 cip->chptr, cip->ctl_id, (int)count, buf);
+	ret = store_val_any(cip, 0, buf, count);
 	if (!ret) ret = count;
 	return ret;
 }
 
-static ssize_t store_val_custom(int id,struct device *class_dev,
-				const char *buf,size_t count)
+static ssize_t store_val_custom(struct device *class_dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
 {
-	struct pvr2_sysfs *sfp;
+	struct pvr2_sysfs_ctl_item *cip;
 	int ret;
-	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
 	pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",
-			 sfp,id,(int)count,buf);
-	ret = store_val_any(id,1,sfp,buf,count);
+			 cip->chptr, cip->ctl_id, (int)count, buf);
+	ret = store_val_any(cip, 1, buf, count);
 	if (!ret) ret = count;
 	return ret;
 }
 
-/*
-  Mike Isely <isely@pobox.com> 30-April-2005
-
-  This next batch of horrible preprocessor hackery is needed because the
-  kernel's device_attribute mechanism fails to pass the actual
-  attribute through to the show / store functions, which means we have no
-  way to package up any attribute-specific parameters, like for example the
-  control id.  So we work around this brain-damage by encoding the control
-  id into the show / store functions themselves and pick the function based
-  on the control id we're setting up.  These macros try to ease the pain.
-  Yuck.
-*/
-
-#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
-struct device_attribute *attr, char *buf) \
-{ return sf_name(ctl_id,class_dev,buf); }
-
-#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
-struct device_attribute *attr, const char *buf, size_t count) \
-{ return sf_name(ctl_id,class_dev,buf,count); }
-
-#define CREATE_BATCH(ctl_id) \
-CREATE_SHOW_INSTANCE(show_name,ctl_id) \
-CREATE_SHOW_INSTANCE(show_type,ctl_id) \
-CREATE_SHOW_INSTANCE(show_min,ctl_id) \
-CREATE_SHOW_INSTANCE(show_max,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
-CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
-CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
-
-CREATE_BATCH(0)
-CREATE_BATCH(1)
-CREATE_BATCH(2)
-CREATE_BATCH(3)
-CREATE_BATCH(4)
-CREATE_BATCH(5)
-CREATE_BATCH(6)
-CREATE_BATCH(7)
-CREATE_BATCH(8)
-CREATE_BATCH(9)
-CREATE_BATCH(10)
-CREATE_BATCH(11)
-CREATE_BATCH(12)
-CREATE_BATCH(13)
-CREATE_BATCH(14)
-CREATE_BATCH(15)
-CREATE_BATCH(16)
-CREATE_BATCH(17)
-CREATE_BATCH(18)
-CREATE_BATCH(19)
-CREATE_BATCH(20)
-CREATE_BATCH(21)
-CREATE_BATCH(22)
-CREATE_BATCH(23)
-CREATE_BATCH(24)
-CREATE_BATCH(25)
-CREATE_BATCH(26)
-CREATE_BATCH(27)
-CREATE_BATCH(28)
-CREATE_BATCH(29)
-CREATE_BATCH(30)
-CREATE_BATCH(31)
-CREATE_BATCH(32)
-CREATE_BATCH(33)
-CREATE_BATCH(34)
-CREATE_BATCH(35)
-CREATE_BATCH(36)
-CREATE_BATCH(37)
-CREATE_BATCH(38)
-CREATE_BATCH(39)
-CREATE_BATCH(40)
-CREATE_BATCH(41)
-CREATE_BATCH(42)
-CREATE_BATCH(43)
-CREATE_BATCH(44)
-CREATE_BATCH(45)
-CREATE_BATCH(46)
-CREATE_BATCH(47)
-CREATE_BATCH(48)
-CREATE_BATCH(49)
-CREATE_BATCH(50)
-CREATE_BATCH(51)
-CREATE_BATCH(52)
-CREATE_BATCH(53)
-CREATE_BATCH(54)
-CREATE_BATCH(55)
-CREATE_BATCH(56)
-CREATE_BATCH(57)
-CREATE_BATCH(58)
-CREATE_BATCH(59)
-
-struct pvr2_sysfs_func_set {
-	ssize_t (*show_name)(struct device *,
-			     struct device_attribute *attr, char *);
-	ssize_t (*show_type)(struct device *,
-			     struct device_attribute *attr, char *);
-	ssize_t (*show_min)(struct device *,
-			    struct device_attribute *attr, char *);
-	ssize_t (*show_max)(struct device *,
-			    struct device_attribute *attr, char *);
-	ssize_t (*show_enum)(struct device *,
-			     struct device_attribute *attr, char *);
-	ssize_t (*show_bits)(struct device *,
-			     struct device_attribute *attr, char *);
-	ssize_t (*show_val_norm)(struct device *,
-				 struct device_attribute *attr, char *);
-	ssize_t (*store_val_norm)(struct device *,
-				  struct device_attribute *attr,
-				  const char *,size_t);
-	ssize_t (*show_val_custom)(struct device *,
-				   struct device_attribute *attr, char *);
-	ssize_t (*store_val_custom)(struct device *,
-				    struct device_attribute *attr,
-				    const char *,size_t);
-};
-
-#define INIT_BATCH(ctl_id) \
-[ctl_id] = { \
-    .show_name = show_name_##ctl_id, \
-    .show_type = show_type_##ctl_id, \
-    .show_min = show_min_##ctl_id, \
-    .show_max = show_max_##ctl_id, \
-    .show_enum = show_enum_##ctl_id, \
-    .show_bits = show_bits_##ctl_id, \
-    .show_val_norm = show_val_norm_##ctl_id, \
-    .store_val_norm = store_val_norm_##ctl_id, \
-    .show_val_custom = show_val_custom_##ctl_id, \
-    .store_val_custom = store_val_custom_##ctl_id, \
-} \
-
-static struct pvr2_sysfs_func_set funcs[] = {
-	INIT_BATCH(0),
-	INIT_BATCH(1),
-	INIT_BATCH(2),
-	INIT_BATCH(3),
-	INIT_BATCH(4),
-	INIT_BATCH(5),
-	INIT_BATCH(6),
-	INIT_BATCH(7),
-	INIT_BATCH(8),
-	INIT_BATCH(9),
-	INIT_BATCH(10),
-	INIT_BATCH(11),
-	INIT_BATCH(12),
-	INIT_BATCH(13),
-	INIT_BATCH(14),
-	INIT_BATCH(15),
-	INIT_BATCH(16),
-	INIT_BATCH(17),
-	INIT_BATCH(18),
-	INIT_BATCH(19),
-	INIT_BATCH(20),
-	INIT_BATCH(21),
-	INIT_BATCH(22),
-	INIT_BATCH(23),
-	INIT_BATCH(24),
-	INIT_BATCH(25),
-	INIT_BATCH(26),
-	INIT_BATCH(27),
-	INIT_BATCH(28),
-	INIT_BATCH(29),
-	INIT_BATCH(30),
-	INIT_BATCH(31),
-	INIT_BATCH(32),
-	INIT_BATCH(33),
-	INIT_BATCH(34),
-	INIT_BATCH(35),
-	INIT_BATCH(36),
-	INIT_BATCH(37),
-	INIT_BATCH(38),
-	INIT_BATCH(39),
-	INIT_BATCH(40),
-	INIT_BATCH(41),
-	INIT_BATCH(42),
-	INIT_BATCH(43),
-	INIT_BATCH(44),
-	INIT_BATCH(45),
-	INIT_BATCH(46),
-	INIT_BATCH(47),
-	INIT_BATCH(48),
-	INIT_BATCH(49),
-	INIT_BATCH(50),
-	INIT_BATCH(51),
-	INIT_BATCH(52),
-	INIT_BATCH(53),
-	INIT_BATCH(54),
-	INIT_BATCH(55),
-	INIT_BATCH(56),
-	INIT_BATCH(57),
-	INIT_BATCH(58),
-	INIT_BATCH(59),
-};
-
-
 static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
 {
 	struct pvr2_sysfs_ctl_item *cip;
-	struct pvr2_sysfs_func_set *fp;
 	struct pvr2_ctrl *cptr;
 	unsigned int cnt,acnt;
 	int ret;
 
-	if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
-		return;
-	}
-
-	fp = funcs + ctl_id;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
 	if (!cptr) return;
 
@@ -527,6 +293,7 @@
 	pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
 
 	cip->cptr = cptr;
+	cip->ctl_id = ctl_id;
 
 	cip->chptr = sfp;
 	cip->item_next = NULL;
@@ -539,19 +306,19 @@
 
 	cip->attr_name.attr.name = "name";
 	cip->attr_name.attr.mode = S_IRUGO;
-	cip->attr_name.show = fp->show_name;
+	cip->attr_name.show = show_name;
 
 	cip->attr_type.attr.name = "type";
 	cip->attr_type.attr.mode = S_IRUGO;
-	cip->attr_type.show = fp->show_type;
+	cip->attr_type.show = show_type;
 
 	cip->attr_min.attr.name = "min_val";
 	cip->attr_min.attr.mode = S_IRUGO;
-	cip->attr_min.show = fp->show_min;
+	cip->attr_min.show = show_min;
 
 	cip->attr_max.attr.name = "max_val";
 	cip->attr_max.attr.mode = S_IRUGO;
-	cip->attr_max.show = fp->show_max;
+	cip->attr_max.show = show_max;
 
 	cip->attr_val.attr.name = "cur_val";
 	cip->attr_val.attr.mode = S_IRUGO;
@@ -561,11 +328,11 @@
 
 	cip->attr_enum.attr.name = "enum_val";
 	cip->attr_enum.attr.mode = S_IRUGO;
-	cip->attr_enum.show = fp->show_enum;
+	cip->attr_enum.show = show_enum;
 
 	cip->attr_bits.attr.name = "bit_val";
 	cip->attr_bits.attr.mode = S_IRUGO;
-	cip->attr_bits.show = fp->show_bits;
+	cip->attr_bits.show = show_bits;
 
 	if (pvr2_ctrl_is_writable(cptr)) {
 		cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
@@ -576,12 +343,12 @@
 	cip->attr_gen[acnt++] = &cip->attr_name.attr;
 	cip->attr_gen[acnt++] = &cip->attr_type.attr;
 	cip->attr_gen[acnt++] = &cip->attr_val.attr;
-	cip->attr_val.show = fp->show_val_norm;
-	cip->attr_val.store = fp->store_val_norm;
+	cip->attr_val.show = show_val_norm;
+	cip->attr_val.store = store_val_norm;
 	if (pvr2_ctrl_has_custom_symbols(cptr)) {
 		cip->attr_gen[acnt++] = &cip->attr_custom.attr;
-		cip->attr_custom.show = fp->show_val_custom;
-		cip->attr_custom.store = fp->store_val_custom;
+		cip->attr_custom.show = show_val_custom;
+		cip->attr_custom.store = store_val_custom;
 	}
 	switch (pvr2_ctrl_get_type(cptr)) {
 	case pvr2_ctl_enum:
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
index ff9373b..6d875bf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index 05e65ce..07775d1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
index 556f12a..ef4afaf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h
index e53aee4..92b7554 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-util.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-util.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index e9b5d4e..0d72dc4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
index 9a995e2..34c011a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 2433a31..4059648 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
index 2b917fd..4ff5b89 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index 66b4d36..f6fcf0a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
index 8aaeff4..8070909 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h
index 1a9a4ba..240de9b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2.h
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index ea53316..1cccd5c 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1255,7 +1255,6 @@
    exactly the same otherwise.
  */
 
-
 /* define local variable for arg */
 #define ARG_DEF(ARG_type, ARG_name)\
 	ARG_type *ARG_name = arg;
@@ -1268,7 +1267,6 @@
 /* copy local variable to arg */
 #define ARG_OUT(ARG_name) /* nothing */
 
-
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
 	int ret = 0;
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
index cec6602..8c0cae7 100644
--- a/drivers/media/video/pwc/pwc-ioctl.h
+++ b/drivers/media/video/pwc/pwc-ioctl.h
@@ -54,7 +54,6 @@
 #include <linux/types.h>
 #include <linux/version.h>
 
-
  /* Enumeration of image sizes */
 #define PSZ_SQCIF	0x00
 #define PSZ_QSIF	0x01
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 5ec5bb9..b15f82c 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -30,6 +30,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
+#include <media/videobuf-dma-sg.h>
 #include <media/soc_camera.h>
 
 #include <linux/videodev2.h>
@@ -582,6 +583,19 @@
 	.buf_release    = pxa_videobuf_release,
 };
 
+static void pxa_camera_init_videobuf(struct videobuf_queue *q,
+			      struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	/* We must pass NULL as dev pointer, then all pci_* dma operations
+	 * transform to normal dma_* ones. */
+	videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				sizeof(struct pxa_buffer), icd);
+}
+
 static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
 {
 	unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
@@ -983,34 +997,23 @@
 	return 0;
 }
 
-static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf)
-{
-	struct soc_camera_host *ici =
-		to_soc_camera_host(icf->icd->dev.parent);
-	struct pxa_camera_dev *pcdev = ici->priv;
-
-	return &pcdev->lock;
-}
-
 static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
 	.owner		= THIS_MODULE,
 	.add		= pxa_camera_add_device,
 	.remove		= pxa_camera_remove_device,
 	.set_fmt_cap	= pxa_camera_set_fmt_cap,
 	.try_fmt_cap	= pxa_camera_try_fmt_cap,
+	.init_videobuf	= pxa_camera_init_videobuf,
 	.reqbufs	= pxa_camera_reqbufs,
 	.poll		= pxa_camera_poll,
 	.querycap	= pxa_camera_querycap,
 	.try_bus_param	= pxa_camera_try_bus_param,
 	.set_bus_param	= pxa_camera_set_bus_param,
-	.spinlock_alloc	= pxa_camera_spinlock_alloc,
 };
 
 /* Should be allocated dynamically too, but we have only one. */
 static struct soc_camera_host pxa_soc_camera_host = {
 	.drv_name		= PXA_CAM_DRV_NAME,
-	.vbq_ops		= &pxa_videobuf_ops,
-	.msize			= sizeof(struct pxa_buffer),
 	.ops			= &pxa_soc_camera_host_ops,
 };
 
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
new file mode 100644
index 0000000..04eb2c3
--- /dev/null
+++ b/drivers/media/video/s2255drv.c
@@ -0,0 +1,2495 @@
+/*
+ *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device
+ *
+ *   Copyright (C) 2007-2008 by Sensoray Company Inc.
+ *                              Dean Anderson
+ *
+ * Some video buffer code based on vivi driver:
+ *
+ * Sensoray 2255 device supports 4 simultaneous channels.
+ * The channels are not "crossbar" inputs, they are physically
+ * attached to separate video decoders.
+ *
+ * Because of USB2.0 bandwidth limitations. There is only a
+ * certain amount of data which may be transferred at one time.
+ *
+ * Example maximum bandwidth utilization:
+ *
+ * -full size, color mode YUYV or YUV422P: 2 channels at once
+ *
+ * -full or half size Grey scale: all 4 channels at once
+ *
+ * -half size, color mode YUYV or YUV422P: all 4 channels at once
+ *
+ * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
+ *  at once.
+ *  (TODO: Incorporate videodev2 frame rate(FR) enumeration,
+ *  which is currently experimental.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-common.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#define FIRMWARE_FILE_NAME "f2255usb.bin"
+
+
+
+/* vendor request in */
+#define S2255_VR_IN		0
+/* vendor request out */
+#define S2255_VR_OUT		1
+/* firmware query */
+#define S2255_VR_FW		0x30
+/* USB endpoint number for configuring the device */
+#define S2255_CONFIG_EP         2
+/* maximum time for DSP to start responding after last FW word loaded(ms) */
+#define S2255_DSP_BOOTTIME      400
+/* maximum time to wait for firmware to load (ms) */
+#define S2255_LOAD_TIMEOUT      (5000 + S2255_DSP_BOOTTIME)
+#define S2255_DEF_BUFS          16
+#define MAX_CHANNELS		4
+#define FRAME_MARKER		0x2255DA4AL
+#define MAX_PIPE_USBBLOCK	(40 * 1024)
+#define DEFAULT_PIPE_USBBLOCK	(16 * 1024)
+#define MAX_CHANNELS		4
+#define MAX_PIPE_BUFFERS	1
+#define SYS_FRAMES		4
+/* maximum size is PAL full size plus room for the marker header(s) */
+#define SYS_FRAMES_MAXSIZE	(720 * 288 * 2 * 2 + 4096)
+#define DEF_USB_BLOCK		(4096)
+#define LINE_SZ_4CIFS_NTSC	640
+#define LINE_SZ_2CIFS_NTSC	640
+#define LINE_SZ_1CIFS_NTSC	320
+#define LINE_SZ_4CIFS_PAL	704
+#define LINE_SZ_2CIFS_PAL	704
+#define LINE_SZ_1CIFS_PAL	352
+#define NUM_LINES_4CIFS_NTSC	240
+#define NUM_LINES_2CIFS_NTSC	240
+#define NUM_LINES_1CIFS_NTSC	240
+#define NUM_LINES_4CIFS_PAL	288
+#define NUM_LINES_2CIFS_PAL	288
+#define NUM_LINES_1CIFS_PAL	288
+#define LINE_SZ_DEF		640
+#define NUM_LINES_DEF		240
+
+
+/* predefined settings */
+#define FORMAT_NTSC	1
+#define FORMAT_PAL	2
+
+#define SCALE_4CIFS	1	/* 640x480(NTSC) or 704x576(PAL) */
+#define SCALE_2CIFS	2	/* 640x240(NTSC) or 704x288(PAL) */
+#define SCALE_1CIFS	3	/* 320x240(NTSC) or 352x288(PAL) */
+
+#define COLOR_YUVPL	1	/* YUV planar */
+#define COLOR_YUVPK	2	/* YUV packed */
+#define COLOR_Y8	4	/* monochrome */
+
+/* frame decimation. Not implemented by V4L yet(experimental in V4L) */
+#define FDEC_1		1	/* capture every frame. default */
+#define FDEC_2		2	/* capture every 2nd frame */
+#define FDEC_3		3	/* capture every 3rd frame */
+#define FDEC_5		5	/* capture every 5th frame */
+
+/*-------------------------------------------------------
+ * Default mode parameters.
+ *-------------------------------------------------------*/
+#define DEF_SCALE	SCALE_4CIFS
+#define DEF_COLOR	COLOR_YUVPL
+#define DEF_FDEC	FDEC_1
+#define DEF_BRIGHT	0
+#define DEF_CONTRAST	0x5c
+#define DEF_SATURATION	0x80
+#define DEF_HUE		0
+
+/* usb config commands */
+#define IN_DATA_TOKEN	0x2255c0de
+#define CMD_2255	0xc2255000
+#define CMD_SET_MODE	(CMD_2255 | 0x10)
+#define CMD_START	(CMD_2255 | 0x20)
+#define CMD_STOP	(CMD_2255 | 0x30)
+#define CMD_STATUS	(CMD_2255 | 0x40)
+
+struct s2255_mode {
+	u32 format;	/* input video format (NTSC, PAL) */
+	u32 scale;	/* output video scale */
+	u32 color;	/* output video color format */
+	u32 fdec;	/* frame decimation */
+	u32 bright;	/* brightness */
+	u32 contrast;	/* contrast */
+	u32 saturation;	/* saturation */
+	u32 hue;	/* hue (NTSC only)*/
+	u32 single;	/* capture 1 frame at a time (!=0), continuously (==0)*/
+	u32 usb_block;	/* block size. should be 4096 of DEF_USB_BLOCK */
+	u32 restart;	/* if DSP requires restart */
+};
+
+/* frame structure */
+#define FRAME_STATE_UNUSED	0
+#define FRAME_STATE_FILLING	1
+#define FRAME_STATE_FULL	2
+
+
+struct s2255_framei {
+	unsigned long size;
+
+	unsigned long ulState;	/* ulState ==0 unused, 1 being filled, 2 full */
+	void *lpvbits;		/* image data */
+	unsigned long cur_size;	/* current data copied to it */
+};
+
+/* image buffer structure */
+struct s2255_bufferi {
+	unsigned long dwFrames;			/* number of frames in buffer */
+	struct s2255_framei frame[SYS_FRAMES];	/* array of FRAME structures */
+};
+
+#define DEF_MODEI_NTSC_CONT	{FORMAT_NTSC, DEF_SCALE, DEF_COLOR,	\
+			DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
+			DEF_HUE, 0, DEF_USB_BLOCK, 0}
+
+struct s2255_dmaqueue {
+	struct list_head	active;
+	/* thread for acquisition */
+	struct task_struct	*kthread;
+	int			frame;
+	struct s2255_dev	*dev;
+	int			channel;
+};
+
+/* for firmware loading, fw_state */
+#define S2255_FW_NOTLOADED	0
+#define S2255_FW_LOADED_DSPWAIT	1
+#define S2255_FW_SUCCESS	2
+#define S2255_FW_FAILED		3
+
+struct s2255_fw {
+	int		      fw_loaded;
+	int		      fw_size;
+	struct urb	      *fw_urb;
+	atomic_t	      fw_state;
+	void		      *pfw_data;
+	wait_queue_head_t     wait_fw;
+	struct timer_list     dsp_wait;
+	const struct firmware *fw;
+};
+
+struct s2255_pipeinfo {
+	u32 max_transfer_size;
+	u32 cur_transfer_size;
+	u8 *transfer_buffer;
+	u32 transfer_flags;;
+	u32 state;
+	u32 prev_state;
+	u32 urb_size;
+	void *stream_urb;
+	void *dev;	/* back pointer to s2255_dev struct*/
+	u32 err_count;
+	u32 buf_index;
+	u32 idx;
+	u32 priority_set;
+};
+
+struct s2255_fmt; /*forward declaration */
+
+struct s2255_dev {
+	int			frames;
+	int			users[MAX_CHANNELS];
+	struct mutex		lock;
+	struct mutex		open_lock;
+	int			resources[MAX_CHANNELS];
+	struct usb_device	*udev;
+	struct usb_interface	*interface;
+	u8			read_endpoint;
+
+	struct s2255_dmaqueue	vidq[MAX_CHANNELS];
+	struct video_device	*vdev[MAX_CHANNELS];
+	struct list_head	s2255_devlist;
+	struct timer_list	timer;
+	struct s2255_fw	*fw_data;
+	int			board_num;
+	int			is_open;
+	struct s2255_pipeinfo	pipes[MAX_PIPE_BUFFERS];
+	struct s2255_bufferi		buffer[MAX_CHANNELS];
+	struct s2255_mode	mode[MAX_CHANNELS];
+	const struct s2255_fmt	*cur_fmt[MAX_CHANNELS];
+	int			cur_frame[MAX_CHANNELS];
+	int			last_frame[MAX_CHANNELS];
+	u32			cc;	/* current channel */
+	int			b_acquire[MAX_CHANNELS];
+	unsigned long		req_image_size[MAX_CHANNELS];
+	int			bad_payload[MAX_CHANNELS];
+	unsigned long		frame_count[MAX_CHANNELS];
+	int			frame_ready;
+	struct kref		kref;
+	spinlock_t              slock;
+};
+#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref)
+
+struct s2255_fmt {
+	char *name;
+	u32 fourcc;
+	int depth;
+};
+
+/* buffer for one video frame */
+struct s2255_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+	const struct s2255_fmt *fmt;
+};
+
+struct s2255_fh {
+	struct s2255_dev	*dev;
+	unsigned int		resources;
+	const struct s2255_fmt	*fmt;
+	unsigned int		width;
+	unsigned int		height;
+	struct videobuf_queue	vb_vidq;
+	enum v4l2_buf_type	type;
+	int			channel;
+	/* mode below is the desired mode.
+	   mode in s2255_dev is the current mode that was last set */
+	struct s2255_mode	mode;
+};
+
+/*
+ * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles.
+ * Limit V4L to one stream at a time.
+ */
+#define S2255_MAX_USERS         1
+
+#define CUR_USB_FWVER	774	/* current cypress EEPROM firmware version */
+#define S2255_MAJOR_VERSION	1
+#define S2255_MINOR_VERSION	13
+#define S2255_RELEASE		0
+#define S2255_VERSION		KERNEL_VERSION(S2255_MAJOR_VERSION, \
+					       S2255_MINOR_VERSION, \
+					       S2255_RELEASE)
+
+/* vendor ids */
+#define USB_S2255_VENDOR_ID	0x1943
+#define USB_S2255_PRODUCT_ID	0x2255
+#define S2255_NORMS		(V4L2_STD_PAL | V4L2_STD_NTSC)
+/* frame prefix size (sent once every frame) */
+#define PREFIX_SIZE		512
+
+/* Channels on box are in reverse order */
+static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
+
+static LIST_HEAD(s2255_devlist);
+
+static int debug;
+static int *s2255_debug = &debug;
+
+static int s2255_start_readpipe(struct s2255_dev *dev);
+static void s2255_stop_readpipe(struct s2255_dev *dev);
+static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
+static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
+static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
+			   int chn);
+static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+			  struct s2255_mode *mode);
+static int s2255_board_shutdown(struct s2255_dev *dev);
+static void s2255_exit_v4l(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev);
+
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (*s2255_debug >= (level)) {				\
+			printk(KERN_DEBUG "s2255: " fmt, ##arg);	\
+		}							\
+	} while (0)
+
+
+static struct usb_driver s2255_driver;
+
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+
+/* start video number */
+static int video_nr = -1;	/* /dev/videoN, -1 for autodetect */
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
+module_param(video_nr, int, 0644);
+MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+
+/* USB device table */
+static struct usb_device_id s2255_table[] = {
+	{USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)},
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, s2255_table);
+
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(400)
+
+/* supported controls */
+static struct v4l2_queryctrl s2255_qctrl[] = {
+	{
+	.id = V4L2_CID_BRIGHTNESS,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Brightness",
+	.minimum = -127,
+	.maximum = 128,
+	.step = 1,
+	.default_value = 0,
+	.flags = 0,
+	}, {
+	.id = V4L2_CID_CONTRAST,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Contrast",
+	.minimum = 0,
+	.maximum = 255,
+	.step = 0x1,
+	.default_value = DEF_CONTRAST,
+	.flags = 0,
+	}, {
+	.id = V4L2_CID_SATURATION,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Saturation",
+	.minimum = 0,
+	.maximum = 255,
+	.step = 0x1,
+	.default_value = DEF_SATURATION,
+	.flags = 0,
+	}, {
+	.id = V4L2_CID_HUE,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Hue",
+	.minimum = 0,
+	.maximum = 255,
+	.step = 0x1,
+	.default_value = DEF_HUE,
+	.flags = 0,
+	}
+};
+
+static int qctl_regs[ARRAY_SIZE(s2255_qctrl)];
+
+/* image formats.  */
+static const struct s2255_fmt formats[] = {
+	{
+		.name = "4:2:2, planar, YUV422P",
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.depth = 16
+
+	}, {
+		.name = "4:2:2, packed, YUYV",
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.depth = 16
+
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.depth = 16
+	}, {
+		.name = "8bpp GREY",
+		.fourcc = V4L2_PIX_FMT_GREY,
+		.depth = 8
+	}
+};
+
+static int norm_maxw(struct video_device *vdev)
+{
+	return (vdev->current_norm & V4L2_STD_NTSC) ?
+	    LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
+}
+
+static int norm_maxh(struct video_device *vdev)
+{
+	return (vdev->current_norm & V4L2_STD_NTSC) ?
+	    (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
+}
+
+static int norm_minw(struct video_device *vdev)
+{
+	return (vdev->current_norm & V4L2_STD_NTSC) ?
+	    LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
+}
+
+static int norm_minh(struct video_device *vdev)
+{
+	return (vdev->current_norm & V4L2_STD_NTSC) ?
+	    (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
+}
+
+
+/*
+ * TODO: fixme: move YUV reordering to hardware
+ * converts 2255 planar format to yuyv or uyvy
+ */
+static void planar422p_to_yuv_packed(const unsigned char *in,
+				     unsigned char *out,
+				     int width, int height,
+				     int fmt)
+{
+	unsigned char *pY;
+	unsigned char *pCb;
+	unsigned char *pCr;
+	unsigned long size = height * width;
+	unsigned int i;
+	pY = (unsigned char *)in;
+	pCr = (unsigned char *)in + height * width;
+	pCb = (unsigned char *)in + height * width + (height * width / 2);
+	for (i = 0; i < size * 2; i += 4) {
+		out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;
+		out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;
+		out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;
+		out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;
+	}
+	return;
+}
+
+
+/* kickstarts the firmware loading. from probe
+ */
+static void s2255_timer(unsigned long user_data)
+{
+	struct s2255_fw *data = (struct s2255_fw *)user_data;
+	dprintk(100, "s2255 timer\n");
+	if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+		printk(KERN_ERR "s2255: can't submit urb\n");
+		if (data->fw) {
+			release_firmware(data->fw);
+			data->fw = NULL;
+		}
+		return;
+	}
+}
+
+/* called when DSP is up and running.  DSP is guaranteed to
+   be running after S2255_DSP_BOOTTIME */
+static void s2255_dsp_running(unsigned long user_data)
+{
+	struct s2255_fw *data = (struct s2255_fw *)user_data;
+	dprintk(1, "dsp running\n");
+	atomic_set(&data->fw_state, S2255_FW_SUCCESS);
+	wake_up(&data->wait_fw);
+	printk(KERN_INFO "s2255: firmware loaded successfully\n");
+	return;
+}
+
+
+/* this loads the firmware asynchronously.
+   Originally this was done synchroously in probe.
+   But it is better to load it asynchronously here than block
+   inside the probe function. Blocking inside probe affects boot time.
+   FW loading is triggered by the timer in the probe function
+*/
+static void s2255_fwchunk_complete(struct urb *urb)
+{
+	struct s2255_fw *data = urb->context;
+	struct usb_device *udev = urb->dev;
+	int len;
+	dprintk(100, "udev %p urb %p", udev, urb);
+	/* TODO: fixme.  reflect change in status */
+	if (urb->status) {
+		dev_err(&udev->dev, "URB failed with status %d", urb->status);
+		return;
+	}
+	if (data->fw_urb == NULL) {
+		dev_err(&udev->dev, "early disconncect\n");
+		return;
+	}
+#define CHUNK_SIZE 512
+	/* all USB transfers must be done with continuous kernel memory.
+	   can't allocate more than 128k in current linux kernel, so
+	   upload the firmware in chunks
+	 */
+	if (data->fw_loaded < data->fw_size) {
+		len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ?
+		    data->fw_size % CHUNK_SIZE : CHUNK_SIZE;
+
+		if (len < CHUNK_SIZE)
+			memset(data->pfw_data, 0, CHUNK_SIZE);
+
+		dprintk(100, "completed len %d, loaded %d \n", len,
+			data->fw_loaded);
+
+		memcpy(data->pfw_data,
+		       (char *) data->fw->data + data->fw_loaded, len);
+
+		usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2),
+				  data->pfw_data, CHUNK_SIZE,
+				  s2255_fwchunk_complete, data);
+		if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+			dev_err(&udev->dev, "failed submit URB\n");
+			atomic_set(&data->fw_state, S2255_FW_FAILED);
+			/* wake up anything waiting for the firmware */
+			wake_up(&data->wait_fw);
+			return;
+		}
+		data->fw_loaded += len;
+	} else {
+		init_timer(&data->dsp_wait);
+		data->dsp_wait.function = s2255_dsp_running;
+		data->dsp_wait.data = (unsigned long)data;
+		atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
+		mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
+			  + jiffies);
+	}
+	dprintk(100, "2255 complete done\n");
+	return;
+
+}
+
+static int s2255_got_frame(struct s2255_dev *dev, int chn)
+{
+	struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+	struct s2255_buffer *buf;
+	unsigned long flags = 0;
+	int rc = 0;
+	dprintk(2, "wakeup: %p channel: %d\n", &dma_q, chn);
+	spin_lock_irqsave(&dev->slock, flags);
+
+	if (list_empty(&dma_q->active)) {
+		dprintk(1, "No active queue to serve\n");
+		rc = -1;
+		goto unlock;
+	}
+	buf = list_entry(dma_q->active.next,
+			 struct s2255_buffer, vb.queue);
+
+	if (!waitqueue_active(&buf->vb.done)) {
+		/* no one active */
+		rc = -1;
+		goto unlock;
+	}
+	list_del(&buf->vb.queue);
+	do_gettimeofday(&buf->vb.ts);
+	dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
+
+	s2255_fillbuff(dev, buf, dma_q->channel);
+	wake_up(&buf->vb.done);
+	dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+	spin_unlock_irqrestore(&dev->slock, flags);
+	return 0;
+}
+
+
+static const struct s2255_fmt *format_by_fourcc(int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (-1 == formats[i].fourcc)
+			continue;
+		if (formats[i].fourcc == fourcc)
+			return formats + i;
+	}
+	return NULL;
+}
+
+
+
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ *          Copyright (c) 2006 by
+ *                  Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ *                  Ted Walther <ted--a.t--enumera.com>
+ *                  John Sokol <sokol--a.t--videotechnology.com>
+ *                  http://v4l.videotechnology.com/
+ *
+ */
+static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
+			   int chn)
+{
+	int pos = 0;
+	struct timeval ts;
+	const char *tmpbuf;
+	char *vbuf = videobuf_to_vmalloc(&buf->vb);
+	unsigned long last_frame;
+	struct s2255_framei *frm;
+
+	if (!vbuf)
+		return;
+
+	last_frame = dev->last_frame[chn];
+	if (last_frame != -1) {
+		frm = &dev->buffer[chn].frame[last_frame];
+		tmpbuf =
+		    (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+		switch (buf->fmt->fourcc) {
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_UYVY:
+			planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
+						 vbuf, buf->vb.width,
+						 buf->vb.height,
+						 buf->fmt->fourcc);
+			break;
+		case V4L2_PIX_FMT_GREY:
+			memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+			break;
+		case V4L2_PIX_FMT_YUV422P:
+			memcpy(vbuf, tmpbuf,
+			       buf->vb.width * buf->vb.height * 2);
+			break;
+		default:
+			printk(KERN_DEBUG "s2255: unknown format?\n");
+		}
+		dev->last_frame[chn] = -1;
+		/* done with the frame, free it */
+		frm->ulState = 0;
+		dprintk(4, "freeing buffer\n");
+	} else {
+		printk(KERN_ERR "s2255: =======no frame\n");
+		return;
+
+	}
+	dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
+		(unsigned long)vbuf, pos);
+	/* tell v4l buffer was filled */
+
+	buf->vb.field_count++;
+	do_gettimeofday(&ts);
+	buf->vb.ts = ts;
+	buf->vb.state = VIDEOBUF_DONE;
+}
+
+
+/* ------------------------------------------------------------------
+   Videobuf operations
+   ------------------------------------------------------------------*/
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+			unsigned int *size)
+{
+	struct s2255_fh *fh = vq->priv_data;
+
+	*size = fh->width * fh->height * (fh->fmt->depth >> 3);
+
+	if (0 == *count)
+		*count = S2255_DEF_BUFS;
+
+	while (*size * (*count) > vid_limit * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
+{
+	dprintk(4, "%s\n", __func__);
+
+	videobuf_waiton(&buf->vb, 0, 0);
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct s2255_fh *fh = vq->priv_data;
+	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+	int rc;
+	dprintk(4, "%s, field=%d\n", __func__, field);
+	if (fh->fmt == NULL)
+		return -EINVAL;
+
+	if ((fh->width < norm_minw(fh->dev->vdev[fh->channel])) ||
+	    (fh->width > norm_maxw(fh->dev->vdev[fh->channel])) ||
+	    (fh->height < norm_minh(fh->dev->vdev[fh->channel])) ||
+	    (fh->height > norm_maxh(fh->dev->vdev[fh->channel]))) {
+		dprintk(4, "invalid buffer prepare\n");
+		return -EINVAL;
+	}
+
+	buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
+
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
+		dprintk(4, "invalid buffer prepare\n");
+		return -EINVAL;
+	}
+
+	buf->fmt = fh->fmt;
+	buf->vb.width = fh->width;
+	buf->vb.height = fh->height;
+	buf->vb.field = field;
+
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+	struct s2255_fh *fh = vq->priv_data;
+	struct s2255_dev *dev = fh->dev;
+	struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+
+	dprintk(1, "%s\n", __func__);
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+			   struct videobuf_buffer *vb)
+{
+	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+	struct s2255_fh *fh = vq->priv_data;
+	dprintk(4, "%s %d\n", __func__, fh->channel);
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops s2255_video_qops = {
+	.buf_setup = buffer_setup,
+	.buf_prepare = buffer_prepare,
+	.buf_queue = buffer_queue,
+	.buf_release = buffer_release,
+};
+
+
+static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources[fh->channel]) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	dev->resources[fh->channel] = 1;
+	dprintk(1, "res: get\n");
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+	return dev->resources[fh->channel];
+}
+
+static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+	dev->resources[fh->channel] = 0;
+	dprintk(1, "res: put\n");
+}
+
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	struct s2255_fh *fh = file->private_data;
+	struct s2255_dev *dev = fh->dev;
+	strlcpy(cap->driver, "s2255", sizeof(cap->driver));
+	strlcpy(cap->card, "s2255", sizeof(cap->card));
+	strlcpy(cap->bus_info, dev_name(&dev->udev->dev),
+		sizeof(cap->bus_info));
+	cap->version = S2255_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+			       struct v4l2_fmtdesc *f)
+{
+	int index = 0;
+	if (f)
+		index = f->index;
+
+	if (index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	dprintk(4, "name %s\n", formats[index].name);
+	strlcpy(f->description, formats[index].name, sizeof(f->description));
+	f->pixelformat = formats[index].fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct s2255_fh *fh = priv;
+
+	f->fmt.pix.width = fh->width;
+	f->fmt.pix.height = fh->height;
+	f->fmt.pix.field = fh->vb_vidq.field;
+	f->fmt.pix.pixelformat = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			      struct v4l2_format *f)
+{
+	const struct s2255_fmt *fmt;
+	enum v4l2_field field;
+	int  b_any_field = 0;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	int is_ntsc;
+
+	is_ntsc =
+	    (dev->vdev[fh->channel]->current_norm & V4L2_STD_NTSC) ? 1 : 0;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	if (field == V4L2_FIELD_ANY)
+		b_any_field = 1;
+
+	dprintk(4, "try format %d \n", is_ntsc);
+	/* supports 3 sizes. see s2255drv.h */
+	dprintk(50, "width test %d, height %d\n",
+		f->fmt.pix.width, f->fmt.pix.height);
+	if (is_ntsc) {
+		/* NTSC */
+		if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
+			f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
+			if (b_any_field) {
+				field = V4L2_FIELD_SEQ_TB;
+			} else if (!((field == V4L2_FIELD_INTERLACED) ||
+				      (field == V4L2_FIELD_SEQ_TB) ||
+				      (field == V4L2_FIELD_INTERLACED_TB))) {
+				dprintk(1, "unsupported field setting\n");
+				return -EINVAL;
+			}
+		} else {
+			f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
+			if (b_any_field) {
+				field = V4L2_FIELD_TOP;
+			} else if (!((field == V4L2_FIELD_TOP) ||
+				      (field == V4L2_FIELD_BOTTOM))) {
+				dprintk(1, "unsupported field setting\n");
+				return -EINVAL;
+			}
+
+		}
+		if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
+			f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
+		else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
+			f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
+		else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
+			f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+		else
+			f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+	} else {
+		/* PAL */
+		if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
+			f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
+			if (b_any_field) {
+				field = V4L2_FIELD_SEQ_TB;
+			} else if (!((field == V4L2_FIELD_INTERLACED) ||
+				      (field == V4L2_FIELD_SEQ_TB) ||
+				      (field == V4L2_FIELD_INTERLACED_TB))) {
+				dprintk(1, "unsupported field setting\n");
+				return -EINVAL;
+			}
+		} else {
+			f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
+			if (b_any_field) {
+				field = V4L2_FIELD_TOP;
+			} else if (!((field == V4L2_FIELD_TOP) ||
+				     (field == V4L2_FIELD_BOTTOM))) {
+				dprintk(1, "unsupported field setting\n");
+				return -EINVAL;
+			}
+		}
+		if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
+			dprintk(50, "pal 704\n");
+			f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
+			field = V4L2_FIELD_SEQ_TB;
+		} else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
+			dprintk(50, "pal 352A\n");
+			f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
+			field = V4L2_FIELD_TOP;
+		} else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
+			dprintk(50, "pal 352B\n");
+			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+			field = V4L2_FIELD_TOP;
+		} else {
+			dprintk(50, "pal 352C\n");
+			f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+			field = V4L2_FIELD_TOP;
+		}
+	}
+
+	dprintk(50, "width %d height %d field %d \n", f->fmt.pix.width,
+		f->fmt.pix.height, f->fmt.pix.field);
+	f->fmt.pix.field = field;
+	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct s2255_fh *fh = priv;
+	const struct s2255_fmt *fmt;
+	struct videobuf_queue *q = &fh->vb_vidq;
+	int ret;
+	int norm;
+
+	ret = vidioc_try_fmt_vid_cap(file, fh, f);
+
+	if (ret < 0)
+		return ret;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	mutex_lock(&q->vb_lock);
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		dprintk(1, "queue busy\n");
+		ret = -EBUSY;
+		goto out_s_fmt;
+	}
+
+	if (res_locked(fh->dev, fh)) {
+		dprintk(1, "can't change format after started\n");
+		ret = -EBUSY;
+		goto out_s_fmt;
+	}
+
+	fh->fmt = fmt;
+	fh->width = f->fmt.pix.width;
+	fh->height = f->fmt.pix.height;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type = f->type;
+	norm = norm_minw(fh->dev->vdev[fh->channel]);
+	if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) {
+		if (fh->height > norm_minh(fh->dev->vdev[fh->channel]))
+			fh->mode.scale = SCALE_4CIFS;
+		else
+			fh->mode.scale = SCALE_2CIFS;
+
+	} else {
+		fh->mode.scale = SCALE_1CIFS;
+	}
+
+	/* color mode */
+	switch (fh->fmt->fourcc) {
+	case V4L2_PIX_FMT_GREY:
+		fh->mode.color = COLOR_Y8;
+		break;
+	case V4L2_PIX_FMT_YUV422P:
+		fh->mode.color = COLOR_YUVPL;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		fh->mode.color = COLOR_YUVPK;
+		break;
+	}
+	ret = 0;
+out_s_fmt:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
+{
+	int rc;
+	struct s2255_fh *fh = priv;
+	rc = videobuf_reqbufs(&fh->vb_vidq, p);
+	return rc;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	int rc;
+	struct s2255_fh *fh = priv;
+	rc = videobuf_querybuf(&fh->vb_vidq, p);
+	return rc;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	int rc;
+	struct s2255_fh *fh = priv;
+	rc = videobuf_qbuf(&fh->vb_vidq, p);
+	return rc;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	int rc;
+	struct s2255_fh *fh = priv;
+	rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
+	return rc;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	struct s2255_fh *fh = priv;
+
+	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+/* write to the configuration pipe, synchronously */
+static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
+			      int size)
+{
+	int pipe;
+	int done;
+	long retval = -1;
+	if (udev) {
+		pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP);
+		retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500);
+	}
+	return retval;
+}
+
+static u32 get_transfer_size(struct s2255_mode *mode)
+{
+	int linesPerFrame = LINE_SZ_DEF;
+	int pixelsPerLine = NUM_LINES_DEF;
+	u32 outImageSize;
+	u32 usbInSize;
+	unsigned int mask_mult;
+
+	if (mode == NULL)
+		return 0;
+
+	if (mode->format == FORMAT_NTSC) {
+		switch (mode->scale) {
+		case SCALE_4CIFS:
+			linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
+			pixelsPerLine = LINE_SZ_4CIFS_NTSC;
+			break;
+		case SCALE_2CIFS:
+			linesPerFrame = NUM_LINES_2CIFS_NTSC;
+			pixelsPerLine = LINE_SZ_2CIFS_NTSC;
+			break;
+		case SCALE_1CIFS:
+			linesPerFrame = NUM_LINES_1CIFS_NTSC;
+			pixelsPerLine = LINE_SZ_1CIFS_NTSC;
+			break;
+		default:
+			break;
+		}
+	} else if (mode->format == FORMAT_PAL) {
+		switch (mode->scale) {
+		case SCALE_4CIFS:
+			linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
+			pixelsPerLine = LINE_SZ_4CIFS_PAL;
+			break;
+		case SCALE_2CIFS:
+			linesPerFrame = NUM_LINES_2CIFS_PAL;
+			pixelsPerLine = LINE_SZ_2CIFS_PAL;
+			break;
+		case SCALE_1CIFS:
+			linesPerFrame = NUM_LINES_1CIFS_PAL;
+			pixelsPerLine = LINE_SZ_1CIFS_PAL;
+			break;
+		default:
+			break;
+		}
+	}
+	outImageSize = linesPerFrame * pixelsPerLine;
+	if (mode->color != COLOR_Y8) {
+		/* 2 bytes/pixel if not monochrome */
+		outImageSize *= 2;
+	}
+
+	/* total bytes to send including prefix and 4K padding;
+	   must be a multiple of USB_READ_SIZE */
+	usbInSize = outImageSize + PREFIX_SIZE;	/* always send prefix */
+	mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1;
+	/* if size not a multiple of USB_READ_SIZE */
+	if (usbInSize & ~mask_mult)
+		usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK);
+	return usbInSize;
+}
+
+static void dump_verify_mode(struct s2255_dev *sdev, struct s2255_mode *mode)
+{
+	struct device *dev = &sdev->udev->dev;
+	dev_info(dev, "------------------------------------------------\n");
+	dev_info(dev, "verify mode\n");
+	dev_info(dev, "format: %d\n", mode->format);
+	dev_info(dev, "scale: %d\n", mode->scale);
+	dev_info(dev, "fdec: %d\n", mode->fdec);
+	dev_info(dev, "color: %d\n", mode->color);
+	dev_info(dev, "bright: 0x%x\n", mode->bright);
+	dev_info(dev, "restart: 0x%x\n", mode->restart);
+	dev_info(dev, "usb_block: 0x%x\n", mode->usb_block);
+	dev_info(dev, "single: 0x%x\n", mode->single);
+	dev_info(dev, "------------------------------------------------\n");
+}
+
+/*
+ * set mode is the function which controls the DSP.
+ * the restart parameter in struct s2255_mode should be set whenever
+ * the image size could change via color format, video system or image
+ * size.
+ * When the restart parameter is set, we sleep for ONE frame to allow the
+ * DSP time to get the new frame
+ */
+static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+			  struct s2255_mode *mode)
+{
+	int res;
+	u32 *buffer;
+	unsigned long chn_rev;
+
+	chn_rev = G_chnmap[chn];
+	dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
+	dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
+		dev->mode[chn].scale);
+	dprintk(2, "mode contrast %x\n", mode->contrast);
+
+	/* save the mode */
+	dev->mode[chn] = *mode;
+	dev->req_image_size[chn] = get_transfer_size(mode);
+	dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]);
+
+	buffer = kzalloc(512, GFP_KERNEL);
+	if (buffer == NULL) {
+		dev_err(&dev->udev->dev, "out of mem\n");
+		return -ENOMEM;
+	}
+
+	/* set the mode */
+	buffer[0] = IN_DATA_TOKEN;
+	buffer[1] = (u32) chn_rev;
+	buffer[2] = CMD_SET_MODE;
+	memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
+	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+	if (debug)
+		dump_verify_mode(dev, mode);
+	kfree(buffer);
+	dprintk(1, "set mode done chn %lu, %d\n", chn, res);
+
+	/* wait at least 3 frames before continuing */
+	if (mode->restart)
+		msleep(125);
+
+	/* clear the restart flag */
+	dev->mode[chn].restart = 0;
+
+	return res;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	int res;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	struct s2255_mode *new_mode;
+	struct s2255_mode *old_mode;
+	int chn;
+	int j;
+	dprintk(4, "%s\n", __func__);
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		dev_err(&dev->udev->dev, "invalid fh type0\n");
+		return -EINVAL;
+	}
+	if (i != fh->type) {
+		dev_err(&dev->udev->dev, "invalid fh type1\n");
+		return -EINVAL;
+	}
+
+	if (!res_get(dev, fh)) {
+		dev_err(&dev->udev->dev, "res get busy\n");
+		return -EBUSY;
+	}
+
+	/* send a set mode command everytime with restart.
+	   in case we switch resolutions or other parameters */
+	chn = fh->channel;
+	new_mode = &fh->mode;
+	old_mode = &fh->dev->mode[chn];
+
+	if (new_mode->color != old_mode->color)
+		new_mode->restart = 1;
+	else if (new_mode->scale != old_mode->scale)
+		new_mode->restart = 1;
+	else if (new_mode->format != old_mode->format)
+		new_mode->restart = 1;
+
+	s2255_set_mode(dev, chn, new_mode);
+	new_mode->restart = 0;
+	*old_mode = *new_mode;
+	dev->cur_fmt[chn] = fh->fmt;
+	dprintk(1, "%s[%d]\n", __func__, chn);
+	dev->last_frame[chn] = -1;
+	dev->bad_payload[chn] = 0;
+	dev->cur_frame[chn] = 0;
+	for (j = 0; j < SYS_FRAMES; j++) {
+		dev->buffer[chn].frame[j].ulState = 0;
+		dev->buffer[chn].frame[j].cur_size = 0;
+	}
+	res = videobuf_streamon(&fh->vb_vidq);
+	if (res == 0) {
+		s2255_start_acquire(dev, chn);
+		dev->b_acquire[chn] = 1;
+	} else {
+		res_free(dev, fh);
+	}
+	return res;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	int res;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+
+	dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		printk(KERN_ERR "invalid fh type0\n");
+		return -EINVAL;
+	}
+	if (i != fh->type) {
+		printk(KERN_ERR "invalid type i\n");
+		return -EINVAL;
+	}
+	s2255_stop_acquire(dev, fh->channel);
+	res = videobuf_streamoff(&fh->vb_vidq);
+	res_free(dev, fh);
+	return res;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+	struct s2255_fh *fh = priv;
+	struct s2255_mode *mode;
+	struct videobuf_queue *q = &fh->vb_vidq;
+	int ret = 0;
+
+	mutex_lock(&q->vb_lock);
+	if (videobuf_queue_is_busy(q)) {
+		dprintk(1, "queue busy\n");
+		ret = -EBUSY;
+		goto out_s_std;
+	}
+
+	if (res_locked(fh->dev, fh)) {
+		dprintk(1, "can't change standard after started\n");
+		ret = -EBUSY;
+		goto out_s_std;
+	}
+	mode = &fh->mode;
+
+	if (*i & V4L2_STD_NTSC) {
+		dprintk(4, "vidioc_s_std NTSC\n");
+		mode->format = FORMAT_NTSC;
+	} else if (*i & V4L2_STD_PAL) {
+		dprintk(4, "vidioc_s_std PAL\n");
+		mode->format = FORMAT_PAL;
+	} else {
+		ret = -EINVAL;
+	}
+out_s_std:
+	mutex_unlock(&q->vb_lock);
+	return ret;
+}
+
+/* Sensoray 2255 is a multiple channel capture device.
+   It does not have a "crossbar" of inputs.
+   We use one V4L device per channel. The user must
+   be aware that certain combinations are not allowed.
+   For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
+   at once in color(you can do full fps on 4 channels with greyscale.
+*/
+static int vidioc_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = S2255_NORMS;
+	strlcpy(inp->name, "Camera", sizeof(inp->name));
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+		if (qc->id && qc->id == s2255_qctrl[i].id) {
+			memcpy(qc, &(s2255_qctrl[i]), sizeof(*qc));
+			return 0;
+		}
+
+	dprintk(4, "query_ctrl -EINVAL %d\n", qc->id);
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+		if (ctrl->id == s2255_qctrl[i].id) {
+			ctrl->value = qctl_regs[i];
+			return 0;
+		}
+	dprintk(4, "g_ctrl -EINVAL\n");
+
+	return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
+{
+	int i;
+	struct s2255_fh *fh = priv;
+	struct s2255_dev *dev = fh->dev;
+	struct s2255_mode *mode;
+	mode = &fh->mode;
+	dprintk(4, "vidioc_s_ctrl\n");
+	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) {
+		if (ctrl->id == s2255_qctrl[i].id) {
+			if (ctrl->value < s2255_qctrl[i].minimum ||
+			    ctrl->value > s2255_qctrl[i].maximum)
+				return -ERANGE;
+
+			qctl_regs[i] = ctrl->value;
+			/* update the mode to the corresponding value */
+			switch (ctrl->id) {
+			case V4L2_CID_BRIGHTNESS:
+				mode->bright = ctrl->value;
+				break;
+			case V4L2_CID_CONTRAST:
+				mode->contrast = ctrl->value;
+				break;
+			case V4L2_CID_HUE:
+				mode->hue = ctrl->value;
+				break;
+			case V4L2_CID_SATURATION:
+				mode->saturation = ctrl->value;
+				break;
+			}
+			mode->restart = 0;
+			/* set mode here.  Note: stream does not need restarted.
+			   some V4L programs restart stream unnecessarily
+			   after a s_crtl.
+			 */
+			s2255_set_mode(dev, fh->channel, mode);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int s2255_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct s2255_dev *h, *dev = NULL;
+	struct s2255_fh *fh;
+	struct list_head *list;
+	enum v4l2_buf_type type = 0;
+	int i = 0;
+	int cur_channel = -1;
+	dprintk(1, "s2255: open called (minor=%d)\n", minor);
+
+	list_for_each(list, &s2255_devlist) {
+		h = list_entry(list, struct s2255_dev, s2255_devlist);
+		for (i = 0; i < MAX_CHANNELS; i++) {
+			if (h->vdev[i]->minor == minor) {
+				cur_channel = i;
+				dev = h;
+				type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			}
+		}
+	}
+
+	if ((NULL == dev) || (cur_channel == -1)) {
+		dprintk(1, "s2255: openv4l no dev\n");
+		return -ENODEV;
+	}
+
+	mutex_lock(&dev->open_lock);
+
+	dev->users[cur_channel]++;
+	if (dev->users[cur_channel] > S2255_MAX_USERS) {
+		dev->users[cur_channel]--;
+		mutex_unlock(&dev->open_lock);
+		printk(KERN_INFO "s2255drv: too many open handles!\n");
+		return -EBUSY;
+	}
+
+	if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
+		err("2255 firmware load failed. retrying.\n");
+		s2255_fwload_start(dev);
+		wait_event_timeout(dev->fw_data->wait_fw,
+				   (atomic_read(&dev->fw_data->fw_state)
+				    != S2255_FW_NOTLOADED),
+				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+		if (atomic_read(&dev->fw_data->fw_state)
+		    != S2255_FW_SUCCESS) {
+			printk(KERN_INFO "2255 FW load failed after 2 tries\n");
+			mutex_unlock(&dev->open_lock);
+			return -EFAULT;
+		}
+	} else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+		/* give S2255_LOAD_TIMEOUT time for firmware to load in case
+		   driver loaded and then device immediately opened */
+		printk(KERN_INFO "%s waiting for firmware load\n", __func__);
+		wait_event_timeout(dev->fw_data->wait_fw,
+				   (atomic_read(&dev->fw_data->fw_state)
+				   != S2255_FW_NOTLOADED),
+				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+		if (atomic_read(&dev->fw_data->fw_state)
+		    != S2255_FW_SUCCESS) {
+			printk(KERN_INFO "2255 firmware not loaded"
+			       "try again\n");
+			mutex_unlock(&dev->open_lock);
+			return -EBUSY;
+		}
+	}
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh) {
+		mutex_unlock(&dev->open_lock);
+		return -ENOMEM;
+	}
+
+	file->private_data = fh;
+	fh->dev = dev;
+	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fh->mode = dev->mode[cur_channel];
+	fh->fmt = dev->cur_fmt[cur_channel];
+	/* default 4CIF NTSC */
+	fh->width = LINE_SZ_4CIFS_NTSC;
+	fh->height = NUM_LINES_4CIFS_NTSC * 2;
+	fh->channel = cur_channel;
+
+	/* Put all controls at a sane state */
+	for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+		qctl_regs[i] = s2255_qctrl[i].default_value;
+
+	dprintk(1, "s2255drv: open minor=%d type=%s users=%d\n",
+		minor, v4l2_type_names[type], dev->users[cur_channel]);
+	dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n",
+		(unsigned long)fh, (unsigned long)dev,
+		(unsigned long)&dev->vidq[cur_channel]);
+	dprintk(4, "s2255drv: open: list_empty active=%d\n",
+		list_empty(&dev->vidq[cur_channel].active));
+
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
+				    NULL, &dev->slock,
+				    fh->type,
+				    V4L2_FIELD_INTERLACED,
+				    sizeof(struct s2255_buffer), fh);
+
+	kref_get(&dev->kref);
+	mutex_unlock(&dev->open_lock);
+	return 0;
+}
+
+
+static unsigned int s2255_poll(struct file *file,
+			       struct poll_table_struct *wait)
+{
+	struct s2255_fh *fh = file->private_data;
+	int rc;
+	dprintk(100, "%s\n", __func__);
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+		return POLLERR;
+
+	rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
+	return rc;
+}
+
+static void s2255_destroy(struct kref *kref)
+{
+	struct s2255_dev *dev = to_s2255_dev(kref);
+	if (!dev) {
+		printk(KERN_ERR "s2255drv: kref problem\n");
+		return;
+	}
+	/* prevent s2255_disconnect from racing s2255_open */
+	mutex_lock(&dev->open_lock);
+	s2255_exit_v4l(dev);
+	/* device unregistered so no longer possible to open. open_mutex
+	   can be unlocked */
+	mutex_unlock(&dev->open_lock);
+
+	/* board shutdown stops the read pipe if it is running */
+	s2255_board_shutdown(dev);
+
+	/* make sure firmware still not trying to load */
+	if (dev->fw_data->fw_urb) {
+		dprintk(2, "kill fw_urb\n");
+		usb_kill_urb(dev->fw_data->fw_urb);
+		usb_free_urb(dev->fw_data->fw_urb);
+		dev->fw_data->fw_urb = NULL;
+	}
+	/*
+	 * TODO: fixme(above, below): potentially leaving timers alive.
+	 *                            do not ignore timeout below if
+	 *                            it occurs.
+	 */
+
+	/* make sure we aren't waiting for the DSP */
+	if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) {
+		/* if we are, wait for the wakeup for fw_success or timeout */
+		wait_event_timeout(dev->fw_data->wait_fw,
+				   (atomic_read(&dev->fw_data->fw_state)
+				   == S2255_FW_SUCCESS),
+				   msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+	}
+
+	if (dev->fw_data) {
+		if (dev->fw_data->fw)
+			release_firmware(dev->fw_data->fw);
+		kfree(dev->fw_data->pfw_data);
+		kfree(dev->fw_data);
+	}
+
+	usb_put_dev(dev->udev);
+	dprintk(1, "%s", __func__);
+	kfree(dev);
+}
+
+static int s2255_close(struct inode *inode, struct file *file)
+{
+	struct s2255_fh *fh = file->private_data;
+	struct s2255_dev *dev = fh->dev;
+	int minor = iminor(inode);
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->open_lock);
+
+	if (dev->b_acquire[fh->channel])
+		s2255_stop_acquire(dev, fh->channel);
+	res_free(dev, fh);
+	videobuf_mmap_free(&fh->vb_vidq);
+	kfree(fh);
+	dev->users[fh->channel]--;
+	mutex_unlock(&dev->open_lock);
+
+	kref_put(&dev->kref, s2255_destroy);
+	dprintk(1, "s2255: close called (minor=%d, users=%d)\n",
+		minor, dev->users[fh->channel]);
+	return 0;
+}
+
+static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
+{
+	struct s2255_fh *fh = file->private_data;
+	int ret;
+
+	if (!fh)
+		return -ENODEV;
+	dprintk(4, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+	dprintk(4, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+
+	return ret;
+}
+
+static const struct file_operations s2255_fops_v4l = {
+	.owner = THIS_MODULE,
+	.open = s2255_open,
+	.release = s2255_close,
+	.poll = s2255_poll,
+	.ioctl = video_ioctl2,	/* V4L2 ioctl handler */
+	.compat_ioctl = v4l_compat_ioctl32,
+	.mmap = s2255_mmap_v4l,
+	.llseek = no_llseek,
+};
+
+static struct video_device template = {
+	.name = "s2255v",
+	.type = VID_TYPE_CAPTURE,
+	.fops = &s2255_fops_v4l,
+	.minor = -1,
+	.release = video_device_release,
+	.vidioc_querycap = vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_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_ctrl = vidioc_g_ctrl,
+	.vidioc_s_ctrl = vidioc_s_ctrl,
+	.vidioc_streamon = vidioc_streamon,
+	.vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf = vidioc_cgmbuf,
+#endif
+	.tvnorms = S2255_NORMS,
+	.current_norm = V4L2_STD_NTSC_M,
+};
+
+static int s2255_probe_v4l(struct s2255_dev *dev)
+{
+	int ret;
+	int i;
+	int cur_nr = video_nr;
+
+	/* initialize all video 4 linux */
+	list_add_tail(&dev->s2255_devlist, &s2255_devlist);
+	/* register 4 video devices */
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		INIT_LIST_HEAD(&dev->vidq[i].active);
+		dev->vidq[i].dev = dev;
+		dev->vidq[i].channel = i;
+		dev->vidq[i].kthread = NULL;
+		/* register 4 video devices */
+		dev->vdev[i] = video_device_alloc();
+		memcpy(dev->vdev[i], &template, sizeof(struct video_device));
+		dev->vdev[i]->dev = &dev->interface->dev;
+		if (video_nr == -1)
+			ret = video_register_device(dev->vdev[i],
+						    VFL_TYPE_GRABBER,
+						    video_nr);
+		else
+			ret = video_register_device(dev->vdev[i],
+						    VFL_TYPE_GRABBER,
+						    cur_nr + i);
+		dev->vdev[i]->priv = dev;
+
+		if (ret != 0) {
+			dev_err(&dev->udev->dev,
+				"failed to register video device!\n");
+			return ret;
+		}
+	}
+	printk(KERN_INFO "Sensoray 2255 V4L driver\n");
+	return ret;
+}
+
+static void s2255_exit_v4l(struct s2255_dev *dev)
+{
+	struct list_head *list;
+	int i;
+	/* unregister the video devices */
+	while (!list_empty(&s2255_devlist)) {
+		list = s2255_devlist.next;
+		list_del(list);
+	}
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		if (-1 != dev->vdev[i]->minor)
+			video_unregister_device(dev->vdev[i]);
+		else
+			video_device_release(dev->vdev[i]);
+	}
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process( call this
+ * function again).
+ *
+ * Received frame structure:
+ * bytes 0-3:  marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 4-7:  channel: 0-3
+ * bytes 8-11: payload size:  size of the frame
+ * bytes 12-payloadsize+12:  frame data
+ */
+static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
+{
+	static int dbgsync; /* = 0; */
+	char *pdest;
+	u32 offset = 0;
+	int bsync = 0;
+	int btrunc = 0;
+	char *psrc;
+	unsigned long copy_size;
+	unsigned long size;
+	s32 idx = -1;
+	struct s2255_framei *frm;
+	unsigned char *pdata;
+	unsigned long cur_size;
+	int bsearch = 0;
+	struct s2255_bufferi *buf;
+	dprintk(100, "buffer to user\n");
+
+	idx = dev->cur_frame[dev->cc];
+	buf = &dev->buffer[dev->cc];
+	frm = &buf->frame[idx];
+
+	if (frm->ulState == 0) {
+		frm->ulState = 1;
+		frm->cur_size = 0;
+		bsearch = 1;
+	} else if (frm->ulState == 2) {
+		/* system frame was not freed */
+		dprintk(2, "sys frame not free.  overrun ringbuf\n");
+		bsearch = 1;
+		frm->ulState = 1;
+		frm->cur_size = 0;
+	}
+
+	if (bsearch) {
+		if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
+			u32 jj;
+			if (dbgsync == 0) {
+				dprintk(3, "not synched, discarding all packets"
+					"until marker\n");
+
+				dbgsync++;
+			}
+			pdata = (unsigned char *)pipe_info->transfer_buffer;
+			for (jj = 0; jj < (pipe_info->cur_transfer_size - 12);
+			     jj++) {
+				if (*(s32 *) pdata == FRAME_MARKER) {
+					int cc;
+					dprintk(3,
+						"found frame marker at offset:"
+						" %d [%x %x]\n", jj, pdata[0],
+						pdata[1]);
+					offset = jj;
+					bsync = 1;
+					cc = *(u32 *) (pdata + sizeof(u32));
+					if (cc >= MAX_CHANNELS) {
+						printk(KERN_ERR
+						       "bad channel\n");
+						return -EINVAL;
+					}
+					/* reverse it */
+					dev->cc = G_chnmap[cc];
+					break;
+				}
+				pdata++;
+			}
+			if (bsync == 0)
+				return -EINVAL;
+		} else {
+			u32 *pword;
+			u32 payload;
+			int cc;
+			dbgsync = 0;
+			bsync = 1;
+			pword = (u32 *) pipe_info->transfer_buffer;
+			cc = pword[1];
+
+			if (cc >= MAX_CHANNELS) {
+				printk("invalid channel found. "
+					"throwing out data!\n");
+				return -EINVAL;
+			}
+			dev->cc = G_chnmap[cc];
+			payload = pword[2];
+			if (payload != dev->req_image_size[dev->cc]) {
+				dprintk(1, "[%d][%d]unexpected payload: %d"
+					"required: %lu \n", cc, dev->cc,
+					payload, dev->req_image_size[dev->cc]);
+				dev->bad_payload[dev->cc]++;
+				/* discard the bad frame */
+				return -EINVAL;
+			}
+
+		}
+	}
+	/* search done.  now find out if should be acquiring
+	   on this channel */
+	if (!dev->b_acquire[dev->cc]) {
+		frm->ulState = 0;
+		return -EINVAL;
+	}
+
+	idx = dev->cur_frame[dev->cc];
+	frm = &dev->buffer[dev->cc].frame[idx];
+
+	if (frm->ulState == 0) {
+		frm->ulState = 1;
+		frm->cur_size = 0;
+	} else if (frm->ulState == 2) {
+		/* system frame ring buffer overrun */
+		dprintk(2, "sys frame overrun.  overwriting frame %d %d\n",
+			dev->cc, idx);
+		frm->ulState = 1;
+		frm->cur_size = 0;
+	}
+
+	if (bsync) {
+		/* skip the marker 512 bytes (and offset if out of sync) */
+		psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
+	} else {
+		psrc = (u8 *)pipe_info->transfer_buffer;
+	}
+
+	if (frm->lpvbits == NULL) {
+		dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
+			frm, dev, dev->cc, idx);
+		return -ENOMEM;
+	}
+
+	pdest = frm->lpvbits + frm->cur_size;
+
+	if (bsync) {
+		copy_size =
+		    (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE;
+		if (copy_size > pipe_info->cur_transfer_size) {
+			printk("invalid copy size, overflow!\n");
+			return -ENOMEM;
+		}
+	} else {
+		copy_size = pipe_info->cur_transfer_size;
+	}
+
+	cur_size = frm->cur_size;
+	size = dev->req_image_size[dev->cc];
+
+	if ((copy_size + cur_size) > size) {
+		copy_size = size - cur_size;
+		btrunc = 1;
+	}
+
+	memcpy(pdest, psrc, copy_size);
+	cur_size += copy_size;
+	frm->cur_size += copy_size;
+	dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+
+	if (cur_size >= (size - PREFIX_SIZE)) {
+		u32 cc = dev->cc;
+		frm->ulState = 2;
+		dprintk(2, "****************[%d]Buffer[%d]full*************\n",
+			cc, idx);
+		dev->last_frame[cc] = dev->cur_frame[cc];
+		dev->cur_frame[cc]++;
+		/* end of system frame ring buffer, start at zero */
+		if ((dev->cur_frame[cc] == SYS_FRAMES) ||
+		    (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
+			dev->cur_frame[cc] = 0;
+
+		/* signal the semaphore for this channel */
+		if (dev->b_acquire[cc])
+			s2255_got_frame(dev, cc);
+		dev->frame_count[cc]++;
+	}
+	/* frame was truncated */
+	if (btrunc) {
+		/* return more data to process */
+		return EAGAIN;
+	}
+	/* done successfully */
+	return 0;
+}
+
+static void s2255_read_video_callback(struct s2255_dev *dev,
+				      struct s2255_pipeinfo *pipe_info)
+{
+	int res;
+	dprintk(50, "callback read video \n");
+
+	if (dev->cc >= MAX_CHANNELS) {
+		dev->cc = 0;
+		dev_err(&dev->udev->dev, "invalid channel\n");
+		return;
+	}
+	/* otherwise copy to the system buffers */
+	res = save_frame(dev, pipe_info);
+	if (res == EAGAIN)
+		save_frame(dev, pipe_info);
+
+	dprintk(50, "callback read video done\n");
+	return;
+}
+
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
+			     u16 Index, u16 Value, void *TransferBuffer,
+			     s32 TransferBufferLength, int bOut)
+{
+	int r;
+	if (!bOut) {
+		r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+				    Request,
+				    USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+				    USB_DIR_IN,
+				    Value, Index, TransferBuffer,
+				    TransferBufferLength, HZ * 5);
+	} else {
+		r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+				    Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				    Value, Index, TransferBuffer,
+				    TransferBufferLength, HZ * 5);
+	}
+	return r;
+}
+
+/*
+ * retrieve FX2 firmware version. future use.
+ * @param dev pointer to device extension
+ * @return -1 for fail, else returns firmware version as an int(16 bits)
+ */
+static int s2255_get_fx2fw(struct s2255_dev *dev)
+{
+	int fw;
+	int ret;
+	unsigned char transBuffer[64];
+	ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
+			       S2255_VR_IN);
+	if (ret < 0)
+		dprintk(2, "get fw error: %x\n", ret);
+	fw = transBuffer[0] + (transBuffer[1] << 8);
+	dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
+	return fw;
+}
+
+/*
+ * Create the system ring buffer to copy frames into from the
+ * usb read pipe.
+ */
+static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+{
+	unsigned long i;
+	unsigned long reqsize;
+	dprintk(1, "create sys buffers\n");
+	if (chn >= MAX_CHANNELS)
+		return -1;
+
+	dev->buffer[chn].dwFrames = SYS_FRAMES;
+
+	/* always allocate maximum size(PAL) for system buffers */
+	reqsize = SYS_FRAMES_MAXSIZE;
+
+	if (reqsize > SYS_FRAMES_MAXSIZE)
+		reqsize = SYS_FRAMES_MAXSIZE;
+
+	for (i = 0; i < SYS_FRAMES; i++) {
+		/* allocate the frames */
+		dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
+
+		dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
+			&dev->buffer[chn].frame[i], chn, i,
+			dev->buffer[chn].frame[i].lpvbits);
+		dev->buffer[chn].frame[i].size = reqsize;
+		if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+			printk(KERN_INFO "out of memory.  using less frames\n");
+			dev->buffer[chn].dwFrames = i;
+			break;
+		}
+	}
+
+	/* make sure internal states are set */
+	for (i = 0; i < SYS_FRAMES; i++) {
+		dev->buffer[chn].frame[i].ulState = 0;
+		dev->buffer[chn].frame[i].cur_size = 0;
+	}
+
+	dev->cur_frame[chn] = 0;
+	dev->last_frame[chn] = -1;
+	return 0;
+}
+
+static int s2255_release_sys_buffers(struct s2255_dev *dev,
+				     unsigned long channel)
+{
+	unsigned long i;
+	dprintk(1, "release sys buffers\n");
+	for (i = 0; i < SYS_FRAMES; i++) {
+		if (dev->buffer[channel].frame[i].lpvbits) {
+			dprintk(1, "vfree %p\n",
+				dev->buffer[channel].frame[i].lpvbits);
+			vfree(dev->buffer[channel].frame[i].lpvbits);
+		}
+		dev->buffer[channel].frame[i].lpvbits = NULL;
+	}
+	return 0;
+}
+
+static int s2255_board_init(struct s2255_dev *dev)
+{
+	int j;
+	struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
+	int fw_ver;
+	dprintk(4, "board init: %p", dev);
+
+	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+		struct s2255_pipeinfo *pipe = &dev->pipes[j];
+
+		memset(pipe, 0, sizeof(*pipe));
+		pipe->dev = dev;
+		pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
+		pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+
+		if (pipe->cur_transfer_size > pipe->max_transfer_size)
+			pipe->cur_transfer_size = pipe->max_transfer_size;
+		pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
+						GFP_KERNEL);
+		if (pipe->transfer_buffer == NULL) {
+			dprintk(1, "out of memory!\n");
+			return -ENOMEM;
+		}
+
+	}
+
+	/* query the firmware */
+	fw_ver = s2255_get_fx2fw(dev);
+
+	printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
+	if (fw_ver < CUR_USB_FWVER)
+		err("usb firmware not up to date %d\n", fw_ver);
+
+	for (j = 0; j < MAX_CHANNELS; j++) {
+		dev->b_acquire[j] = 0;
+		dev->mode[j] = mode_def;
+		dev->cur_fmt[j] = &formats[0];
+		dev->mode[j].restart = 1;
+		dev->req_image_size[j] = get_transfer_size(&mode_def);
+		dev->frame_count[j] = 0;
+		/* create the system buffers */
+		s2255_create_sys_buffers(dev, j);
+	}
+	/* start read pipe */
+	s2255_start_readpipe(dev);
+
+	dprintk(1, "S2255: board initialized\n");
+	return 0;
+}
+
+static int s2255_board_shutdown(struct s2255_dev *dev)
+{
+	u32 i;
+
+	dprintk(1, "S2255: board shutdown: %p", dev);
+
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		if (dev->b_acquire[i])
+			s2255_stop_acquire(dev, i);
+	}
+
+	s2255_stop_readpipe(dev);
+
+	for (i = 0; i < MAX_CHANNELS; i++)
+		s2255_release_sys_buffers(dev, i);
+
+	/* release transfer buffers */
+	for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
+		struct s2255_pipeinfo *pipe = &dev->pipes[i];
+		kfree(pipe->transfer_buffer);
+	}
+	return 0;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+	struct s2255_pipeinfo *pipe_info;
+	struct s2255_dev *dev;
+	int status;
+	int pipe;
+
+	pipe_info = purb->context;
+	dprintk(100, "read pipe completion %p, status %d\n", purb,
+		purb->status);
+	if (pipe_info == NULL) {
+		err("no context !");
+		return;
+	}
+
+	dev = pipe_info->dev;
+	if (dev == NULL) {
+		err("no context !");
+		return;
+	}
+	status = purb->status;
+	if (status != 0) {
+		dprintk(2, "read_pipe_completion: err\n");
+		return;
+	}
+
+	if (pipe_info->state == 0) {
+		dprintk(2, "exiting USB pipe");
+		return;
+	}
+
+	s2255_read_video_callback(dev, pipe_info);
+
+	pipe_info->err_count = 0;
+	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+	/* reuse urb */
+	usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+			  pipe,
+			  pipe_info->transfer_buffer,
+			  pipe_info->cur_transfer_size,
+			  read_pipe_completion, pipe_info);
+
+	if (pipe_info->state != 0) {
+		if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+			dev_err(&dev->udev->dev, "error submitting urb\n");
+			usb_free_urb(pipe_info->stream_urb);
+		}
+	} else {
+		dprintk(2, "read pipe complete state 0\n");
+	}
+	return;
+}
+
+static int s2255_start_readpipe(struct s2255_dev *dev)
+{
+	int pipe;
+	int retval;
+	int i;
+	struct s2255_pipeinfo *pipe_info = dev->pipes;
+	pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+	dprintk(2, "start pipe IN %d\n", dev->read_endpoint);
+
+	for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
+		pipe_info->state = 1;
+		pipe_info->buf_index = (u32) i;
+		pipe_info->priority_set = 0;
+		pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!pipe_info->stream_urb) {
+			dev_err(&dev->udev->dev,
+				"ReadStream: Unable to alloc URB");
+			return -ENOMEM;
+		}
+		/* transfer buffer allocated in board_init */
+		usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+				  pipe,
+				  pipe_info->transfer_buffer,
+				  pipe_info->cur_transfer_size,
+				  read_pipe_completion, pipe_info);
+
+		pipe_info->urb_size = sizeof(pipe_info->stream_urb);
+		dprintk(4, "submitting URB %p\n", pipe_info->stream_urb);
+		retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+		if (retval) {
+			printk(KERN_ERR "s2255: start read pipe failed\n");
+			return retval;
+		}
+	}
+
+	return 0;
+}
+
+/* starts acquisition process */
+static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+{
+	unsigned char *buffer;
+	int res;
+	unsigned long chn_rev;
+	int j;
+	if (chn >= MAX_CHANNELS) {
+		dprintk(2, "start acquire failed, bad channel %lu\n", chn);
+		return -1;
+	}
+
+	chn_rev = G_chnmap[chn];
+	dprintk(1, "S2255: start acquire %lu \n", chn);
+
+	buffer = kzalloc(512, GFP_KERNEL);
+	if (buffer == NULL) {
+		dev_err(&dev->udev->dev, "out of mem\n");
+		return -ENOMEM;
+	}
+
+	dev->last_frame[chn] = -1;
+	dev->bad_payload[chn] = 0;
+	dev->cur_frame[chn] = 0;
+	for (j = 0; j < SYS_FRAMES; j++) {
+		dev->buffer[chn].frame[j].ulState = 0;
+		dev->buffer[chn].frame[j].cur_size = 0;
+	}
+
+	/* send the start command */
+	*(u32 *) buffer = IN_DATA_TOKEN;
+	*((u32 *) buffer + 1) = (u32) chn_rev;
+	*((u32 *) buffer + 2) = (u32) CMD_START;
+	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+	if (res != 0)
+		dev_err(&dev->udev->dev, "CMD_START error\n");
+
+	dprintk(2, "start acquire exit[%lu] %d \n", chn, res);
+	kfree(buffer);
+	return 0;
+}
+
+static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+{
+	unsigned char *buffer;
+	int res;
+	unsigned long chn_rev;
+
+	if (chn >= MAX_CHANNELS) {
+		dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
+		return -1;
+	}
+	chn_rev = G_chnmap[chn];
+
+	buffer = kzalloc(512, GFP_KERNEL);
+	if (buffer == NULL) {
+		dev_err(&dev->udev->dev, "out of mem\n");
+		return -ENOMEM;
+	}
+
+	/* send the stop command */
+	dprintk(4, "stop acquire %lu\n", chn);
+	*(u32 *) buffer = IN_DATA_TOKEN;
+	*((u32 *) buffer + 1) = (u32) chn_rev;
+	*((u32 *) buffer + 2) = CMD_STOP;
+	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+
+	if (res != 0)
+		dev_err(&dev->udev->dev, "CMD_STOP error\n");
+
+	dprintk(4, "stop acquire: releasing states \n");
+
+	kfree(buffer);
+	dev->b_acquire[chn] = 0;
+
+	return 0;
+}
+
+static void s2255_stop_readpipe(struct s2255_dev *dev)
+{
+	int j;
+
+	if (dev == NULL) {
+		err("s2255: invalid device");
+		return;
+	}
+	dprintk(4, "stop read pipe\n");
+	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+		struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
+		if (pipe_info) {
+			if (pipe_info->state == 0)
+				continue;
+			pipe_info->state = 0;
+			pipe_info->prev_state = 1;
+
+		}
+	}
+
+	for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+		struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
+		if (pipe_info->stream_urb) {
+			/* cancel urb */
+			usb_kill_urb(pipe_info->stream_urb);
+			usb_free_urb(pipe_info->stream_urb);
+			pipe_info->stream_urb = NULL;
+		}
+	}
+	dprintk(2, "s2255 stop read pipe: %d\n", j);
+	return;
+}
+
+static void s2255_fwload_start(struct s2255_dev *dev)
+{
+	dev->fw_data->fw_size = dev->fw_data->fw->size;
+	atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
+	memcpy(dev->fw_data->pfw_data,
+	       dev->fw_data->fw->data, CHUNK_SIZE);
+	dev->fw_data->fw_loaded = CHUNK_SIZE;
+	usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev,
+			  usb_sndbulkpipe(dev->udev, 2),
+			  dev->fw_data->pfw_data,
+			  CHUNK_SIZE, s2255_fwchunk_complete,
+			  dev->fw_data);
+	mod_timer(&dev->timer, jiffies + HZ);
+}
+
+/* standard usb probe function */
+static int s2255_probe(struct usb_interface *interface,
+		       const struct usb_device_id *id)
+{
+	struct s2255_dev *dev = NULL;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int i;
+	int retval = -ENOMEM;
+
+	dprintk(2, "s2255: probe\n");
+
+	/* allocate memory for our device state and initialize it to zero */
+	dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
+	if (dev == NULL) {
+		err("s2255: out of memory");
+		goto error;
+	}
+
+	dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
+	if (!dev->fw_data)
+		goto error;
+
+	mutex_init(&dev->lock);
+	mutex_init(&dev->open_lock);
+
+	/* grab usb_device and save it */
+	dev->udev = usb_get_dev(interface_to_usbdev(interface));
+	if (dev->udev == NULL) {
+		dev_err(&interface->dev, "null usb device\n");
+		retval = -ENODEV;
+		goto error;
+	}
+	kref_init(&dev->kref);
+	dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref,
+		dev->udev, interface);
+	dev->interface = interface;
+	/* set up the endpoint information  */
+	iface_desc = interface->cur_altsetting;
+	dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+			/* we found the bulk in endpoint */
+			dev->read_endpoint = endpoint->bEndpointAddress;
+		}
+	}
+
+	if (!dev->read_endpoint) {
+		dev_err(&interface->dev, "Could not find bulk-in endpoint");
+		goto error;
+	}
+
+	/* set intfdata */
+	usb_set_intfdata(interface, dev);
+
+	dprintk(100, "after intfdata %p\n", dev);
+
+	init_timer(&dev->timer);
+	dev->timer.function = s2255_timer;
+	dev->timer.data = (unsigned long)dev->fw_data;
+
+	init_waitqueue_head(&dev->fw_data->wait_fw);
+
+
+	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+	if (!dev->fw_data->fw_urb) {
+		dev_err(&interface->dev, "out of memory!\n");
+		goto error;
+	}
+	dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
+	if (!dev->fw_data->pfw_data) {
+		dev_err(&interface->dev, "out of memory!\n");
+		goto error;
+	}
+	/* load the first chunk */
+	if (request_firmware(&dev->fw_data->fw,
+			     FIRMWARE_FILE_NAME, &dev->udev->dev)) {
+		printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
+		goto error;
+	}
+
+	/* loads v4l specific */
+	s2255_probe_v4l(dev);
+	/* load 2255 board specific */
+	s2255_board_init(dev);
+
+	dprintk(4, "before probe done %p\n", dev);
+	spin_lock_init(&dev->slock);
+
+	s2255_fwload_start(dev);
+	dev_info(&interface->dev, "Sensoray 2255 detected\n");
+	return 0;
+error:
+	return retval;
+}
+
+/* disconnect routine. when board is removed physically or with rmmod */
+static void s2255_disconnect(struct usb_interface *interface)
+{
+	struct s2255_dev *dev = NULL;
+	dprintk(1, "s2255: disconnect interface %p\n", interface);
+	dev = usb_get_intfdata(interface);
+	if (dev) {
+		kref_put(&dev->kref, s2255_destroy);
+		dprintk(1, "s2255drv: disconnect\n");
+		dev_info(&interface->dev, "s2255usb now disconnected\n");
+	}
+	usb_set_intfdata(interface, NULL);
+}
+
+static struct usb_driver s2255_driver = {
+	.name = "s2255",
+	.probe = s2255_probe,
+	.disconnect = s2255_disconnect,
+	.id_table = s2255_table,
+};
+
+static int __init usb_s2255_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&s2255_driver);
+
+	if (result)
+		err("usb_register failed. Error number %d", result);
+
+	dprintk(2, "s2255_init: done\n");
+	return result;
+}
+
+static void __exit usb_s2255_exit(void)
+{
+	usb_deregister(&s2255_driver);
+}
+
+module_init(usb_s2255_init);
+module_exit(usb_s2255_exit);
+
+MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
+MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 996b494..03e7721 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -66,6 +66,7 @@
 
 /* Addresses to scan */
 static unsigned short normal_i2c[]	 = { I2C_ADDRESS, I2C_CLIENT_END };
+
 I2C_CLIENT_INSMOD;
 
 static struct i2c_client client_template;
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index ec8c65d..fde99d9 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -130,6 +130,7 @@
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
+
 I2C_CLIENT_INSMOD;
 
 static struct i2c_client client_template;
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 716ee7f..f050242 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,7 +31,6 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 
-
 #include <media/rds.h>
 
 /* Addresses to scan */
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 435c083..bcd1c8f 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -67,7 +67,6 @@
 		0x42 >> 1, 0x40 >> 1,	/* SAA7114, SAA7115 and SAA7118 */
 		I2C_CLIENT_END };
 
-
 I2C_CLIENT_INSMOD;
 
 struct saa711x_state {
@@ -1558,7 +1557,7 @@
 }
 
 static const struct i2c_device_id saa7115_id[] = {
-	{ "saa711x", 1 }, /* autodetect */
+	{ "saa7115_auto", 1 }, /* autodetect */
 	{ "saa7111", 0 },
 	{ "saa7113", 0 },
 	{ "saa7114", 0 },
@@ -1577,4 +1576,3 @@
 	.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
 	.id_table = saa7115_id,
 };
-
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
deleted file mode 100644
index cedb988..0000000
--- a/drivers/media/video/saa711x.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * saa711x - Philips SAA711x video decoder driver version 0.0.1
- *
- * To do: Now, it handles only saa7113/7114. Should be improved to
- * handle all Philips saa711x devices.
- *
- * Based on saa7113 driver from Dave Perks <dperks@ibm.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#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 <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/types.h>
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-
-MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
-MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
-MODULE_LICENSE("GPL");
-
-#include <linux/i2c.h>
-
-#define I2C_NAME(s) (s)->name
-
-#include <linux/video_decoder.h>
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, " Set the default Debug level.  Default: 0 (Off) - (0-1)");
-
-
-#define dprintk(num, format, args...) \
-	do { \
-		if (debug >= num) \
-			printk(format, ##args); \
-	} while (0)
-
-/* ----------------------------------------------------------------------- */
-
-struct saa711x {
-	unsigned char reg[32];
-
-	int norm;
-	int input;
-	int enable;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
-};
-
-#define   I2C_SAA7113        0x4A
-#define   I2C_SAA7114        0x42
-
-/* ----------------------------------------------------------------------- */
-
-static inline int
-saa711x_write (struct i2c_client *client,
-	       u8                 reg,
-	       u8                 value)
-{
-	struct saa711x *decoder = i2c_get_clientdata(client);
-
-	decoder->reg[reg] = value;
-	return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int
-saa711x_write_block (struct i2c_client *client,
-		     const u8          *data,
-		     unsigned int       len)
-{
-	int ret = -1;
-	u8 reg;
-
-	/* the saa711x has an autoincrement function, use it if
-	 * the adapter understands raw I2C */
-	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		/* do raw I2C, not smbus compatible */
-		struct saa711x *decoder = i2c_get_clientdata(client);
-		struct i2c_msg msg;
-		u8 block_data[32];
-
-		msg.addr = client->addr;
-		msg.flags = 0;
-		while (len >= 2) {
-			msg.buf = (char *) block_data;
-			msg.len = 0;
-			block_data[msg.len++] = reg = data[0];
-			do {
-				block_data[msg.len++] =
-				    decoder->reg[reg++] = data[1];
-				len -= 2;
-				data += 2;
-			} while (len >= 2 && data[0] == reg &&
-				 msg.len < 32);
-			if ((ret = i2c_transfer(client->adapter,
-						&msg, 1)) < 0)
-				break;
-		}
-	} else {
-		/* do some slow I2C emulation kind of thing */
-		while (len >= 2) {
-			reg = *data++;
-			if ((ret = saa711x_write(client, reg,
-						 *data++)) < 0)
-				break;
-			len -= 2;
-		}
-	}
-
-	return ret;
-}
-
-static int
-saa711x_init_decoder (struct i2c_client *client,
-	      struct video_decoder_init *init)
-{
-	return saa711x_write_block(client, init->data, init->len);
-}
-
-static inline int
-saa711x_read (struct i2c_client *client,
-	      u8                 reg)
-{
-	return i2c_smbus_read_byte_data(client, reg);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const unsigned char saa711x_i2c_init[] = {
-	0x00, 0x00,	/* PH711x_CHIP_VERSION 00 - ID byte */
-	0x01, 0x08,	/* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
-	0x02, 0xc0,	/* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
-	0x03, 0x23,	/* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
-	0x04, 0x00,	/* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
-	0x05, 0x00,	/* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
-	0x06, 0xeb,	/* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
-	0x07, 0xe0,	/* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
-	0x08, 0x88,	/* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
-	0x09, 0x00,	/* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
-	0x0a, 0x80,	/* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
-	0x0b, 0x47,	/* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
-	0x0c, 0x40,	/* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
-	0x0d, 0x00,	/* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
-	0x0e, 0x01,	/* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
-	0x0f, 0xaa,	/* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
-	0x10, 0x00,	/* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
-	0x11, 0x1C,	/* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
-	0x12, 0x01,	/* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
-	0x13, 0x00,	/* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
-	0x14, 0x00,	/* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
-	0x15, 0x00,	/* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
-	0x16, 0x00,	/* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
-	0x17, 0x00,	/* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
-};
-
-static int
-saa711x_command (struct i2c_client *client,
-		 unsigned int       cmd,
-		 void              *arg)
-{
-	struct saa711x *decoder = i2c_get_clientdata(client);
-
-	switch (cmd) {
-
-	case 0:
-	case DECODER_INIT:
-	{
-		struct video_decoder_init *init = arg;
-		if (NULL != init)
-			return saa711x_init_decoder(client, init);
-		else {
-			struct video_decoder_init vdi;
-			vdi.data = saa711x_i2c_init;
-			vdi.len = sizeof(saa711x_i2c_init);
-			return saa711x_init_decoder(client, &vdi);
-		}
-	}
-
-	case DECODER_DUMP:
-	{
-		int i;
-
-		for (i = 0; i < 32; i += 16) {
-			int j;
-
-			printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
-			for (j = 0; j < 16; ++j) {
-				printk(" %02x",
-				       saa711x_read(client, i + j));
-			}
-			printk("\n");
-		}
-	}
-		break;
-
-	case DECODER_GET_CAPABILITIES:
-	{
-		struct video_decoder_capability *cap = arg;
-
-		cap->flags = VIDEO_DECODER_PAL |
-			     VIDEO_DECODER_NTSC |
-			     VIDEO_DECODER_SECAM |
-			     VIDEO_DECODER_AUTO |
-			     VIDEO_DECODER_CCIR;
-		cap->inputs = 8;
-		cap->outputs = 1;
-	}
-		break;
-
-	case DECODER_GET_STATUS:
-	{
-		int *iarg = arg;
-		int status;
-		int res;
-
-		status = saa711x_read(client, 0x1f);
-		dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
-			status);
-		res = 0;
-		if ((status & (1 << 6)) == 0) {
-			res |= DECODER_STATUS_GOOD;
-		}
-		switch (decoder->norm) {
-		case VIDEO_MODE_NTSC:
-			res |= DECODER_STATUS_NTSC;
-			break;
-		case VIDEO_MODE_PAL:
-			res |= DECODER_STATUS_PAL;
-			break;
-		case VIDEO_MODE_SECAM:
-			res |= DECODER_STATUS_SECAM;
-			break;
-		default:
-		case VIDEO_MODE_AUTO:
-			if ((status & (1 << 5)) != 0) {
-				res |= DECODER_STATUS_NTSC;
-			} else {
-				res |= DECODER_STATUS_PAL;
-			}
-			break;
-		}
-		if ((status & (1 << 0)) != 0) {
-			res |= DECODER_STATUS_COLOR;
-		}
-		*iarg = res;
-	}
-		break;
-
-	case DECODER_SET_GPIO:
-	{
-		int *iarg = arg;
-		if (0 != *iarg) {
-			saa711x_write(client, 0x11,
-				(decoder->reg[0x11] | 0x80));
-		} else {
-			saa711x_write(client, 0x11,
-				(decoder->reg[0x11] & 0x7f));
-		}
-		break;
-	}
-
-	case DECODER_SET_VBI_BYPASS:
-	{
-		int *iarg = arg;
-		if (0 != *iarg) {
-			saa711x_write(client, 0x13,
-				(decoder->reg[0x13] & 0xf0) | 0x0a);
-		} else {
-			saa711x_write(client, 0x13,
-				(decoder->reg[0x13] & 0xf0));
-		}
-		break;
-	}
-
-	case DECODER_SET_NORM:
-	{
-		int *iarg = arg;
-
-		switch (*iarg) {
-
-		case VIDEO_MODE_NTSC:
-			saa711x_write(client, 0x08,
-				      (decoder->reg[0x08] & 0x3f) | 0x40);
-			saa711x_write(client, 0x0e,
-				      (decoder->reg[0x0e] & 0x8f));
-			break;
-
-		case VIDEO_MODE_PAL:
-			saa711x_write(client, 0x08,
-				      (decoder->reg[0x08] & 0x3f) | 0x00);
-			saa711x_write(client, 0x0e,
-				      (decoder->reg[0x0e] & 0x8f));
-			break;
-
-		case VIDEO_MODE_SECAM:
-			saa711x_write(client, 0x08,
-				      (decoder->reg[0x08] & 0x3f) | 0x00);
-			saa711x_write(client, 0x0e,
-				      (decoder->reg[0x0e] & 0x8f) | 0x50);
-			break;
-
-		case VIDEO_MODE_AUTO:
-			saa711x_write(client, 0x08,
-				      (decoder->reg[0x08] & 0x3f) | 0x80);
-			saa711x_write(client, 0x0e,
-				      (decoder->reg[0x0e] & 0x8f));
-			break;
-
-		default:
-			return -EINVAL;
-
-		}
-		decoder->norm = *iarg;
-	}
-		break;
-
-	case DECODER_SET_INPUT:
-	{
-		int *iarg = arg;
-		if (*iarg < 0 || *iarg > 9) {
-			return -EINVAL;
-		}
-		if (decoder->input != *iarg) {
-			decoder->input = *iarg;
-			/* select mode */
-			saa711x_write(client, 0x02,
-				      (decoder->reg[0x02] & 0xf0) | decoder->input);
-			/* bypass chrominance trap for modes 4..7 */
-			saa711x_write(client, 0x09,
-				      (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
-		}
-	}
-		break;
-
-	case DECODER_SET_OUTPUT:
-	{
-		int *iarg = arg;
-
-		/* not much choice of outputs */
-		if (*iarg != 0) {
-			return -EINVAL;
-		}
-	}
-		break;
-
-	case DECODER_ENABLE_OUTPUT:
-	{
-		int *iarg = arg;
-		int enable = (*iarg != 0);
-
-		if (decoder->enable != enable) {
-			decoder->enable = enable;
-
-			/* RJ: If output should be disabled (for
-			 * playing videos), we also need a open PLL.
-			 * The input is set to 0 (where no input
-			 * source is connected), although this
-			 * is not necessary.
-			 *
-			 * If output should be enabled, we have to
-			 * reverse the above.
-			 */
-
-			if (decoder->enable) {
-				saa711x_write(client, 0x02,
-					      (decoder->
-					       reg[0x02] & 0xf8) |
-					      decoder->input);
-				saa711x_write(client, 0x08,
-					      (decoder->reg[0x08] & 0xfb));
-				saa711x_write(client, 0x11,
-					      (decoder->
-					       reg[0x11] & 0xf3) | 0x0c);
-			} else {
-				saa711x_write(client, 0x02,
-					      (decoder->reg[0x02] & 0xf8));
-				saa711x_write(client, 0x08,
-					      (decoder->
-					       reg[0x08] & 0xfb) | 0x04);
-				saa711x_write(client, 0x11,
-					      (decoder->reg[0x11] & 0xf3));
-			}
-		}
-	}
-		break;
-
-	case DECODER_SET_PICTURE:
-	{
-		struct video_picture *pic = arg;
-
-		if (decoder->bright != pic->brightness) {
-			/* We want 0 to 255 we get 0-65535 */
-			decoder->bright = pic->brightness;
-			saa711x_write(client, 0x0a, decoder->bright >> 8);
-		}
-		if (decoder->contrast != pic->contrast) {
-			/* We want 0 to 127 we get 0-65535 */
-			decoder->contrast = pic->contrast;
-			saa711x_write(client, 0x0b,
-				      decoder->contrast >> 9);
-		}
-		if (decoder->sat != pic->colour) {
-			/* We want 0 to 127 we get 0-65535 */
-			decoder->sat = pic->colour;
-			saa711x_write(client, 0x0c, decoder->sat >> 9);
-		}
-		if (decoder->hue != pic->hue) {
-			/* We want -128 to 127 we get 0-65535 */
-			decoder->hue = pic->hue;
-			saa711x_write(client, 0x0d,
-				      (decoder->hue - 32768) >> 8);
-		}
-	}
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-
-/* standard i2c insmod options */
-static unsigned short normal_i2c[] = {
-	I2C_SAA7113>>1,         /* saa7113 */
-	I2C_SAA7114>>1,         /* saa7114 */
-	I2C_CLIENT_END
-};
-
-I2C_CLIENT_INSMOD;
-
-
-static struct i2c_driver i2c_driver_saa711x;
-
-static int
-saa711x_detect_client (struct i2c_adapter *adapter,
-		       int                 address,
-		       int                 kind)
-{
-	int i;
-	struct i2c_client *client;
-	struct saa711x *decoder;
-	struct video_decoder_init vdi;
-
-	dprintk(1,
-		KERN_INFO
-		"saa711x.c: detecting saa711x client on address 0x%x\n",
-		address << 1);
-
-	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver_saa711x;
-	strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
-	decoder = kzalloc(sizeof(struct saa711x), GFP_KERNEL);
-	if (decoder == NULL) {
-		kfree(client);
-		return -ENOMEM;
-	}
-	decoder->norm = VIDEO_MODE_NTSC;
-	decoder->input = 0;
-	decoder->enable = 1;
-	decoder->bright = 32768;
-	decoder->contrast = 32768;
-	decoder->hue = 32768;
-	decoder->sat = 32768;
-	i2c_set_clientdata(client, decoder);
-
-	i = i2c_attach_client(client);
-	if (i) {
-		kfree(client);
-		kfree(decoder);
-		return i;
-	}
-
-	vdi.data = saa711x_i2c_init;
-	vdi.len = sizeof(saa711x_i2c_init);
-	i = saa711x_init_decoder(client, &vdi);
-	if (i < 0) {
-		dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
-			I2C_NAME(client), i);
-	} else {
-		dprintk(1,
-			KERN_INFO
-			"%s_attach: chip version %x at address 0x%x\n",
-			I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
-			client->addr << 1);
-	}
-
-	return 0;
-}
-
-static int
-saa711x_attach_adapter (struct i2c_adapter *adapter)
-{
-	dprintk(1,
-		KERN_INFO
-		"saa711x.c: starting probe for adapter %s (0x%x)\n",
-		I2C_NAME(adapter), adapter->id);
-	return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
-}
-
-static int
-saa711x_detach_client (struct i2c_client *client)
-{
-	struct saa711x *decoder = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-
-	kfree(decoder);
-	kfree(client);
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_saa711x = {
-	.driver = {
-		.name = "saa711x",
-	},
-	.id = I2C_DRIVERID_SAA711X,
-	.attach_adapter = saa711x_attach_adapter,
-	.detach_client = saa711x_detach_client,
-	.command = saa711x_command,
-};
-
-static int __init
-saa711x_init (void)
-{
-	return i2c_add_driver(&i2c_driver_saa711x);
-}
-
-static void __exit
-saa711x_exit (void)
-{
-	i2c_del_driver(&i2c_driver_saa711x);
-}
-
-module_init(saa711x_init);
-module_exit(saa711x_exit);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 79d11a6..d0e83fe 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -666,7 +666,6 @@
 {
 	struct saa7127_state *state;
 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
-	int read_result = 0;
 
 	/* Check if the adapter supports the needed features */
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -710,20 +709,29 @@
 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
 	saa7127_set_video_enable(client, 1);
 
-	/* Detect if it's an saa7129 */
-	read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
-	saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
-	if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-		v4l_info(client, "saa7129 found @ 0x%x (%s)\n",
-				client->addr << 1, client->adapter->name);
-		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
-		saa7127_write_inittab(client, saa7129_init_config_extra);
-		state->ident = V4L2_IDENT_SAA7129;
-	} else {
-		v4l_info(client, "saa7127 found @ 0x%x (%s)\n",
-				client->addr << 1, client->adapter->name);
-		state->ident = V4L2_IDENT_SAA7127;
+	if (id->driver_data) {	/* Chip type is already known */
+		state->ident = id->driver_data;
+	} else {		/* Needs detection */
+		int read_result;
+
+		/* Detect if it's an saa7129 */
+		read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
+		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+		if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+			saa7127_write(client, SAA7129_REG_FADE_KEY_COL2,
+					read_result);
+			state->ident = V4L2_IDENT_SAA7129;
+			strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
+		} else {
+			state->ident = V4L2_IDENT_SAA7127;
+			strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
+		}
 	}
+
+	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+			client->addr << 1, client->adapter->name);
+	if (state->ident == V4L2_IDENT_SAA7129)
+		saa7127_write_inittab(client, saa7129_init_config_extra);
 	return 0;
 }
 
@@ -740,7 +748,11 @@
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_device_id saa7127_id[] = {
-	{ "saa7127", 0 },
+	{ "saa7127_auto", 0 },	/* auto-detection */
+	{ "saa7126", V4L2_IDENT_SAA7127 },
+	{ "saa7127", V4L2_IDENT_SAA7127 },
+	{ "saa7128", V4L2_IDENT_SAA7129 },
+	{ "saa7129", V4L2_IDENT_SAA7129 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, saa7127_id);
@@ -753,4 +765,3 @@
 	.remove = saa7127_remove,
 	.id_table = saa7127_id,
 };
-
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 002e70a..707be17 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 
-
 #define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX     27000
 #define MPEG_TOTAL_TARGET_BITRATE_MAX  27000
@@ -21,6 +20,7 @@
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
+
 I2C_CLIENT_INSMOD;
 
 MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
@@ -448,6 +448,104 @@
 	return 0;
 }
 
+static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+		struct v4l2_queryctrl *qctrl)
+{
+	int err;
+
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ASPECT_4x3,
+				V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+				V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		err = v4l2_ctrl_query_fill_std(qctrl);
+		if (err == 0 &&
+		    params->vi_bitrate_mode ==
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+	case V4L2_CID_MPEG_STREAM_PID_PMT:
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+	case V4L2_CID_MPEG_STREAM_PID_PCR:
+		return v4l2_ctrl_query_fill_std(qctrl);
+
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+		struct v4l2_querymenu *qmenu)
+{
+	static const char *mpeg_audio_l2_bitrate[] = {
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"256 kbps",
+		"",
+		"384 kbps",
+		NULL
+	};
+	struct v4l2_queryctrl qctrl;
+	int err;
+
+	qctrl.id = qmenu->id;
+	err = saa6752hs_qctrl(params, &qctrl);
+	if (err)
+		return err;
+	if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
+		return v4l2_ctrl_query_menu(qmenu, &qctrl,
+				mpeg_audio_l2_bitrate);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+			v4l2_ctrl_get_menu(qmenu->id));
+}
+
 static int saa6752hs_init(struct i2c_client* client)
 {
 	unsigned char buf[9], buf2[4];
@@ -609,7 +707,6 @@
 	i2c_attach_client(&h->client);
 
 	v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
-
 	return 0;
 }
 
@@ -662,6 +759,10 @@
 		}
 		h->params = params;
 		break;
+	case VIDIOC_QUERYCTRL:
+		return saa6752hs_qctrl(&h->params, arg);
+	case VIDIOC_QUERYMENU:
+		return saa6752hs_qmenu(&h->params, arg);
 	case VIDIOC_G_FMT:
 	{
 	   struct v4l2_format *f = arg;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index f118de6..9929d20 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -80,7 +80,6 @@
 } snd_card_saa7134_t;
 
 
-
 /*
  * PCM structure
  */
@@ -1121,6 +1120,3 @@
 module_exit(saa7134_alsa_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ricardo Cerqueira");
-
-
-
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 2618cfa..6893f99 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1287,6 +1287,22 @@
 			.vmux = 8,
 		}},
 	},
+	[SAA7134_BOARD_AVERMEDIA_M103] = {
+		/* Massimo Piccioni <dafastidio@libero.it> */
+		.name           = "AVerMedia MiniPCI DVB-T Hybrid M103",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		 .mpeg           = SAA7134_MPEG_DVB,
+		 .inputs         = {{
+			 .name = name_tv,
+			 .vmux = 1,
+			 .amux = TV,
+			 .tv   = 1,
+		 } },
+	},
 	[SAA7134_BOARD_NOVAC_PRIMETV7133] = {
 		/* toshii@netbsd.org */
 		.name           = "Noval Prime TV 7133",
@@ -3503,6 +3519,39 @@
 			.amux = TV,
 			.gpio = 0x0200000,
 		},
+       },
+       [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+	       .name           = "ASUSTeK P7131 Analog",
+	       .audio_clock    = 0x00187de7,
+	       .tuner_type     = TUNER_PHILIPS_TDA8290,
+	       .radio_type     = UNSET,
+	       .tuner_addr     = ADDR_UNSET,
+	       .radio_addr     = ADDR_UNSET,
+	       .gpiomask       = 1 << 21,
+	       .inputs         = {{
+		       .name = name_tv,
+		       .vmux = 1,
+		       .amux = TV,
+		       .tv   = 1,
+		       .gpio = 0x0000000,
+	       }, {
+		       .name = name_comp1,
+		       .vmux = 3,
+		       .amux = LINE2,
+	       }, {
+		       .name = name_comp2,
+		       .vmux = 0,
+		       .amux = LINE2,
+	       }, {
+		       .name = name_svideo,
+		       .vmux = 8,
+		       .amux = LINE2,
+	       } },
+	       .radio = {
+		       .name = name_radio,
+		       .amux = TV,
+		       .gpio = 0x0200000,
+	       },
 	},
 	[SAA7134_BOARD_SABRENT_TV_PCB05] = {
 		.name           = "Sabrent PCMCIA TV-PCB05",
@@ -3940,32 +3989,111 @@
 	[SAA7134_BOARD_BEHOLD_M6] = {
 		/* Igor Kuznetsov <igk@igk.ru> */
 		/* Andrey Melnikoff <temnota@kmv.ru> */
-		.name           = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV M6",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.inputs         = {{
+		.inputs         = { {
 			.name = name_tv,
 			.vmux = 3,
 			.amux = TV,
 			.tv   = 1,
-		},{
+		}, {
 			.name = name_comp1,
 			.vmux = 1,
 			.amux = LINE1,
-		},{
+		}, {
 			.name = name_svideo,
 			.vmux = 8,
 			.amux = LINE1,
-		}},
+		} },
 		.radio = {
 			.name = name_radio,
 			.amux = LINE2,
 		},
 		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
+	},
+	[SAA7134_BOARD_BEHOLD_M63] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV M63",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
+	},
+	[SAA7134_BOARD_BEHOLD_M6_EXTRA] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+		.name           = "Beholder BeholdTV M6 Extra",
+		.audio_clock    = 0x00187de7,
+		/* FIXME: Must be PHILIPS_FM1216ME_MK5*/
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = { {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+		.video_out = CCIR656,
+		.vid_port_opts  = (SET_T_CODE_POLARITY_NON_INVERTED |
+					SET_CLOCK_NOT_DELAYED |
+					SET_CLOCK_INVERTED |
+					SET_VSYNC_OFF),
 	},
 	[SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = {
 		.name           = "Twinhan Hybrid DTV-DVB 3056 PCI",
@@ -4121,9 +4249,9 @@
 			 .amux = TV,
 			 .tv   = 1,
 		 }, {
-			 .name = name_comp1,
-			 .vmux = 3,
-			 .amux = LINE2,
+			 .name = name_comp,
+			 .vmux = 0,
+			 .amux = LINE1,
 		 }, {
 			 .name = name_svideo,
 			 .vmux = 8,
@@ -4141,6 +4269,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -4150,6 +4279,10 @@
 			.name = name_svideo,
 			.vmux = 8,
 			.amux = LINE1,
+		}, {
+			.name = name_comp,
+			.vmux = 0,
+			.amux = LINE1,
 		} },
 		.radio = {
 			.name = name_radio,
@@ -4163,7 +4296,6 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -5226,13 +5358,13 @@
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x5ace,
 		.subdevice    = 0x6193,
-		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M6_EXTRA,
 	}, {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x5ace,
 		.subdevice    = 0x6191,
-		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M63,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5284,10 +5416,22 @@
 	}, {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5169,
+		.subdevice    = 0x1502,
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x5ace,
 		.subdevice    = 0x6290,
 		.driver_data  = SAA7134_BOARD_BEHOLD_H6,
 	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf636,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5352,6 +5496,7 @@
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
 		switch (dev->board) {
 		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		case SAA7134_BOARD_AVERMEDIA_M103:
 			saa7134_set_gpio(dev, 23, 0);
 			msleep(10);
 			saa7134_set_gpio(dev, 23, 1);
@@ -5493,6 +5638,7 @@
 	case SAA7134_BOARD_FLYDVBT_LR301:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
 	case SAA7134_BOARD_FLYDVBTDUO:
 	case SAA7134_BOARD_PROTEUS_2309:
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -5560,6 +5706,7 @@
 		msleep(10);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+	case SAA7134_BOARD_AVERMEDIA_M103:
 		saa7134_set_gpio(dev, 23, 0);
 		msleep(10);
 		saa7134_set_gpio(dev, 23, 1);
@@ -5601,6 +5748,8 @@
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 	case SAA7134_BOARD_BEHOLD_607_9FM:
 	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -5683,6 +5832,7 @@
 		switch (dev->board) {
 		case SAA7134_BOARD_AVERMEDIA_A16D:
 		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		case SAA7134_BOARD_AVERMEDIA_M103:
 			ctl.demod = XC3028_FE_ZARLINK456;
 			break;
 		default:
@@ -5825,6 +5975,15 @@
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		break;
 	}
+       case SAA7134_BOARD_ASUSTeK_TVFM7135:
+       /* The card below is detected as card=53, but is different */
+	       if (dev->autodetected && (dev->eedata[0x27] == 0x03)) {
+		       dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG;
+		       printk(KERN_INFO "%s: P7131 analog only, using "
+						       "entry of %s\n",
+		       dev->name, saa7134_boards[dev->board].name);
+	       }
+	       break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 		hauppauge_eeprom(dev, dev->eedata+0x80);
 		/* break intentionally omitted */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 2c19cd0..cfee84e 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -150,7 +150,6 @@
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
 
-
 static void request_module_async(struct work_struct *work){
 	struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk);
 	if (card_is_empress(dev))
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 341b101..be48b9b 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1263,6 +1263,7 @@
 						&avermedia_xc3028_mt352_dev,
 						&dev->i2c_adap);
 		attach_xc3028 = 1;
+		break;
 	case SAA7134_BOARD_MD7134_BRIDGE_2:
 		dev->dvb.frontend = dvb_attach(tda10086_attach,
 						&sd1878_4m, &dev->i2c_adap);
@@ -1290,6 +1291,15 @@
 			fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
 		}
 		break;
+	case SAA7134_BOARD_AVERMEDIA_M103:
+		saa7134_set_gpio(dev, 25, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 25, 1);
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 3ae71a3..2a5ab95 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -208,7 +208,7 @@
 	return 0;
 }
 
-static int empress_enum_fmt_cap(struct file *file, void  *priv,
+static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (f->index != 0)
@@ -220,7 +220,7 @@
 	return 0;
 }
 
-static int empress_g_fmt_cap(struct file *file, void *priv,
+static int empress_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct saa7134_dev *dev = file->private_data;
@@ -233,7 +233,7 @@
 	return 0;
 }
 
-static int empress_s_fmt_cap(struct file *file, void *priv,
+static int empress_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct saa7134_dev *dev = file->private_data;
@@ -294,10 +294,20 @@
 	return videobuf_streamoff(&dev->empress_tsq);
 }
 
+static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+					      unsigned int cmd, void *arg)
+{
+	if (dev->mpeg_i2c_client == NULL)
+		return -EINVAL;
+	return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+								cmd, arg);
+}
+
 static int empress_s_ext_ctrls(struct file *file, void *priv,
 			       struct v4l2_ext_controls *ctrls)
 {
 	struct saa7134_dev *dev = file->private_data;
+	int err;
 
 	/* count == 0 is abused in saa6752hs.c, so that special
 		case is handled here explicitly. */
@@ -307,10 +317,10 @@
 	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
 
-	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+	err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls);
 	ts_init_encoder(dev);
 
-	return 0;
+	return err;
 }
 
 static int empress_g_ext_ctrls(struct file *file, void *priv,
@@ -320,9 +330,62 @@
 
 	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
-	saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+	return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+}
 
-	return 0;
+static int empress_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	static const u32 user_ctrls[] = {
+		V4L2_CID_USER_CLASS,
+		V4L2_CID_BRIGHTNESS,
+		V4L2_CID_CONTRAST,
+		V4L2_CID_SATURATION,
+		V4L2_CID_HUE,
+		V4L2_CID_AUDIO_VOLUME,
+		V4L2_CID_AUDIO_MUTE,
+		V4L2_CID_HFLIP,
+		0
+	};
+
+	static const u32 mpeg_ctrls[] = {
+		V4L2_CID_MPEG_CLASS,
+		V4L2_CID_MPEG_STREAM_TYPE,
+		V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+		V4L2_CID_MPEG_AUDIO_ENCODING,
+		V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+		V4L2_CID_MPEG_VIDEO_ENCODING,
+		V4L2_CID_MPEG_VIDEO_ASPECT,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		V4L2_CID_MPEG_VIDEO_BITRATE,
+		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		0
+	};
+	static const u32 *ctrl_classes[] = {
+		user_ctrls,
+		mpeg_ctrls,
+		NULL
+	};
+	struct saa7134_dev *dev = file->private_data;
+
+	c->id = v4l2_ctrl_next(ctrl_classes, c->id);
+	if (c->id == 0)
+		return -EINVAL;
+	if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
+		return v4l2_ctrl_query_fill_std(c);
+	if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+		return saa7134_queryctrl(file, priv, c);
+	return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c);
+}
+
+static int empress_querymenu(struct file *file, void *priv,
+					struct v4l2_querymenu *c)
+{
+	struct saa7134_dev *dev = file->private_data;
+
+	if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
 }
 
 static const struct file_operations ts_fops =
@@ -348,9 +411,9 @@
 	.minor	       = -1,
 
 	.vidioc_querycap		= empress_querycap,
-	.vidioc_enum_fmt_cap		= empress_enum_fmt_cap,
-	.vidioc_s_fmt_cap		= empress_s_fmt_cap,
-	.vidioc_g_fmt_cap		= empress_g_fmt_cap,
+	.vidioc_enum_fmt_vid_cap	= empress_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= empress_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= empress_g_fmt_vid_cap,
 	.vidioc_reqbufs			= empress_reqbufs,
 	.vidioc_querybuf		= empress_querybuf,
 	.vidioc_qbuf			= empress_qbuf,
@@ -363,7 +426,8 @@
 	.vidioc_g_input			= empress_g_input,
 	.vidioc_s_input			= empress_s_input,
 
-	.vidioc_queryctrl		= saa7134_queryctrl,
+	.vidioc_queryctrl		= empress_queryctrl,
+	.vidioc_querymenu		= empress_querymenu,
 	.vidioc_g_ctrl			= saa7134_g_ctrl,
 	.vidioc_s_ctrl			= saa7134_s_ctrl,
 
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index d8af386..5f713e6 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -327,6 +327,8 @@
 
 	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
 		client->driver->driver.name, client->addr, client->name);
+	if (client->addr == 0x20 && client->driver && client->driver->command)
+		dev->mpeg_i2c_client = client;
 
 	/* Am I an i2c remote control? */
 
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 76e6501..ad08d13 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -198,6 +198,84 @@
 	return 1;
 }
 
+/* Common (grey or coloured) pinnacle PCTV remote handling
+ *
+ */
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+			    int parity_offset, int marker, int code_modulo)
+{
+	unsigned char b[4];
+	unsigned int start = 0,parity = 0,code = 0;
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(&ir->c, b, 4)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	for (start = 0; start < ARRAY_SIZE(b); start++) {
+		if (b[start] == marker) {
+			code=b[(start+parity_offset + 1) % 4];
+			parity=b[(start+parity_offset) % 4];
+		}
+	}
+
+	/* Empty Request */
+	if (parity == 0)
+		return 0;
+
+	/* Repeating... */
+	if (ir->old == parity)
+		return 0;
+
+	ir->old = parity;
+
+	/* drop special codes when a key is held down a long time for the grey controller
+	   In this case, the second bit of the code is asserted */
+	if (marker == 0xfe && (code & 0x40))
+		return 0;
+
+	code %= code_modulo;
+
+	*ir_raw = code;
+	*ir_key = code;
+
+	i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+	return 1;
+}
+
+/* The grey pinnacle PCTV remote
+ *
+ *  There are one issue with this remote:
+ *   - I2c packet does not change when the same key is pressed quickly. The workaround
+ *     is to hold down each key for about half a second, so that another code is generated
+ *     in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+	 *
+	 * this is the only value that results in 42 unique
+	 * codes < 128
+	 */
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
 	struct card_ir *ir = dev->remote;
@@ -409,6 +487,7 @@
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
 		ir_codes     = ir_codes_asus_pc39;
 		mask_keydown = 0x0040000;
 		rc5_gpio = 1;
@@ -540,6 +619,8 @@
 		break;
 	case SAA7134_BOARD_BEHOLD_607_9FM:
 	case SAA7134_BOARD_BEHOLD_M6:
+	case SAA7134_BOARD_BEHOLD_M63:
+	case SAA7134_BOARD_BEHOLD_M6_EXTRA:
 	case SAA7134_BOARD_BEHOLD_H6:
 		snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
 		ir->get_key   = get_key_beholdm6xx;
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index 86f5eef..cf89d96 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -368,6 +368,7 @@
 #define SAA7135_DSP_RWCLEAR			0x586
 #define SAA7135_DSP_RWCLEAR_RERR		    1
 
+#define SAA7133_I2S_AUDIO_CONTROL               0x591
 /* ------------------------------------------------------------------ */
 /*
  * Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 232af59..c5d0b44 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -477,7 +477,6 @@
 	unsigned int i, audio, nscan;
 	int max1,max2,carrier,rx,mode,lastmode,default_carrier;
 
-
 	set_freezable();
 
 	for (;;) {
@@ -775,7 +774,6 @@
 	struct saa7134_dev *dev = data;
 	u32 value, norms;
 
-
 	set_freezable();
 	for (;;) {
 		tvaudio_sleep(dev,-1);
@@ -873,13 +871,34 @@
 
 	if (!card_is_empress(dev))
 		return;
-	i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
 
-	/* enable I2S audio output for the mpeg encoder */
-	saa_writeb(SAA7134_I2S_OUTPUT_SELECT,  0x80);
-	saa_writeb(SAA7134_I2S_OUTPUT_FORMAT,  i2s_format);
-	saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,   0x0F);
-	saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,   0x01);
+	if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+		return;
+
+	/* configure GPIO for out */
+	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+	    /* Set I2S format (SONY)  */
+	    saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
+	    /* Start I2S */
+	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
+	    break;
+
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	    i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+	    /* enable I2S audio output for the mpeg encoder */
+	    saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
+	    saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
+	    saa_writeb(SAA7134_I2S_OUTPUT_LEVEL,  0x0F);
+	    saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,  0x01);
+
+	default:
+	    break;
+	}
 }
 
 int saa7134_tvaudio_rx2mode(u32 rx)
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 48e1a01..1a51375 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1496,7 +1496,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
+static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -1516,7 +1516,7 @@
 	return 0;
 }
 
-static int saa7134_g_fmt_cap(struct file *file, void *priv,
+static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -1532,7 +1532,7 @@
 	return 0;
 }
 
-static int saa7134_g_fmt_overlay(struct file *file, void *priv,
+static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -1546,7 +1546,7 @@
 	return 0;
 }
 
-static int saa7134_try_fmt_cap(struct file *file, void *priv,
+static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -1597,7 +1597,7 @@
 	return 0;
 }
 
-static int saa7134_try_fmt_overlay(struct file *file, void *priv,
+static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
 						struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -1611,13 +1611,13 @@
 	return verify_preview(dev, &f->fmt.win);
 }
 
-static int saa7134_s_fmt_cap(struct file *file, void *priv,
+static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
 	int err;
 
-	err = saa7134_try_fmt_cap(file, priv, f);
+	err = saa7134_try_fmt_vid_cap(file, priv, f);
 	if (0 != err)
 		return err;
 
@@ -1628,7 +1628,7 @@
 	return 0;
 }
 
-static int saa7134_s_fmt_overlay(struct file *file, void *priv,
+static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct saa7134_fh *fh = priv;
@@ -2028,7 +2028,7 @@
 	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
 }
 
-static int saa7134_enum_fmt_cap(struct file *file, void  *priv,
+static int saa7134_enum_fmt_vid_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (f->index >= FORMATS)
@@ -2042,7 +2042,7 @@
 	return 0;
 }
 
-static int saa7134_enum_fmt_overlay(struct file *file, void  *priv,
+static int saa7134_enum_fmt_vid_overlay(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (saa7134_no_overlay > 0) {
@@ -2061,7 +2061,7 @@
 	return 0;
 }
 
-static int saa7134_enum_fmt_vbi(struct file *file, void  *priv,
+static int saa7134_enum_fmt_vbi_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (0 != f->index)
@@ -2208,6 +2208,32 @@
 	return 0;
 }
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+			      struct v4l2_register *reg)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+	reg->val = saa_readb(reg->reg);
+	return 0;
+}
+
+static int vidioc_s_register (struct file *file, void *priv,
+				struct v4l2_register *reg)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+	saa_writeb(reg->reg&0xffffff, reg->val);
+	return 0;
+}
+#endif
+
 static int radio_querycap(struct file *file, void *priv,
 					struct v4l2_capability *cap)
 {
@@ -2348,18 +2374,18 @@
 	.fops				= &video_fops,
 	.minor				= -1,
 	.vidioc_querycap		= saa7134_querycap,
-	.vidioc_enum_fmt_cap		= saa7134_enum_fmt_cap,
-	.vidioc_g_fmt_cap		= saa7134_g_fmt_cap,
-	.vidioc_try_fmt_cap		= saa7134_try_fmt_cap,
-	.vidioc_s_fmt_cap		= saa7134_s_fmt_cap,
-	.vidioc_enum_fmt_overlay	= saa7134_enum_fmt_overlay,
-	.vidioc_g_fmt_overlay		= saa7134_g_fmt_overlay,
-	.vidioc_try_fmt_overlay		= saa7134_try_fmt_overlay,
-	.vidioc_s_fmt_overlay		= saa7134_s_fmt_overlay,
-	.vidioc_enum_fmt_vbi		= saa7134_enum_fmt_vbi,
-	.vidioc_g_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
-	.vidioc_try_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
-	.vidioc_s_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
+	.vidioc_enum_fmt_vid_cap	= saa7134_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= saa7134_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= saa7134_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= saa7134_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_overlay	= saa7134_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay	= saa7134_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay	= saa7134_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay	= saa7134_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vbi_cap	= saa7134_enum_fmt_vbi_cap,
+	.vidioc_g_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap		= saa7134_try_get_set_fmt_vbi_cap,
 	.vidioc_g_audio			= saa7134_g_audio,
 	.vidioc_s_audio			= saa7134_s_audio,
 	.vidioc_cropcap			= saa7134_cropcap,
@@ -2391,6 +2417,10 @@
 	.vidioc_g_parm			= saa7134_g_parm,
 	.vidioc_g_frequency		= saa7134_g_frequency,
 	.vidioc_s_frequency		= saa7134_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register              = vidioc_g_register,
+	.vidioc_s_register              = vidioc_s_register,
+#endif
 	.tvnorms			= SAA7134_NORMS,
 	.current_norm			= V4L2_STD_PAL,
 };
@@ -2458,13 +2488,14 @@
 	int vo = saa7134_boards[dev->board].video_out;
 	int video_reg;
 	unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+
+	/* Configure videoport */
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
 	video_reg = video_out[vo][1];
 	if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
 		video_reg &= ~VP_T_CODE_P_INVERTED;
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
-	saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
 	video_reg = video_out[vo][5];
 	if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
@@ -2481,6 +2512,9 @@
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
 	saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
 
+	/* Start videoport */
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+
 	return 0;
 }
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 34ff0d4..6927cbe 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -264,7 +264,10 @@
 #define SAA7134_BOARD_AVERMEDIA_A700_PRO    140
 #define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
 #define SAA7134_BOARD_BEHOLD_H6      142
-
+#define SAA7134_BOARD_BEHOLD_M63      143
+#define SAA7134_BOARD_BEHOLD_M6_EXTRA    144
+#define SAA7134_BOARD_AVERMEDIA_M103    145
+#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -552,6 +555,7 @@
 	struct saa7134_ts          ts;
 	struct saa7134_dmaqueue    ts_q;
 	struct saa7134_mpeg_ops    *mops;
+	struct i2c_client 	   *mpeg_i2c_client;
 
 	/* SAA7134_MPEG_EMPRESS only */
 	struct video_device        *empress_dev;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
new file mode 100644
index 0000000..012005e
--- /dev/null
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -0,0 +1,657 @@
+/*
+ * V4L2 Driver for SuperH Mobile CEU interface
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on V4L2 Driver for PXA camera host - "pxa_camera.c",
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+#include <media/sh_mobile_ceu.h>
+#include <media/videobuf-dma-contig.h>
+
+/* register offsets for sh7722 / sh7723 */
+
+#define CAPSR  0x00
+#define CAPCR  0x04
+#define CAMCR  0x08
+#define CMCYR  0x0c
+#define CAMOR  0x10
+#define CAPWR  0x14
+#define CAIFR  0x18
+#define CSTCR  0x20 /* not on sh7723 */
+#define CSECR  0x24 /* not on sh7723 */
+#define CRCNTR 0x28
+#define CRCMPR 0x2c
+#define CFLCR  0x30
+#define CFSZR  0x34
+#define CDWDR  0x38
+#define CDAYR  0x3c
+#define CDACR  0x40
+#define CDBYR  0x44
+#define CDBCR  0x48
+#define CBDSR  0x4c
+#define CFWCR  0x5c
+#define CLFCR  0x60
+#define CDOCR  0x64
+#define CDDCR  0x68
+#define CDDAR  0x6c
+#define CEIER  0x70
+#define CETCR  0x74
+#define CSTSR  0x7c
+#define CSRTR  0x80
+#define CDSSR  0x84
+#define CDAYR2 0x90
+#define CDACR2 0x94
+#define CDBYR2 0x98
+#define CDBCR2 0x9c
+
+static DEFINE_MUTEX(camera_lock);
+
+/* per video frame buffer */
+struct sh_mobile_ceu_buffer {
+	struct videobuf_buffer vb; /* v4l buffer must be first */
+	const struct soc_camera_data_format *fmt;
+};
+
+struct sh_mobile_ceu_dev {
+	struct device *dev;
+	struct soc_camera_host ici;
+	struct soc_camera_device *icd;
+
+	unsigned int irq;
+	void __iomem *base;
+	unsigned long video_limit;
+
+	spinlock_t lock;
+	struct list_head capture;
+	struct videobuf_buffer *active;
+
+	struct sh_mobile_ceu_info *pdata;
+};
+
+static void ceu_write(struct sh_mobile_ceu_dev *priv,
+		      unsigned long reg_offs, unsigned long data)
+{
+	iowrite32(data, priv->base + reg_offs);
+}
+
+static unsigned long ceu_read(struct sh_mobile_ceu_dev *priv,
+			      unsigned long reg_offs)
+{
+	return ioread32(priv->base + reg_offs);
+}
+
+/*
+ *  Videobuf operations
+ */
+static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
+					unsigned int *count,
+					unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
+
+	*size = PAGE_ALIGN(icd->width * icd->height * bytes_per_pixel);
+
+	if (0 == *count)
+		*count = 2;
+
+	if (pcdev->video_limit) {
+		while (*size * *count > pcdev->video_limit)
+			(*count)--;
+	}
+
+	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq,
+			struct sh_mobile_ceu_buffer *buf)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+		&buf->vb, buf->vb.baddr, buf->vb.bsize);
+
+	if (in_interrupt())
+		BUG();
+
+	videobuf_dma_contig_free(vq, &buf->vb);
+	dev_dbg(&icd->dev, "%s freed\n", __func__);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
+{
+	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~1);
+	ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & 0x0317f313);
+	ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | 1);
+
+	ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~0x10000);
+
+	ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
+
+	if (pcdev->active) {
+		ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
+		ceu_write(pcdev, CAPSR, 0x1); /* start capture */
+	}
+}
+
+static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
+					  struct videobuf_buffer *vb,
+					  enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct sh_mobile_ceu_buffer *buf;
+	int ret;
+
+	buf = container_of(vb, struct sh_mobile_ceu_buffer, vb);
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/* Added list head initialization on alloc */
+	WARN_ON(!list_empty(&vb->queue));
+
+#ifdef DEBUG
+	/* This can be useful if you want to see if we actually fill
+	 * the buffer with something */
+	memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	if (buf->fmt	!= icd->current_fmt ||
+	    vb->width	!= icd->width ||
+	    vb->height	!= icd->height ||
+	    vb->field	!= field) {
+		buf->fmt	= icd->current_fmt;
+		vb->width	= icd->width;
+		vb->height	= icd->height;
+		vb->field	= field;
+		vb->state	= VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	return 0;
+fail:
+	free_buffer(vq, buf);
+out:
+	return ret;
+}
+
+static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
+					 struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	unsigned long flags;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	vb->state = VIDEOBUF_ACTIVE;
+	spin_lock_irqsave(&pcdev->lock, flags);
+	list_add_tail(&vb->queue, &pcdev->capture);
+
+	if (!pcdev->active) {
+		pcdev->active = vb;
+		sh_mobile_ceu_capture(pcdev);
+	}
+
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
+					   struct videobuf_buffer *vb)
+{
+	free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
+}
+
+static struct videobuf_queue_ops sh_mobile_ceu_videobuf_ops = {
+	.buf_setup      = sh_mobile_ceu_videobuf_setup,
+	.buf_prepare    = sh_mobile_ceu_videobuf_prepare,
+	.buf_queue      = sh_mobile_ceu_videobuf_queue,
+	.buf_release    = sh_mobile_ceu_videobuf_release,
+};
+
+static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
+{
+	struct sh_mobile_ceu_dev *pcdev = data;
+	struct videobuf_buffer *vb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	vb = pcdev->active;
+	list_del_init(&vb->queue);
+
+	if (!list_empty(&pcdev->capture))
+		pcdev->active = list_entry(pcdev->capture.next,
+					   struct videobuf_buffer, queue);
+	else
+		pcdev->active = NULL;
+
+	sh_mobile_ceu_capture(pcdev);
+
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	int ret = -EBUSY;
+
+	mutex_lock(&camera_lock);
+
+	if (pcdev->icd)
+		goto err;
+
+	dev_info(&icd->dev,
+		 "SuperH Mobile CEU driver attached to camera %d\n",
+		 icd->devnum);
+
+	if (pcdev->pdata->enable_camera)
+		pcdev->pdata->enable_camera();
+
+	ret = icd->ops->init(icd);
+	if (ret)
+		goto err;
+
+	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+	while (ceu_read(pcdev, CSTSR) & 1)
+		msleep(1);
+
+	pcdev->icd = icd;
+err:
+	mutex_unlock(&camera_lock);
+
+	return ret;
+}
+
+static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	BUG_ON(icd != pcdev->icd);
+
+	/* disable capture, disable interrupts */
+	ceu_write(pcdev, CEIER, 0);
+	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+	icd->ops->release(icd);
+	if (pcdev->pdata->disable_camera)
+		pcdev->pdata->disable_camera();
+
+	dev_info(&icd->dev,
+		 "SuperH Mobile CEU driver detached from camera %d\n",
+		 icd->devnum);
+
+	pcdev->icd = NULL;
+}
+
+static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
+				       __u32 pixfmt)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	int ret, buswidth, width, cfszr_width, cdwdr_width;
+	unsigned long camera_flags, common_flags, value;
+
+	camera_flags = icd->ops->query_bus_param(icd);
+	common_flags = soc_camera_bus_param_compatible(camera_flags,
+						       pcdev->pdata->flags);
+	if (!common_flags)
+		return -EINVAL;
+
+	ret = icd->ops->set_bus_param(icd, common_flags);
+	if (ret < 0)
+		return ret;
+
+	switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+	case SOCAM_DATAWIDTH_8:
+		buswidth = 8;
+		break;
+	case SOCAM_DATAWIDTH_16:
+		buswidth = 16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ceu_write(pcdev, CRCNTR, 0);
+	ceu_write(pcdev, CRCMPR, 0);
+
+	value = 0x00000010;
+	value |= (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ? (1 << 1) : 0;
+	value |= (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ? (1 << 0) : 0;
+	value |= (buswidth == 16) ? (1 << 12) : 0;
+	ceu_write(pcdev, CAMCR, value);
+
+	ceu_write(pcdev, CAPCR, 0x00300000);
+	ceu_write(pcdev, CAIFR, 0);
+
+	mdelay(1);
+
+	width = icd->width * (icd->current_fmt->depth / 8);
+	width = (buswidth == 16) ? width / 2 : width;
+	cfszr_width = (buswidth == 8) ? width / 2 : width;
+	cdwdr_width = (buswidth == 16) ? width * 2 : width;
+
+	ceu_write(pcdev, CAMOR, 0);
+	ceu_write(pcdev, CAPWR, (icd->height << 16) | width);
+	ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */
+	ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);
+	ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */
+	ceu_write(pcdev, CDOCR, 0x00000016);
+
+	ceu_write(pcdev, CDWDR, cdwdr_width);
+	ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
+
+	/* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
+	/* in data fetch mode: no need for CDACR, CDBYR, CDBCR */
+
+	return 0;
+}
+
+static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
+				       __u32 pixfmt)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+	unsigned long camera_flags, common_flags;
+
+	camera_flags = icd->ops->query_bus_param(icd);
+	common_flags = soc_camera_bus_param_compatible(camera_flags,
+						       pcdev->pdata->flags);
+	if (!common_flags)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
+				     __u32 pixfmt, struct v4l2_rect *rect)
+{
+	return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+}
+
+static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
+				     struct v4l2_format *f)
+{
+	/* FIXME: calculate using depth and bus width */
+
+	if (f->fmt.pix.height < 4)
+		f->fmt.pix.height = 4;
+	if (f->fmt.pix.height > 1920)
+		f->fmt.pix.height = 1920;
+	if (f->fmt.pix.width < 2)
+		f->fmt.pix.width = 2;
+	if (f->fmt.pix.width > 2560)
+		f->fmt.pix.width = 2560;
+	f->fmt.pix.width &= ~0x01;
+	f->fmt.pix.height &= ~0x03;
+
+	/* limit to sensor capabilities */
+	return icd->ops->try_fmt_cap(icd, f);
+}
+
+static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
+				 struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/* This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered */
+	for (i = 0; i < p->count; i++) {
+		struct sh_mobile_ceu_buffer *buf;
+
+		buf = container_of(icf->vb_vidq.bufs[i],
+				   struct sh_mobile_ceu_buffer, vb);
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct sh_mobile_ceu_buffer *buf;
+
+	buf = list_entry(icf->vb_vidq.stream.next,
+			 struct sh_mobile_ceu_buffer, vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+
+	return 0;
+}
+
+static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
+				  struct v4l2_capability *cap)
+{
+	strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
+	cap->version = KERNEL_VERSION(0, 0, 5);
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
+					struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
+	videobuf_queue_dma_contig_init(q,
+				       &sh_mobile_ceu_videobuf_ops,
+				       &ici->dev, &pcdev->lock,
+				       V4L2_BUF_TYPE_VIDEO_CAPTURE,
+				       V4L2_FIELD_NONE,
+				       sizeof(struct sh_mobile_ceu_buffer),
+				       icd);
+}
+
+static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= sh_mobile_ceu_add_device,
+	.remove		= sh_mobile_ceu_remove_device,
+	.set_fmt_cap	= sh_mobile_ceu_set_fmt_cap,
+	.try_fmt_cap	= sh_mobile_ceu_try_fmt_cap,
+	.reqbufs	= sh_mobile_ceu_reqbufs,
+	.poll		= sh_mobile_ceu_poll,
+	.querycap	= sh_mobile_ceu_querycap,
+	.try_bus_param	= sh_mobile_ceu_try_bus_param,
+	.set_bus_param	= sh_mobile_ceu_set_bus_param,
+	.init_videobuf	= sh_mobile_ceu_init_videobuf,
+};
+
+static int sh_mobile_ceu_probe(struct platform_device *pdev)
+{
+	struct sh_mobile_ceu_dev *pcdev;
+	struct resource *res;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || !irq) {
+		dev_err(&pdev->dev, "Not enough CEU platform resources.\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	platform_set_drvdata(pdev, pcdev);
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	pcdev->pdata = pdev->dev.platform_data;
+	if (!pcdev->pdata) {
+		err = -EINVAL;
+		dev_err(&pdev->dev, "CEU platform data not set.\n");
+		goto exit_kfree;
+	}
+
+	base = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (!base) {
+		err = -ENXIO;
+		dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
+		goto exit_kfree;
+	}
+
+	pcdev->irq = irq;
+	pcdev->base = base;
+	pcdev->video_limit = 0; /* only enabled if second resource exists */
+	pcdev->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		err = dma_declare_coherent_memory(&pdev->dev, res->start,
+						  res->start,
+						  (res->end - res->start) + 1,
+						  DMA_MEMORY_MAP |
+						  DMA_MEMORY_EXCLUSIVE);
+		if (!err) {
+			dev_err(&pdev->dev, "Unable to declare CEU memory.\n");
+			err = -ENXIO;
+			goto exit_iounmap;
+		}
+
+		pcdev->video_limit = (res->end - res->start) + 1;
+	}
+
+	/* request irq */
+	err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,
+			  pdev->dev.bus_id, pcdev);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
+		goto exit_release_mem;
+	}
+
+	pcdev->ici.priv = pcdev;
+	pcdev->ici.dev.parent = &pdev->dev;
+	pcdev->ici.nr = pdev->id;
+	pcdev->ici.drv_name = pdev->dev.bus_id,
+	pcdev->ici.ops = &sh_mobile_ceu_host_ops,
+
+	err = soc_camera_host_register(&pcdev->ici);
+	if (err)
+		goto exit_free_irq;
+
+	return 0;
+
+exit_free_irq:
+	free_irq(pcdev->irq, pcdev);
+exit_release_mem:
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+		dma_release_declared_memory(&pdev->dev);
+exit_iounmap:
+	iounmap(base);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int sh_mobile_ceu_remove(struct platform_device *pdev)
+{
+	struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
+
+	soc_camera_host_unregister(&pcdev->ici);
+	free_irq(pcdev->irq, pcdev);
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+		dma_release_declared_memory(&pdev->dev);
+	iounmap(pcdev->base);
+	kfree(pcdev);
+	return 0;
+}
+
+static struct platform_driver sh_mobile_ceu_driver = {
+	.driver 	= {
+		.name	= "sh_mobile_ceu",
+	},
+	.probe		= sh_mobile_ceu_probe,
+	.remove		= sh_mobile_ceu_remove,
+};
+
+static int __init sh_mobile_ceu_init(void)
+{
+	return platform_driver_register(&sh_mobile_ceu_driver);
+}
+
+static void __exit sh_mobile_ceu_exit(void)
+{
+	return platform_driver_unregister(&sh_mobile_ceu_driver);
+}
+
+module_init(sh_mobile_ceu_init);
+module_exit(sh_mobile_ceu_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile CEU driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 35223e0..6ff489b 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -44,7 +44,6 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
@@ -57,7 +56,6 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), },
 	/* SN9C103 */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index d015bfe..e39b98f 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -26,6 +26,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
 #include <media/soc_camera.h>
 
 static LIST_HEAD(hosts);
@@ -44,7 +45,7 @@
 	return NULL;
 }
 
-static int soc_camera_try_fmt_cap(struct file *file, void *priv,
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
 				  struct v4l2_format *f)
 {
 	struct soc_camera_file *icf = file->private_data;
@@ -182,7 +183,6 @@
 	struct soc_camera_device *icd;
 	struct soc_camera_host *ici;
 	struct soc_camera_file *icf;
-	spinlock_t *lock;
 	int ret;
 
 	icf = vmalloc(sizeof(*icf));
@@ -209,13 +209,6 @@
 	}
 
 	icf->icd = icd;
-
-	icf->lock = ici->ops->spinlock_alloc(icf);
-	if (!icf->lock) {
-		ret = -ENOMEM;
-		goto esla;
-	}
-
 	icd->use_count++;
 
 	/* Now we really have to activate the camera */
@@ -233,21 +226,12 @@
 	file->private_data = icf;
 	dev_dbg(&icd->dev, "camera device open\n");
 
-	/* We must pass NULL as dev pointer, then all pci_* dma operations
-	 * transform to normal dma_* ones. */
-	videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock,
-				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-				ici->msize, icd);
+	ici->ops->init_videobuf(&icf->vb_vidq, icd);
 
 	return 0;
 
 	/* All errors are entered with the video_lock held */
 eiciadd:
-	lock = icf->lock;
-	icf->lock = NULL;
-	if (ici->ops->spinlock_free)
-		ici->ops->spinlock_free(lock);
-esla:
 	module_put(ici->ops->owner);
 emgi:
 	module_put(icd->ops->owner);
@@ -263,15 +247,11 @@
 	struct soc_camera_device *icd = icf->icd;
 	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 	struct video_device *vdev = icd->vdev;
-	spinlock_t *lock = icf->lock;
 
 	mutex_lock(&video_lock);
 	icd->use_count--;
 	if (!icd->use_count)
 		ici->ops->remove(icd);
-	icf->lock = NULL;
-	if (ici->ops->spinlock_free)
-		ici->ops->spinlock_free(lock);
 	module_put(icd->ops->owner);
 	module_put(ici->ops->owner);
 	mutex_unlock(&video_lock);
@@ -342,7 +322,7 @@
 };
 
 
-static int soc_camera_s_fmt_cap(struct file *file, void *priv,
+static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct soc_camera_file *icf = file->private_data;
@@ -362,7 +342,7 @@
 	/* buswidth may be further adjusted by the ici */
 	icd->buswidth = data_fmt->depth;
 
-	ret = soc_camera_try_fmt_cap(file, icf, f);
+	ret = soc_camera_try_fmt_vid_cap(file, icf, f);
 	if (ret < 0)
 		return ret;
 
@@ -389,7 +369,7 @@
 	return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
 }
 
-static int soc_camera_enum_fmt_cap(struct file *file, void  *priv,
+static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
 				   struct v4l2_fmtdesc *f)
 {
 	struct soc_camera_file *icf = file->private_data;
@@ -408,7 +388,7 @@
 	return 0;
 }
 
-static int soc_camera_g_fmt_cap(struct file *file, void *priv,
+static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct soc_camera_file *icf = file->private_data;
@@ -767,27 +747,12 @@
 {
 }
 
-static spinlock_t *spinlock_alloc(struct soc_camera_file *icf)
-{
-	spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
-
-	if (lock)
-		spin_lock_init(lock);
-
-	return lock;
-}
-
-static void spinlock_free(spinlock_t *lock)
-{
-	kfree(lock);
-}
-
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
 	int ret;
 	struct soc_camera_host *ix;
 
-	if (!ici->vbq_ops || !ici->ops->add || !ici->ops->remove)
+	if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove)
 		return -EINVAL;
 
 	/* Number might be equal to the platform device ID */
@@ -811,11 +776,6 @@
 	if (ret)
 		goto edevr;
 
-	if (!ici->ops->spinlock_alloc) {
-		ici->ops->spinlock_alloc = spinlock_alloc;
-		ici->ops->spinlock_free = spinlock_free;
-	}
-
 	scan_add_host(ici);
 
 	return 0;
@@ -925,15 +885,15 @@
 	vdev->minor		= -1;
 	vdev->tvnorms		= V4L2_STD_UNKNOWN,
 	vdev->vidioc_querycap	= soc_camera_querycap;
-	vdev->vidioc_g_fmt_cap	= soc_camera_g_fmt_cap;
-	vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
-	vdev->vidioc_s_fmt_cap	= soc_camera_s_fmt_cap;
+	vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap;
+	vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap;
+	vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap;
 	vdev->vidioc_enum_input	= soc_camera_enum_input;
 	vdev->vidioc_g_input	= soc_camera_g_input;
 	vdev->vidioc_s_input	= soc_camera_s_input;
 	vdev->vidioc_s_std	= soc_camera_s_std;
 	vdev->vidioc_reqbufs	= soc_camera_reqbufs;
-	vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
+	vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap;
 	vdev->vidioc_querybuf	= soc_camera_querybuf;
 	vdev->vidioc_qbuf	= soc_camera_qbuf;
 	vdev->vidioc_dqbuf	= soc_camera_dqbuf;
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
new file mode 100644
index 0000000..eefb032
--- /dev/null
+++ b/drivers/media/video/soc_camera_platform.c
@@ -0,0 +1,198 @@
+/*
+ * Generic Platform Camera Driver
+ *
+ * Copyright (C) 2008 Magnus Damm
+ * Based on mt9m001 driver,
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/soc_camera.h>
+
+struct soc_camera_platform_info {
+	int iface;
+	char *format_name;
+	unsigned long format_depth;
+	struct v4l2_pix_format format;
+	unsigned long bus_param;
+	int (*set_capture)(struct soc_camera_platform_info *info, int enable);
+};
+
+struct soc_camera_platform_priv {
+	struct soc_camera_platform_info *info;
+	struct soc_camera_device icd;
+	struct soc_camera_data_format format;
+};
+
+static struct soc_camera_platform_info *
+soc_camera_platform_get_info(struct soc_camera_device *icd)
+{
+	struct soc_camera_platform_priv *priv;
+	priv = container_of(icd, struct soc_camera_platform_priv, icd);
+	return priv->info;
+}
+
+static int soc_camera_platform_init(struct soc_camera_device *icd)
+{
+	return 0;
+}
+
+static int soc_camera_platform_release(struct soc_camera_device *icd)
+{
+	return 0;
+}
+
+static int soc_camera_platform_start_capture(struct soc_camera_device *icd)
+{
+	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	return p->set_capture(p, 1);
+}
+
+static int soc_camera_platform_stop_capture(struct soc_camera_device *icd)
+{
+	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	return p->set_capture(p, 0);
+}
+
+static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd,
+					     unsigned long flags)
+{
+	return 0;
+}
+
+static unsigned long
+soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
+{
+	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+	return p->bus_param;
+}
+
+static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd,
+					   __u32 pixfmt, struct v4l2_rect *rect)
+{
+	return 0;
+}
+
+static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd,
+					   struct v4l2_format *f)
+{
+	struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+
+	f->fmt.pix.width = p->format.width;
+	f->fmt.pix.height = p->format.height;
+	return 0;
+}
+
+static int soc_camera_platform_video_probe(struct soc_camera_device *icd)
+{
+	struct soc_camera_platform_priv *priv;
+	priv = container_of(icd, struct soc_camera_platform_priv, icd);
+
+	priv->format.name = priv->info->format_name;
+	priv->format.depth = priv->info->format_depth;
+	priv->format.fourcc = priv->info->format.pixelformat;
+	priv->format.colorspace = priv->info->format.colorspace;
+
+	icd->formats = &priv->format;
+	icd->num_formats = 1;
+
+	return soc_camera_video_start(icd);
+}
+
+static void soc_camera_platform_video_remove(struct soc_camera_device *icd)
+{
+	soc_camera_video_stop(icd);
+}
+
+static struct soc_camera_ops soc_camera_platform_ops = {
+	.owner			= THIS_MODULE,
+	.probe			= soc_camera_platform_video_probe,
+	.remove			= soc_camera_platform_video_remove,
+	.init			= soc_camera_platform_init,
+	.release		= soc_camera_platform_release,
+	.start_capture		= soc_camera_platform_start_capture,
+	.stop_capture		= soc_camera_platform_stop_capture,
+	.set_fmt_cap		= soc_camera_platform_set_fmt_cap,
+	.try_fmt_cap		= soc_camera_platform_try_fmt_cap,
+	.set_bus_param		= soc_camera_platform_set_bus_param,
+	.query_bus_param	= soc_camera_platform_query_bus_param,
+};
+
+static int soc_camera_platform_probe(struct platform_device *pdev)
+{
+	struct soc_camera_platform_priv *priv;
+	struct soc_camera_platform_info *p;
+	struct soc_camera_device *icd;
+	int ret;
+
+	p = pdev->dev.platform_data;
+	if (!p)
+		return -EINVAL;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->info = p;
+	platform_set_drvdata(pdev, priv);
+
+	icd = &priv->icd;
+	icd->ops	= &soc_camera_platform_ops;
+	icd->control	= &pdev->dev;
+	icd->width_min	= 0;
+	icd->width_max	= priv->info->format.width;
+	icd->height_min	= 0;
+	icd->height_max	= priv->info->format.height;
+	icd->y_skip_top	= 0;
+	icd->iface	= priv->info->iface;
+
+	ret = soc_camera_device_register(icd);
+	if (ret)
+		kfree(priv);
+
+	return ret;
+}
+
+static int soc_camera_platform_remove(struct platform_device *pdev)
+{
+	struct soc_camera_platform_priv *priv = platform_get_drvdata(pdev);
+
+	soc_camera_device_unregister(&priv->icd);
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_driver soc_camera_platform_driver = {
+	.driver 	= {
+		.name	= "soc_camera_platform",
+	},
+	.probe		= soc_camera_platform_probe,
+	.remove		= soc_camera_platform_remove,
+};
+
+static int __init soc_camera_platform_module_init(void)
+{
+	return platform_driver_register(&soc_camera_platform_driver);
+}
+
+static void __exit soc_camera_platform_module_exit(void)
+{
+	return platform_driver_unregister(&soc_camera_platform_driver);
+}
+
+module_init(soc_camera_platform_module_init);
+module_exit(soc_camera_platform_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera Platform driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index b12c60c..f308c38 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -981,7 +981,7 @@
 }
 
 
-static int stk_vidioc_enum_fmt_cap(struct file *filp,
+static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_fmtdesc *fmtd)
 {
 	fmtd->flags = 0;
@@ -1025,7 +1025,7 @@
 	{ .w = 176,  .h = 144,  .m = MODE_QCIF, },
 };
 
-static int stk_vidioc_g_fmt_cap(struct file *filp,
+static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_format *f)
 {
 	struct v4l2_pix_format *pix_format = &f->fmt.pix;
@@ -1054,7 +1054,7 @@
 	return 0;
 }
 
-static int stk_vidioc_try_fmt_cap(struct file *filp,
+static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_format *fmtd)
 {
 	int i;
@@ -1131,7 +1131,7 @@
 	return stk_sensor_configure(dev);
 }
 
-static int stk_vidioc_s_fmt_cap(struct file *filp,
+static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
 		void *priv, struct v4l2_format *fmtd)
 {
 	int ret;
@@ -1145,7 +1145,7 @@
 		return -EBUSY;
 	if (dev->owner && dev->owner != filp)
 		return -EBUSY;
-	ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
+	ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd);
 	if (ret)
 		return ret;
 	dev->owner = filp;
@@ -1342,10 +1342,10 @@
 	.release = stk_v4l_dev_release,
 
 	.vidioc_querycap = stk_vidioc_querycap,
-	.vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
-	.vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
-	.vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
+	.vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap,
 	.vidioc_enum_input = stk_vidioc_enum_input,
 	.vidioc_s_input = stk_vidioc_s_input,
 	.vidioc_g_input = stk_vidioc_g_input,
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index 8f0100f..29991d1 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -523,6 +523,9 @@
 	if (val < 0)
 		return val;
 
+	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+		val ^= sensor->platform_data->is_upside_down();
+
 	vc->value = val;
 	return 0;
 }
@@ -556,6 +559,9 @@
 	if (lvc == NULL)
 		return -EINVAL;
 
+	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+		val ^= sensor->platform_data->is_upside_down();
+
 	val = val << lvc->start_bit;
 	if (tcm825x_write_reg_mask(client, lvc->reg, val))
 		return -EIO;
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
index 966765b..770ebac 100644
--- a/drivers/media/video/tcm825x.h
+++ b/drivers/media/video/tcm825x.h
@@ -182,6 +182,7 @@
 	int (*needs_reset)(struct v4l2_int_device *s, void *buf,
 			   struct v4l2_pix_format *fmt);
 	int (*ifparm)(struct v4l2_ifparm *p);
+	int (*is_upside_down)(void);
 };
 
 /* Array of image sizes supported by TCM825X.  These must be ordered from
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index b4d10f7..ae75c18 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -72,6 +72,7 @@
 	I2C_ADDR_TDA7432 >> 1,
 	I2C_CLIENT_END,
 };
+
 I2C_CLIENT_INSMOD;
 
 /* Structure of address and subaddresses for the tda7432 */
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 0cee002..2437c1a 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -34,6 +34,7 @@
 static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+
 #define dprintk(args...) \
 	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 3c05571..7a8ce8f 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -30,7 +30,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 
-
 #include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
@@ -42,6 +41,7 @@
     I2C_ADDR_TDA9875 >> 1,
     I2C_CLIENT_END
 };
+
 I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 9513d86..421c144 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -36,6 +36,7 @@
 static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+
 #define dprintk(args...) \
 	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 7fd5336..b5c8957 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -36,6 +36,7 @@
 static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
+
 #define dprintk(args...) \
 	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 28ab9f9..9220378 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -39,7 +39,6 @@
 
 static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
 
-
 I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 0d12ace..93d879d 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1298,7 +1298,6 @@
 	.id_table = tuner_id,
 };
 
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c77914d..463680b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -69,7 +69,6 @@
 /* chip description */
 struct CHIPDESC {
 	char       *name;             /* chip name         */
-	int        id;                /* ID */
 	int        addr_lo, addr_hi;  /* i2c address range */
 	int        registers;         /* # of registers    */
 
@@ -1256,7 +1255,6 @@
 static struct CHIPDESC chiplist[] = {
 	{
 		.name       = "tda9840",
-		.id         = I2C_DRIVERID_TDA9840,
 		.insmodopt  = &tda9840,
 		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
 		.addr_hi    = I2C_ADDR_TDA9840 >> 1,
@@ -1272,7 +1270,6 @@
 	},
 	{
 		.name       = "tda9873h",
-		.id         = I2C_DRIVERID_TDA9873,
 		.checkit    = tda9873_checkit,
 		.insmodopt  = &tda9873,
 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
@@ -1293,7 +1290,6 @@
 	},
 	{
 		.name       = "tda9874h/a",
-		.id         = I2C_DRIVERID_TDA9874,
 		.checkit    = tda9874a_checkit,
 		.initialize = tda9874a_initialize,
 		.insmodopt  = &tda9874a,
@@ -1306,7 +1302,6 @@
 	},
 	{
 		.name       = "tda9850",
-		.id         = I2C_DRIVERID_TDA9850,
 		.insmodopt  = &tda9850,
 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
 		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
@@ -1319,7 +1314,6 @@
 	},
 	{
 		.name       = "tda9855",
-		.id         = I2C_DRIVERID_TDA9855,
 		.insmodopt  = &tda9855,
 		.addr_lo    = I2C_ADDR_TDA985x_L >> 1,
 		.addr_hi    = I2C_ADDR_TDA985x_H >> 1,
@@ -1344,7 +1338,6 @@
 	},
 	{
 		.name       = "tea6300",
-		.id         = I2C_DRIVERID_TEA6300,
 		.insmodopt  = &tea6300,
 		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
 		.addr_hi    = I2C_ADDR_TEA6300 >> 1,
@@ -1365,7 +1358,6 @@
 	},
 	{
 		.name       = "tea6320",
-		.id         = I2C_DRIVERID_TEA6300,
 		.initialize = tea6320_initialize,
 		.insmodopt  = &tea6320,
 		.addr_lo    = I2C_ADDR_TEA6300 >> 1,
@@ -1387,7 +1379,6 @@
 	},
 	{
 		.name       = "tea6420",
-		.id         = I2C_DRIVERID_TEA6420,
 		.insmodopt  = &tea6420,
 		.addr_lo    = I2C_ADDR_TEA6420 >> 1,
 		.addr_hi    = I2C_ADDR_TEA6420 >> 1,
@@ -1400,7 +1391,6 @@
 	},
 	{
 		.name       = "tda8425",
-		.id         = I2C_DRIVERID_TDA8425,
 		.insmodopt  = &tda8425,
 		.addr_lo    = I2C_ADDR_TDA8425 >> 1,
 		.addr_hi    = I2C_ADDR_TDA8425 >> 1,
@@ -1424,7 +1414,6 @@
 	},
 	{
 		.name       = "pic16c54 (PV951)",
-		.id         = I2C_DRIVERID_PIC16C54_PV9,
 		.insmodopt  = &pic16c54,
 		.addr_lo    = I2C_ADDR_PIC16C54 >> 1,
 		.addr_hi    = I2C_ADDR_PIC16C54>> 1,
@@ -1440,8 +1429,6 @@
 	},
 	{
 		.name       = "ta8874z",
-		.id         = -1,
-		/*.id         = I2C_DRIVERID_TA8874Z, */
 		.checkit    = ta8874z_checkit,
 		.insmodopt  = &ta8874z,
 		.addr_lo    = I2C_ADDR_TDA9840 >> 1,
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index a9c5e5a..abf6854 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -169,7 +169,6 @@
 }
 
 
-
 #if ENABLE_HEXDUMP
 static void usbvision_hexdump(const unsigned char *data, int len)
 {
@@ -2317,7 +2316,6 @@
 	del_timer(&usbvision->powerOffTimer);
 	INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
 	(void) schedule_work(&usbvision->powerOffWork);
-
 }
 
 void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
@@ -2518,7 +2516,6 @@
 		}
 	}
 
-
 	/* Submit all URBs */
 	for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
 			errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
@@ -2564,7 +2561,6 @@
 		usbvision->sbuf[bufIdx].urb = NULL;
 	}
 
-
 	PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
 	usbvision->streaming = Stream_Off;
 
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index e2274d7..a6d0085 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -190,7 +190,6 @@
 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
 }
 
-
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm usbvision_algo = {
@@ -514,11 +513,7 @@
 	.id                = I2C_HW_B_BT848, /* FIXME */
 	.client_register   = attach_inform,
 	.client_unregister = detach_inform,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-	.class             = I2C_ADAP_CLASS_TV_ANALOG,
-#else
 	.class		   = I2C_CLASS_TV_ANALOG,
-#endif
 };
 
 static struct i2c_client i2c_client_template = {
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index d97261a..cd6c41d 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -179,7 +179,6 @@
 /*   /sys/bus/usb/drivers/USBVision Video Grabber                            */
 /*****************************************************************************/
 
-
 #define YES_NO(x) ((x) ? "Yes" : "No")
 
 static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
@@ -370,7 +369,6 @@
 	}
 }
 
-
 /*
  * usbvision_open()
  *
@@ -388,7 +386,6 @@
 
 	PDEBUG(DBG_IO, "open");
 
-
 	usbvision_reset_powerOffTimer(usbvision);
 
 	if (usbvision->user)
@@ -442,9 +439,6 @@
 		mutex_unlock(&usbvision->lock);
 	}
 
-	if (errCode) {
-	}
-
 	/* prepare queues */
 	usbvision_empty_framequeues(usbvision);
 
@@ -495,8 +489,6 @@
 	}
 
 	PDEBUG(DBG_IO, "success");
-
-
 	return 0;
 }
 
@@ -998,7 +990,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 					struct v4l2_fmtdesc *vfd)
 {
 	if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
@@ -1012,7 +1004,7 @@
 	return 0;
 }
 
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
 					struct v4l2_format *vf)
 {
 	struct video_device *dev = video_devdata(file);
@@ -1030,7 +1022,7 @@
 	return 0;
 }
 
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 			       struct v4l2_format *vf)
 {
 	struct video_device *dev = video_devdata(file);
@@ -1060,7 +1052,7 @@
 	return 0;
 }
 
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			       struct v4l2_format *vf)
 {
 	struct video_device *dev = video_devdata(file);
@@ -1068,7 +1060,7 @@
 		(struct usb_usbvision *) video_get_drvdata(dev);
 	int ret;
 
-	if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+	if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
 		return ret;
 	}
 
@@ -1346,9 +1338,7 @@
 		usbvision_release(usbvision);
 	}
 
-
 	PDEBUG(DBG_IO, "success");
-
 	return errCode;
 }
 
@@ -1360,7 +1350,6 @@
 {
 	/* TODO */
 	return -ENODEV;
-
 }
 
 static int usbvision_vbi_close(struct inode *inode, struct file *file)
@@ -1407,10 +1396,10 @@
 	.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_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
@@ -1899,7 +1888,6 @@
 	}
 
 	PDEBUG(DBG_PROBE, "success");
-
 }
 
 static struct usb_driver usbvision_driver = {
diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig
new file mode 100644
index 0000000..c2d9760
--- /dev/null
+++ b/drivers/media/video/uvc/Kconfig
@@ -0,0 +1,17 @@
+config USB_VIDEO_CLASS
+	tristate "USB Video Class (UVC)"
+	---help---
+	  Support for the USB Video Class (UVC).  Currently only video
+	  input devices, such as webcams, are supported.
+
+	  For more information see: <http://linux-uvc.berlios.de/>
+
+config USB_VIDEO_CLASS_INPUT_EVDEV
+	bool "UVC input events device support"
+	default y
+	depends on USB_VIDEO_CLASS && INPUT
+	---help---
+	  This option makes USB Video Class devices register an input device
+	  to report button events.
+
+	  If you are in doubt, say Y.
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index f0ee46d..3ae9551 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1254,3 +1254,4 @@
 	for (; mapping < mend; ++mapping)
 		uvc_ctrl_add_mapping(mapping);
 }
+
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 60ced58..f2b2983 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -298,7 +298,8 @@
 	switch (buffer[2]) {
 	case VS_FORMAT_UNCOMPRESSED:
 	case VS_FORMAT_FRAME_BASED:
-		if (buflen < 27) {
+		n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+		if (buflen < n) {
 			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
 			       "interface %d FORMAT error\n",
 			       dev->udev->devnum,
@@ -1632,13 +1633,16 @@
 	 * reference to the uvc_device instance after uvc_v4l2_open() received
 	 * the pointer to the device (video_devdata) but before it got the
 	 * chance to increase the reference count (kref_get).
+	 *
+	 * Note that the reference can't be released with the lock held,
+	 * otherwise a AB-BA deadlock can occur with videodev_lock that
+	 * videodev acquires in videodev_open() and video_unregister_device().
 	 */
 	mutex_lock(&uvc_driver.open_mutex);
-
 	dev->state |= UVC_DEV_DISCONNECTED;
-	kref_put(&dev->kref, uvc_delete);
-
 	mutex_unlock(&uvc_driver.open_mutex);
+
+	kref_put(&dev->kref, uvc_delete);
 }
 
 static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1825,6 +1829,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Asus F9SG */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x8a31,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
 	/* Syntek (Asus U3S) */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1891,6 +1904,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Medion Akoya Mini E1210 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0141,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* Acer OrbiCam - Unknown vendor */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1953,3 +1975,4 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
+
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 0923f0e..7388d0c 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -475,3 +475,4 @@
 	wake_up(&buf->wait);
 	return nextbuf;
 }
+
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
index be9084e..75e678a 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -22,6 +22,7 @@
 /* --------------------------------------------------------------------------
  * Input device
  */
+#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
 static int uvc_input_init(struct uvc_device *dev)
 {
 	struct usb_device *udev = dev->udev;
@@ -67,6 +68,19 @@
 		input_unregister_device(dev->input);
 }
 
+static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
+	int value)
+{
+	if (dev->input)
+		input_report_key(dev->input, code, value);
+}
+
+#else
+#define uvc_input_init(dev)
+#define uvc_input_cleanup(dev)
+#define uvc_input_report_key(dev, code, value)
+#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
+
 /* --------------------------------------------------------------------------
  * Status interrupt endpoint
  */
@@ -83,8 +97,7 @@
 			return;
 		uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
 			data[1], data[3] ? "pressed" : "released", len);
-		if (dev->input)
-			input_report_key(dev->input, BTN_0, data[3]);
+		uvc_input_report_key(dev, BTN_0, data[3]);
 	} else {
 		uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
 			"len %d.\n", data[1], data[2], data[3], len);
@@ -203,5 +216,6 @@
 	if (dev->int_urb == NULL)
 		return 0;
 
-	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+	return usb_submit_urb(dev->int_urb, GFP_NOIO);
 }
+
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 2e0a665..b5a11eb 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1032,7 +1032,7 @@
 {
 	struct video_device *vdev = video_devdata(file);
 	struct uvc_video_device *video = video_get_drvdata(vdev);
-	struct uvc_buffer *buffer;
+	struct uvc_buffer *uninitialized_var(buffer);
 	struct page *page;
 	unsigned long addr, start, size;
 	unsigned int i;
@@ -1103,3 +1103,4 @@
 	.mmap		= uvc_v4l2_mmap,
 	.poll		= uvc_v4l2_poll,
 };
+
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 6faf1fb..ad63794 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -554,9 +554,56 @@
 }
 
 /*
+ * Free transfer buffers.
+ */
+static void uvc_free_urb_buffers(struct uvc_video_device *video)
+{
+	unsigned int i;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		if (video->urb_buffer[i]) {
+			usb_buffer_free(video->dev->udev, video->urb_size,
+				video->urb_buffer[i], video->urb_dma[i]);
+			video->urb_buffer[i] = NULL;
+		}
+	}
+
+	video->urb_size = 0;
+}
+
+/*
+ * Allocate transfer buffers. This function can be called with buffers
+ * already allocated when resuming from suspend, in which case it will
+ * return without touching the buffers.
+ *
+ * Return 0 on success or -ENOMEM when out of memory.
+ */
+static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+	unsigned int size)
+{
+	unsigned int i;
+
+	/* Buffers are already allocated, bail out. */
+	if (video->urb_size)
+		return 0;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+			size, GFP_KERNEL, &video->urb_dma[i]);
+		if (video->urb_buffer[i] == NULL) {
+			uvc_free_urb_buffers(video);
+			return -ENOMEM;
+		}
+	}
+
+	video->urb_size = size;
+	return 0;
+}
+
+/*
  * Uninitialize isochronous/bulk URBs and free transfer buffers.
  */
-static void uvc_uninit_video(struct uvc_video_device *video)
+static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
 {
 	struct urb *urb;
 	unsigned int i;
@@ -566,19 +613,12 @@
 			continue;
 
 		usb_kill_urb(urb);
-		/* urb->transfer_buffer_length is not touched by USB core, so
-		 * we can use it here as the buffer length.
-		 */
-		if (video->urb_buffer[i]) {
-			usb_buffer_free(video->dev->udev,
-				urb->transfer_buffer_length,
-				video->urb_buffer[i], urb->transfer_dma);
-			video->urb_buffer[i] = NULL;
-		}
-
 		usb_free_urb(urb);
 		video->urb[i] = NULL;
 	}
+
+	if (free_buffers)
+		uvc_free_urb_buffers(video);
 }
 
 /*
@@ -586,7 +626,7 @@
  * is given by the endpoint.
  */
 static int uvc_init_video_isoc(struct uvc_video_device *video,
-	struct usb_host_endpoint *ep)
+	struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
 	struct urb *urb;
 	unsigned int npackets, i, j;
@@ -610,18 +650,13 @@
 
 	size = npackets * psize;
 
-	for (i = 0; i < UVC_URBS; ++i) {
-		urb = usb_alloc_urb(npackets, GFP_KERNEL);
-		if (urb == NULL) {
-			uvc_uninit_video(video);
-			return -ENOMEM;
-		}
+	if (uvc_alloc_urb_buffers(video, size) < 0)
+		return -ENOMEM;
 
-		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-			size, GFP_KERNEL, &urb->transfer_dma);
-		if (video->urb_buffer[i] == NULL) {
-			usb_free_urb(urb);
-			uvc_uninit_video(video);
+	for (i = 0; i < UVC_URBS; ++i) {
+		urb = usb_alloc_urb(npackets, gfp_flags);
+		if (urb == NULL) {
+			uvc_uninit_video(video, 1);
 			return -ENOMEM;
 		}
 
@@ -632,6 +667,7 @@
 		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 		urb->interval = ep->desc.bInterval;
 		urb->transfer_buffer = video->urb_buffer[i];
+		urb->transfer_dma = video->urb_dma[i];
 		urb->complete = uvc_video_complete;
 		urb->number_of_packets = npackets;
 		urb->transfer_buffer_length = size;
@@ -652,7 +688,7 @@
  * given by the endpoint.
  */
 static int uvc_init_video_bulk(struct uvc_video_device *video,
-	struct usb_host_endpoint *ep)
+	struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
 	struct urb *urb;
 	unsigned int pipe, i;
@@ -671,20 +707,15 @@
 	if (size > psize * UVC_MAX_ISO_PACKETS)
 		size = psize * UVC_MAX_ISO_PACKETS;
 
+	if (uvc_alloc_urb_buffers(video, size) < 0)
+		return -ENOMEM;
+
 	pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
 
 	for (i = 0; i < UVC_URBS; ++i) {
-		urb = usb_alloc_urb(0, GFP_KERNEL);
+		urb = usb_alloc_urb(0, gfp_flags);
 		if (urb == NULL) {
-			uvc_uninit_video(video);
-			return -ENOMEM;
-		}
-
-		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-			size, GFP_KERNEL, &urb->transfer_dma);
-		if (video->urb_buffer[i] == NULL) {
-			usb_free_urb(urb);
-			uvc_uninit_video(video);
+			uvc_uninit_video(video, 1);
 			return -ENOMEM;
 		}
 
@@ -692,6 +723,7 @@
 			video->urb_buffer[i], size, uvc_video_complete,
 			video);
 		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		urb->transfer_dma = video->urb_dma[i];
 
 		video->urb[i] = urb;
 	}
@@ -702,7 +734,7 @@
 /*
  * Initialize isochronous/bulk URBs and allocate transfer buffers.
  */
-static int uvc_init_video(struct uvc_video_device *video)
+static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
 {
 	struct usb_interface *intf = video->streaming->intf;
 	struct usb_host_interface *alts;
@@ -747,7 +779,7 @@
 		if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
 			return ret;
 
-		ret = uvc_init_video_isoc(video, ep);
+		ret = uvc_init_video_isoc(video, ep, gfp_flags);
 	} else {
 		/* Bulk endpoint, proceed to URB initialization. */
 		ep = uvc_find_endpoint(&intf->altsetting[0],
@@ -755,7 +787,7 @@
 		if (ep == NULL)
 			return -EIO;
 
-		ret = uvc_init_video_bulk(video, ep);
+		ret = uvc_init_video_bulk(video, ep, gfp_flags);
 	}
 
 	if (ret < 0)
@@ -763,10 +795,10 @@
 
 	/* Submit the URBs. */
 	for (i = 0; i < UVC_URBS; ++i) {
-		if ((ret = usb_submit_urb(video->urb[i], GFP_KERNEL)) < 0) {
+		if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
 			uvc_printk(KERN_ERR, "Failed to submit URB %u "
 					"(%d).\n", i, ret);
-			uvc_uninit_video(video);
+			uvc_uninit_video(video, 1);
 			return ret;
 		}
 	}
@@ -791,7 +823,7 @@
 		return 0;
 
 	video->frozen = 1;
-	uvc_uninit_video(video);
+	uvc_uninit_video(video, 0);
 	usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
 	return 0;
 }
@@ -818,7 +850,7 @@
 	if (!uvc_queue_streaming(&video->queue))
 		return 0;
 
-	if ((ret = uvc_init_video(video)) < 0)
+	if ((ret = uvc_init_video(video, GFP_NOIO)) < 0)
 		uvc_queue_enable(&video->queue, 0);
 
 	return ret;
@@ -920,7 +952,7 @@
 	int ret;
 
 	if (!enable) {
-		uvc_uninit_video(video);
+		uvc_uninit_video(video, 1);
 		usb_set_interface(video->dev->udev,
 			video->streaming->intfnum, 0);
 		uvc_queue_enable(&video->queue, 0);
@@ -930,5 +962,6 @@
 	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
 		return ret;
 
-	return uvc_init_video(video);
+	return uvc_init_video(video, GFP_KERNEL);
 }
+
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index a995a78..bafe340 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -602,6 +602,8 @@
 
 	struct urb *urb[UVC_URBS];
 	char *urb_buffer[UVC_URBS];
+	dma_addr_t urb_dma[UVC_URBS];
+	unsigned int urb_size;
 
 	__u8 last_fid;
 };
@@ -794,3 +796,4 @@
 #endif /* __KERNEL__ */
 
 #endif
+
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
new file mode 100644
index 0000000..03f20ac
--- /dev/null
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -0,0 +1,418 @@
+/*
+ * helper functions for physically contiguous capture buffers
+ *
+ * The functions support hardware lacking scatter gather support
+ * (i.e. the buffers must be linear in physical memory)
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * Based on videobuf-vmalloc.c,
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <media/videobuf-dma-contig.h>
+
+struct videobuf_dma_contig_memory {
+	u32 magic;
+	void *vaddr;
+	dma_addr_t dma_handle;
+	unsigned long size;
+};
+
+#define MAGIC_DC_MEM 0x0733ac61
+#define MAGIC_CHECK(is, should)						\
+	if (unlikely((is) != (should)))	{				\
+		pr_err("magic mismatch: %x expected %x\n", is, should); \
+		BUG();							\
+	}
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+
+	dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+		map, map->count, vma->vm_start, vma->vm_end);
+
+	map->count++;
+}
+
+static void videobuf_vm_close(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+	struct videobuf_queue *q = map->q;
+	int i;
+
+	dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
+		map, map->count, vma->vm_start, vma->vm_end);
+
+	map->count--;
+	if (0 == map->count) {
+		struct videobuf_dma_contig_memory *mem;
+
+		dev_dbg(map->q->dev, "munmap %p q=%p\n", map, q);
+		mutex_lock(&q->vb_lock);
+
+		/* We need first to cancel streams, before unmapping */
+		if (q->streaming)
+			videobuf_queue_cancel(q);
+
+		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+			if (NULL == q->bufs[i])
+				continue;
+
+			if (q->bufs[i]->map != map)
+				continue;
+
+			mem = q->bufs[i]->priv;
+			if (mem) {
+				/* This callback is called only if kernel has
+				   allocated memory and this memory is mmapped.
+				   In this case, memory should be freed,
+				   in order to do memory unmap.
+				 */
+
+				MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+				/* vfree is not atomic - can't be
+				   called with IRQ's disabled
+				 */
+				dev_dbg(map->q->dev, "buf[%d] freeing %p\n",
+					i, mem->vaddr);
+
+				dma_free_coherent(q->dev, mem->size,
+						  mem->vaddr, mem->dma_handle);
+				mem->vaddr = NULL;
+			}
+
+			q->bufs[i]->map   = NULL;
+			q->bufs[i]->baddr = 0;
+		}
+
+		kfree(map);
+
+		mutex_unlock(&q->vb_lock);
+	}
+}
+
+static struct vm_operations_struct videobuf_vm_ops = {
+	.open     = videobuf_vm_open,
+	.close    = videobuf_vm_close,
+};
+
+static void *__videobuf_alloc(size_t size)
+{
+	struct videobuf_dma_contig_memory *mem;
+	struct videobuf_buffer *vb;
+
+	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
+	if (vb) {
+		mem = vb->priv = ((char *)vb) + size;
+		mem->magic = MAGIC_DC_MEM;
+	}
+
+	return vb;
+}
+
+static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_contig_memory *mem = buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	return mem->vaddr;
+}
+
+static int __videobuf_iolock(struct videobuf_queue *q,
+			     struct videobuf_buffer *vb,
+			     struct v4l2_framebuffer *fbuf)
+{
+	struct videobuf_dma_contig_memory *mem = vb->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	switch (vb->memory) {
+	case V4L2_MEMORY_MMAP:
+		dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
+
+		/* All handling should be done by __videobuf_mmap_mapper() */
+		if (!mem->vaddr) {
+			dev_err(q->dev, "memory is not alloced/mmapped.\n");
+			return -EINVAL;
+		}
+		break;
+	case V4L2_MEMORY_USERPTR:
+		dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
+
+		/* The only USERPTR currently supported is the one needed for
+		   read() method.
+		 */
+		if (vb->baddr)
+			return -EINVAL;
+
+		mem->size = PAGE_ALIGN(vb->size);
+		mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
+						&mem->dma_handle, GFP_KERNEL);
+		if (!mem->vaddr) {
+			dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
+					 mem->size);
+			return -ENOMEM;
+		}
+
+		dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
+			mem->vaddr, mem->size);
+		break;
+	case V4L2_MEMORY_OVERLAY:
+	default:
+		dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+			   struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_contig_memory *mem = buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
+				DMA_FROM_DEVICE);
+	return 0;
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+	unsigned int i;
+
+	dev_dbg(q->dev, "%s\n", __func__);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (q->bufs[i] && q->bufs[i]->map)
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+				  struct vm_area_struct *vma)
+{
+	struct videobuf_dma_contig_memory *mem;
+	struct videobuf_mapping *map;
+	unsigned int first;
+	int retval;
+	unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	dev_dbg(q->dev, "%s\n", __func__);
+	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	/* look for first buffer to map */
+	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+		if (!q->bufs[first])
+			continue;
+
+		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+			continue;
+		if (q->bufs[first]->boff == offset)
+			break;
+	}
+	if (VIDEO_MAX_FRAME == first) {
+		dev_dbg(q->dev, "invalid user space offset [offset=0x%lx]\n",
+			offset);
+		return -EINVAL;
+	}
+
+	/* create mapping + update buffer list */
+	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	q->bufs[first]->map = map;
+	map->start = vma->vm_start;
+	map->end = vma->vm_end;
+	map->q = q;
+
+	q->bufs[first]->baddr = vma->vm_start;
+
+	mem = q->bufs[first]->priv;
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
+	mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
+					&mem->dma_handle, GFP_KERNEL);
+	if (!mem->vaddr) {
+		dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
+			mem->size);
+		goto error;
+	}
+	dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
+		mem->vaddr, mem->size);
+
+	/* Try to remap memory */
+
+	size = vma->vm_end - vma->vm_start;
+	size = (size < mem->size) ? size : mem->size;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	retval = remap_pfn_range(vma, vma->vm_start,
+				 mem->dma_handle >> PAGE_SHIFT,
+				 size, vma->vm_page_prot);
+	if (retval) {
+		dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
+		dma_free_coherent(q->dev, mem->size,
+				  mem->vaddr, mem->dma_handle);
+		goto error;
+	}
+
+	vma->vm_ops          = &videobuf_vm_ops;
+	vma->vm_flags       |= VM_DONTEXPAND;
+	vma->vm_private_data = map;
+
+	dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+		map, q, vma->vm_start, vma->vm_end,
+		(long int) q->bufs[first]->bsize,
+		vma->vm_pgoff, first);
+
+	videobuf_vm_open(vma);
+
+	return 0;
+
+error:
+	kfree(map);
+	return -ENOMEM;
+}
+
+static int __videobuf_copy_to_user(struct videobuf_queue *q,
+				   char __user *data, size_t count,
+				   int nonblocking)
+{
+	struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
+	void *vaddr;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+	BUG_ON(!mem->vaddr);
+
+	/* copy to userspace */
+	if (count > q->read_buf->size - q->read_off)
+		count = q->read_buf->size - q->read_off;
+
+	vaddr = mem->vaddr;
+
+	if (copy_to_user(data, vaddr + q->read_off, count))
+		return -EFAULT;
+
+	return count;
+}
+
+static int __videobuf_copy_stream(struct videobuf_queue *q,
+				  char __user *data, size_t count, size_t pos,
+				  int vbihack, int nonblocking)
+{
+	unsigned int  *fc;
+	struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	if (vbihack) {
+		/* dirty, undocumented hack -- pass the frame counter
+			* within the last four bytes of each vbi data block.
+			* We need that one to maintain backward compatibility
+			* to all vbi decoding software out there ... */
+		fc = (unsigned int *)mem->vaddr;
+		fc += (q->read_buf->size >> 2) - 1;
+		*fc = q->read_buf->field_count >> 1;
+		dev_dbg(q->dev, "vbihack: %d\n", *fc);
+	}
+
+	/* copy stuff using the common method */
+	count = __videobuf_copy_to_user(q, data, count, nonblocking);
+
+	if ((count == -EFAULT) && (pos == 0))
+		return -EFAULT;
+
+	return count;
+}
+
+static struct videobuf_qtype_ops qops = {
+	.magic        = MAGIC_QTYPE_OPS,
+
+	.alloc        = __videobuf_alloc,
+	.iolock       = __videobuf_iolock,
+	.sync         = __videobuf_sync,
+	.mmap_free    = __videobuf_mmap_free,
+	.mmap_mapper  = __videobuf_mmap_mapper,
+	.video_copy_to_user = __videobuf_copy_to_user,
+	.copy_stream  = __videobuf_copy_stream,
+	.vmalloc      = __videobuf_to_vmalloc,
+};
+
+void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
+				    struct videobuf_queue_ops *ops,
+				    struct device *dev,
+				    spinlock_t *irqlock,
+				    enum v4l2_buf_type type,
+				    enum v4l2_field field,
+				    unsigned int msize,
+				    void *priv)
+{
+	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+				 priv, &qops);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
+
+dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_contig_memory *mem = buf->priv;
+
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	return mem->dma_handle;
+}
+EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
+
+void videobuf_dma_contig_free(struct videobuf_queue *q,
+			      struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_contig_memory *mem = buf->priv;
+
+	/* mmapped memory can't be freed here, otherwise mmapped region
+	   would be released, while still needed. In this case, the memory
+	   release should happen inside videobuf_vm_close().
+	   So, it should free memory only if the memory were allocated for
+	   read() operation.
+	 */
+	if ((buf->memory != V4L2_MEMORY_USERPTR) || !buf->baddr)
+		return;
+
+	if (!mem)
+		return;
+
+	MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+	dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
+	mem->vaddr = NULL;
+}
+EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
+
+MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 03a7b94..bc6d5ab 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -1,7 +1,7 @@
 /*
  * helper functions for SG DMA video4linux capture buffers
  *
- * The functions expect the hardware being able to scatter gatter
+ * The functions expect the hardware being able to scatter gather
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
  * to touch the video data.
@@ -80,17 +80,15 @@
 videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 {
 	struct scatterlist *sglist;
-	int i = 0;
+	int i;
 
 	if (NULL == pages[0])
 		return NULL;
-	sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
+	sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL);
 	if (NULL == sglist)
 		return NULL;
 	sg_init_table(sglist, nr_pages);
 
-	if (NULL == pages[0])
-		goto nopage;
 	if (PageHighMem(pages[0]))
 		/* DMA to highmem pages might not work */
 		goto highmem;
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 6e4d73e..b56cffc 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -13,7 +13,6 @@
  * (at your option) any later version.
  */
 
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -257,4 +256,3 @@
  * compile-command: "make DVB=1"
  * End:
  */
-
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index c91e1d8..a868b7e 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -1,7 +1,7 @@
 /*
  * helper functions for vmalloc video4linux capture buffers
  *
- * The functions expect the hardware being able to scatter gatter
+ * The functions expect the hardware being able to scatter gather
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
  * to touch the video data.
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 7649860..6616e65 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -17,15 +17,19 @@
  */
 
 #define dbgarg(cmd, fmt, arg...) \
-		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {		\
+		do {							\
+		    if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {		\
 			printk(KERN_DEBUG "%s: ",  vfd->name);		\
 			v4l_printk_ioctl(cmd);				\
 			printk(" " fmt,  ## arg);			\
-		}
+		    }							\
+		} while (0)
 
 #define dbgarg2(fmt, arg...) \
-		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)			\
-			printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+		do {							\
+		    if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)		\
+			printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
+		} while (0)
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -138,7 +142,7 @@
 /* ----------------------------------------------------------------- */
 /* some arrays for pretty-printing debug messages of enum types      */
 
-char *v4l2_field_names[] = {
+const char *v4l2_field_names[] = {
 	[V4L2_FIELD_ANY]        = "any",
 	[V4L2_FIELD_NONE]       = "none",
 	[V4L2_FIELD_TOP]        = "top",
@@ -152,19 +156,19 @@
 };
 EXPORT_SYMBOL(v4l2_field_names);
 
-char *v4l2_type_names[] = {
-	[V4L2_BUF_TYPE_VIDEO_CAPTURE]      = "video-cap",
-	[V4L2_BUF_TYPE_VIDEO_OVERLAY]      = "video-over",
-	[V4L2_BUF_TYPE_VIDEO_OUTPUT]       = "video-out",
+const char *v4l2_type_names[] = {
+	[V4L2_BUF_TYPE_VIDEO_CAPTURE]      = "vid-cap",
+	[V4L2_BUF_TYPE_VIDEO_OVERLAY]      = "vid-overlay",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT]       = "vid-out",
 	[V4L2_BUF_TYPE_VBI_CAPTURE]        = "vbi-cap",
 	[V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
 	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
 	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
-	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
 };
 EXPORT_SYMBOL(v4l2_type_names);
 
-static char *v4l2_memory_names[] = {
+static const char *v4l2_memory_names[] = {
 	[V4L2_MEMORY_MMAP]    = "mmap",
 	[V4L2_MEMORY_USERPTR] = "userptr",
 	[V4L2_MEMORY_OVERLAY] = "overlay",
@@ -278,6 +282,7 @@
 	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
 	[_IOC_NR(VIDIOC_G_CHIP_IDENT)]     = "VIDIOC_G_CHIP_IDENT",
+	[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)]   = "VIDIOC_S_HW_FREQ_SEEK",
 #endif
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -371,6 +376,14 @@
  *	sysfs stuff
  */
 
+static ssize_t show_index(struct device *cd,
+			 struct device_attribute *attr, char *buf)
+{
+	struct video_device *vfd = container_of(cd, struct video_device,
+						class_dev);
+	return sprintf(buf, "%i\n", vfd->index);
+}
+
 static ssize_t show_name(struct device *cd,
 			 struct device_attribute *attr, char *buf)
 {
@@ -379,6 +392,12 @@
 	return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
 }
 
+static struct device_attribute video_device_attrs[] = {
+	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR(index, S_IRUGO, show_index, NULL),
+	__ATTR_NULL
+};
+
 struct video_device *video_device_alloc(void)
 {
 	struct video_device *vfd;
@@ -407,11 +426,6 @@
 	vfd->release(vfd);
 }
 
-static struct device_attribute video_device_attrs[] = {
-	__ATTR(name, S_IRUGO, show_name, NULL),
-	__ATTR_NULL
-};
-
 static struct class video_class = {
 	.name    = VIDEO_NAME,
 	.dev_attrs = video_device_attrs,
@@ -650,7 +664,7 @@
 			p->field, p->sequence,
 			prt_names(p->memory, v4l2_memory_names),
 			p->m.userptr, p->length);
-	dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+	dbgarg2("timecode=%02d:%02d:%02d type=%d, "
 		"flags=0x%08d, frames=%d, userbits=0x%08x\n",
 			tc->hours,tc->minutes,tc->seconds,
 			tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
@@ -659,7 +673,7 @@
 static inline void dbgrect(struct video_device *vfd, char *s,
 							struct v4l2_rect *r)
 {
-	dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+	dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top,
 						r->width, r->height);
 };
 
@@ -677,40 +691,85 @@
 		fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
 };
 
+static inline void v4l_print_ext_ctrls(unsigned int cmd,
+	struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
+{
+	__u32 i;
+
+	if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG))
+		return;
+	dbgarg(cmd, "");
+	printk(KERN_CONT "class=0x%x", c->ctrl_class);
+	for (i = 0; i < c->count; i++) {
+		if (show_vals)
+			printk(KERN_CONT " id/val=0x%x/0x%x",
+				c->controls[i].id, c->controls[i].value);
+		else
+			printk(KERN_CONT " id=0x%x", c->controls[i].id);
+	}
+	printk(KERN_CONT "\n");
+};
+
+static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+{
+	__u32 i;
+
+	/* zero the reserved fields */
+	c->reserved[0] = c->reserved[1] = 0;
+	for (i = 0; i < c->count; i++) {
+		c->controls[i].reserved2[0] = 0;
+		c->controls[i].reserved2[1] = 0;
+	}
+	/* V4L2_CID_PRIVATE_BASE cannot be used as control class
+	   when using extended controls.
+	   Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
+	   is it allowed for backwards compatibility.
+	 */
+	if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
+		return 0;
+	/* Check that all controls are from the same control class. */
+	for (i = 0; i < c->count; i++) {
+		if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
+			c->error_idx = i;
+			return 0;
+		}
+	}
+	return 1;
+}
 
 static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
 {
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (vfd->vidioc_try_fmt_cap)
+		if (vfd->vidioc_try_fmt_vid_cap)
 			return (0);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		if (vfd->vidioc_try_fmt_overlay)
-			return (0);
-		break;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		if (vfd->vidioc_try_fmt_vbi)
-			return (0);
-		break;
-	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-		if (vfd->vidioc_try_fmt_vbi_output)
-			return (0);
-		break;
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-		if (vfd->vidioc_try_fmt_vbi_capture)
+		if (vfd->vidioc_try_fmt_vid_overlay)
 			return (0);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		if (vfd->vidioc_try_fmt_video_output)
-			return (0);
-		break;
-	case V4L2_BUF_TYPE_VBI_OUTPUT:
-		if (vfd->vidioc_try_fmt_vbi_output)
+		if (vfd->vidioc_try_fmt_vid_out)
 			return (0);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-		if (vfd->vidioc_try_fmt_output_overlay)
+		if (vfd->vidioc_try_fmt_vid_out_overlay)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (vfd->vidioc_try_fmt_vbi_cap)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+		if (vfd->vidioc_try_fmt_vbi_out)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		if (vfd->vidioc_try_fmt_sliced_vbi_cap)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		if (vfd->vidioc_try_fmt_sliced_vbi_out)
 			return (0);
 		break;
 	case V4L2_BUF_TYPE_PRIVATE:
@@ -827,46 +886,37 @@
 
 		switch (type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			if (vfd->vidioc_enum_fmt_cap)
-				ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+			if (vfd->vidioc_enum_fmt_vid_cap)
+				ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (vfd->vidioc_enum_fmt_overlay)
-				ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+			if (vfd->vidioc_enum_fmt_vid_overlay)
+				ret = vfd->vidioc_enum_fmt_vid_overlay(file,
+					fh, f);
 			break;
+#if 1
+		/* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT
+		 * according to the spec. The bttv and saa7134 drivers support
+		 * it though, so just warn that this is deprecated and will be
+		 * removed in the near future. */
 		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (vfd->vidioc_enum_fmt_vbi)
-				ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+			if (vfd->vidioc_enum_fmt_vbi_cap) {
+				printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n");
+				ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f);
+			}
 			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-			if (vfd->vidioc_enum_fmt_vbi_output)
-				ret=vfd->vidioc_enum_fmt_vbi_output(file,
-								fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-			if (vfd->vidioc_enum_fmt_vbi_capture)
-				ret=vfd->vidioc_enum_fmt_vbi_capture(file,
-								fh, f);
-			break;
+#endif
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (vfd->vidioc_enum_fmt_video_output)
-				ret=vfd->vidioc_enum_fmt_video_output(file,
-								fh, f);
-			break;
-		case V4L2_BUF_TYPE_VBI_OUTPUT:
-			if (vfd->vidioc_enum_fmt_vbi_output)
-				ret=vfd->vidioc_enum_fmt_vbi_output(file,
-								fh, f);
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-			if (vfd->vidioc_enum_fmt_output_overlay)
-				ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
+			if (vfd->vidioc_enum_fmt_vid_out)
+				ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (vfd->vidioc_enum_fmt_type_private)
-				ret=vfd->vidioc_enum_fmt_type_private(file,
+				ret = vfd->vidioc_enum_fmt_type_private(file,
 								fh, f);
 			break;
+		default:
+			break;
 		}
 		if (!ret)
 			dbgarg (cmd, "index=%d, type=%d, flags=%d, "
@@ -882,54 +932,56 @@
 	case VIDIOC_G_FMT:
 	{
 		struct v4l2_format *f = (struct v4l2_format *)arg;
-		enum v4l2_buf_type type=f->type;
 
-		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-		f->type=type;
+		memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
 
 		/* FIXME: Should be one dump per type */
-		dbgarg (cmd, "type=%s\n", prt_names(type,
-					v4l2_type_names));
+		dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
-		switch (type) {
+		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			if (vfd->vidioc_g_fmt_cap)
-				ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+			if (vfd->vidioc_g_fmt_vid_cap)
+				ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f);
 			if (!ret)
-				v4l_print_pix_fmt(vfd,&f->fmt.pix);
+				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (vfd->vidioc_g_fmt_overlay)
-				ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (vfd->vidioc_g_fmt_vbi)
-				ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-			if (vfd->vidioc_g_fmt_vbi_output)
-				ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-			if (vfd->vidioc_g_fmt_vbi_capture)
-				ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+			if (vfd->vidioc_g_fmt_vid_overlay)
+				ret = vfd->vidioc_g_fmt_vid_overlay(file,
+								    fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (vfd->vidioc_g_fmt_video_output)
-				ret=vfd->vidioc_g_fmt_video_output(file,
-								fh, f);
+			if (vfd->vidioc_g_fmt_vid_out)
+				ret = vfd->vidioc_g_fmt_vid_out(file, fh, f);
+			if (!ret)
+				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-			if (vfd->vidioc_g_fmt_output_overlay)
-				ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
+			if (vfd->vidioc_g_fmt_vid_out_overlay)
+				ret = vfd->vidioc_g_fmt_vid_out_overlay(file,
+				       fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_g_fmt_vbi_cap)
+				ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
-			if (vfd->vidioc_g_fmt_vbi_output)
-				ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+			if (vfd->vidioc_g_fmt_vbi_out)
+				ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_g_fmt_sliced_vbi_cap)
+				ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file,
+									fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_g_fmt_sliced_vbi_out)
+				ret = vfd->vidioc_g_fmt_sliced_vbi_out(file,
+									fh, f);
 			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (vfd->vidioc_g_fmt_type_private)
-				ret=vfd->vidioc_g_fmt_type_private(file,
+				ret = vfd->vidioc_g_fmt_type_private(file,
 								fh, f);
 			break;
 		}
@@ -941,48 +993,50 @@
 		struct v4l2_format *f = (struct v4l2_format *)arg;
 
 		/* FIXME: Should be one dump per type */
-		dbgarg (cmd, "type=%s\n", prt_names(f->type,
-					v4l2_type_names));
+		dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			v4l_print_pix_fmt(vfd,&f->fmt.pix);
-			if (vfd->vidioc_s_fmt_cap)
-				ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+			v4l_print_pix_fmt(vfd, &f->fmt.pix);
+			if (vfd->vidioc_s_fmt_vid_cap)
+				ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (vfd->vidioc_s_fmt_overlay)
-				ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (vfd->vidioc_s_fmt_vbi)
-				ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-			if (vfd->vidioc_s_fmt_vbi_output)
-				ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-			if (vfd->vidioc_s_fmt_vbi_capture)
-				ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+			if (vfd->vidioc_s_fmt_vid_overlay)
+				ret = vfd->vidioc_s_fmt_vid_overlay(file,
+								    fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (vfd->vidioc_s_fmt_video_output)
-				ret=vfd->vidioc_s_fmt_video_output(file,
-								fh, f);
+			v4l_print_pix_fmt(vfd, &f->fmt.pix);
+			if (vfd->vidioc_s_fmt_vid_out)
+				ret = vfd->vidioc_s_fmt_vid_out(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-			if (vfd->vidioc_s_fmt_output_overlay)
-				ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
+			if (vfd->vidioc_s_fmt_vid_out_overlay)
+				ret = vfd->vidioc_s_fmt_vid_out_overlay(file,
+					fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_s_fmt_vbi_cap)
+				ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
-			if (vfd->vidioc_s_fmt_vbi_output)
-				ret=vfd->vidioc_s_fmt_vbi_output(file,
-								fh, f);
+			if (vfd->vidioc_s_fmt_vbi_out)
+				ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_s_fmt_sliced_vbi_cap)
+				ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file,
+									fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_s_fmt_sliced_vbi_out)
+				ret = vfd->vidioc_s_fmt_sliced_vbi_out(file,
+									fh, f);
 			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (vfd->vidioc_s_fmt_type_private)
-				ret=vfd->vidioc_s_fmt_type_private(file,
+				ret = vfd->vidioc_s_fmt_type_private(file,
 								fh, f);
 			break;
 		}
@@ -997,46 +1051,48 @@
 						v4l2_type_names));
 		switch (f->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			if (vfd->vidioc_try_fmt_cap)
-				ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+			if (vfd->vidioc_try_fmt_vid_cap)
+				ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f);
 			if (!ret)
-				v4l_print_pix_fmt(vfd,&f->fmt.pix);
+				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (vfd->vidioc_try_fmt_overlay)
-				ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (vfd->vidioc_try_fmt_vbi)
-				ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-			if (vfd->vidioc_try_fmt_vbi_output)
-				ret=vfd->vidioc_try_fmt_vbi_output(file,
-								fh, f);
-			break;
-		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-			if (vfd->vidioc_try_fmt_vbi_capture)
-				ret=vfd->vidioc_try_fmt_vbi_capture(file,
-								fh, f);
+			if (vfd->vidioc_try_fmt_vid_overlay)
+				ret = vfd->vidioc_try_fmt_vid_overlay(file,
+					fh, f);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-			if (vfd->vidioc_try_fmt_video_output)
-				ret=vfd->vidioc_try_fmt_video_output(file,
-								fh, f);
+			if (vfd->vidioc_try_fmt_vid_out)
+				ret = vfd->vidioc_try_fmt_vid_out(file, fh, f);
+			if (!ret)
+				v4l_print_pix_fmt(vfd, &f->fmt.pix);
 			break;
 		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-			if (vfd->vidioc_try_fmt_output_overlay)
-				ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
+			if (vfd->vidioc_try_fmt_vid_out_overlay)
+				ret = vfd->vidioc_try_fmt_vid_out_overlay(file,
+				       fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_try_fmt_vbi_cap)
+				ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f);
 			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
-			if (vfd->vidioc_try_fmt_vbi_output)
-				ret=vfd->vidioc_try_fmt_vbi_output(file,
+			if (vfd->vidioc_try_fmt_vbi_out)
+				ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_try_fmt_sliced_vbi_cap)
+				ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_try_fmt_sliced_vbi_out)
+				ret = vfd->vidioc_try_fmt_sliced_vbi_out(file,
 								fh, f);
 			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (vfd->vidioc_try_fmt_type_private)
-				ret=vfd->vidioc_try_fmt_type_private(file,
+				ret = vfd->vidioc_try_fmt_type_private(file,
 								fh, f);
 			break;
 		}
@@ -1120,29 +1176,29 @@
 	}
 	case VIDIOC_G_FBUF:
 	{
-		struct v4l2_framebuffer *p=arg;
+		struct v4l2_framebuffer *p = arg;
+
 		if (!vfd->vidioc_g_fbuf)
 			break;
-		ret=vfd->vidioc_g_fbuf(file, fh, arg);
+		ret = vfd->vidioc_g_fbuf(file, fh, arg);
 		if (!ret) {
-			dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
-					p->capability,p->flags,
+			dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
+					p->capability, p->flags,
 					(unsigned long)p->base);
-			v4l_print_pix_fmt (vfd, &p->fmt);
+			v4l_print_pix_fmt(vfd, &p->fmt);
 		}
 		break;
 	}
 	case VIDIOC_S_FBUF:
 	{
-		struct v4l2_framebuffer *p=arg;
+		struct v4l2_framebuffer *p = arg;
+
 		if (!vfd->vidioc_s_fbuf)
 			break;
-
-		dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
-				p->capability,p->flags,(unsigned long)p->base);
-		v4l_print_pix_fmt (vfd, &p->fmt);
-		ret=vfd->vidioc_s_fbuf(file, fh, arg);
-
+		dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
+			p->capability, p->flags, (unsigned long)p->base);
+		v4l_print_pix_fmt(vfd, &p->fmt);
+		ret = vfd->vidioc_s_fbuf(file, fh, arg);
 		break;
 	}
 	case VIDIOC_STREAMON:
@@ -1194,7 +1250,7 @@
 		v4l2_video_std_construct(p, curr_id, descr);
 		p->index = index;
 
-		dbgarg(cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+		dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
 				"framelines=%d\n", p->index,
 				(unsigned long long)p->id, p->name,
 				p->frameperiod.numerator,
@@ -1208,18 +1264,22 @@
 	{
 		v4l2_std_id *id = arg;
 
-		*id = vfd->current_norm;
+		ret = 0;
+		/* Calls the specific handler */
+		if (vfd->vidioc_g_std)
+			ret = vfd->vidioc_g_std(file, fh, id);
+		else
+			*id = vfd->current_norm;
 
-		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
-
-		ret=0;
+		if (!ret)
+			dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
 		break;
 	}
 	case VIDIOC_S_STD:
 	{
 		v4l2_std_id *id = arg,norm;
 
-		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+		dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
 
 		norm = (*id) & vfd->tvnorms;
 		if ( vfd->tvnorms && !norm)	/* Check if std is supported */
@@ -1295,6 +1355,25 @@
 	}
 
 	/* ------ output switching ---------- */
+	case VIDIOC_ENUMOUTPUT:
+	{
+		struct v4l2_output *p = arg;
+		int i = p->index;
+
+		if (!vfd->vidioc_enum_output)
+			break;
+		memset(p, 0, sizeof(*p));
+		p->index = i;
+
+		ret = vfd->vidioc_enum_output(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "index=%d, name=%s, type=%d, "
+				"audioset=0x%x, "
+				"modulator=%d, std=0x%08Lx\n",
+				p->index, p->name, p->type, p->audioset,
+				p->modulator, (unsigned long long)p->std);
+		break;
+	}
 	case VIDIOC_G_OUTPUT:
 	{
 		unsigned int *i = arg;
@@ -1320,132 +1399,172 @@
 	/* --- controls ---------------------------------------------- */
 	case VIDIOC_QUERYCTRL:
 	{
-		struct v4l2_queryctrl *p=arg;
+		struct v4l2_queryctrl *p = arg;
 
 		if (!vfd->vidioc_queryctrl)
 			break;
-		ret=vfd->vidioc_queryctrl(file, fh, p);
-
+		ret = vfd->vidioc_queryctrl(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "id=%d, type=%d, name=%s, "
-					"min/max=%d/%d,"
-					" step=%d, default=%d, flags=0x%08x\n",
-					p->id,p->type,p->name,p->minimum,
-					p->maximum,p->step,p->default_value,
-					p->flags);
+			dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, "
+					"step=%d, default=%d, flags=0x%08x\n",
+					p->id, p->type, p->name,
+					p->minimum, p->maximum,
+					p->step, p->default_value, p->flags);
+		else
+			dbgarg(cmd, "id=0x%x\n", p->id);
 		break;
 	}
 	case VIDIOC_G_CTRL:
 	{
 		struct v4l2_control *p = arg;
 
-		if (!vfd->vidioc_g_ctrl)
-			break;
-		dbgarg(cmd, "Enum for index=%d\n", p->id);
+		if (vfd->vidioc_g_ctrl)
+			ret = vfd->vidioc_g_ctrl(file, fh, p);
+		else if (vfd->vidioc_g_ext_ctrls) {
+			struct v4l2_ext_controls ctrls;
+			struct v4l2_ext_control ctrl;
 
-		ret=vfd->vidioc_g_ctrl(file, fh, p);
+			ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+			ctrls.count = 1;
+			ctrls.controls = &ctrl;
+			ctrl.id = p->id;
+			ctrl.value = p->value;
+			if (check_ext_ctrls(&ctrls, 1)) {
+				ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls);
+				if (ret == 0)
+					p->value = ctrl.value;
+			}
+		} else
+			break;
 		if (!ret)
-			dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+			dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+		else
+			dbgarg(cmd, "id=0x%x\n", p->id);
 		break;
 	}
 	case VIDIOC_S_CTRL:
 	{
 		struct v4l2_control *p = arg;
+		struct v4l2_ext_controls ctrls;
+		struct v4l2_ext_control ctrl;
 
-		if (!vfd->vidioc_s_ctrl)
+		if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls)
 			break;
-		dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
 
-		ret=vfd->vidioc_s_ctrl(file, fh, p);
+		dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+
+		if (vfd->vidioc_s_ctrl) {
+			ret = vfd->vidioc_s_ctrl(file, fh, p);
+			break;
+		}
+		if (!vfd->vidioc_s_ext_ctrls)
+			break;
+
+		ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+		ctrls.count = 1;
+		ctrls.controls = &ctrl;
+		ctrl.id = p->id;
+		ctrl.value = p->value;
+		if (check_ext_ctrls(&ctrls, 1))
+			ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls);
 		break;
 	}
 	case VIDIOC_G_EXT_CTRLS:
 	{
 		struct v4l2_ext_controls *p = arg;
 
-		if (vfd->vidioc_g_ext_ctrls) {
-			dbgarg(cmd, "count=%d\n", p->count);
-
-			ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
-		}
+		p->error_idx = p->count;
+		if (!vfd->vidioc_g_ext_ctrls)
+			break;
+		if (check_ext_ctrls(p, 0))
+			ret = vfd->vidioc_g_ext_ctrls(file, fh, p);
+		v4l_print_ext_ctrls(cmd, vfd, p, !ret);
 		break;
 	}
 	case VIDIOC_S_EXT_CTRLS:
 	{
 		struct v4l2_ext_controls *p = arg;
 
-		if (vfd->vidioc_s_ext_ctrls) {
-			dbgarg(cmd, "count=%d\n", p->count);
-
-			ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
-		}
+		p->error_idx = p->count;
+		if (!vfd->vidioc_s_ext_ctrls)
+			break;
+		v4l_print_ext_ctrls(cmd, vfd, p, 1);
+		if (check_ext_ctrls(p, 0))
+			ret = vfd->vidioc_s_ext_ctrls(file, fh, p);
 		break;
 	}
 	case VIDIOC_TRY_EXT_CTRLS:
 	{
 		struct v4l2_ext_controls *p = arg;
 
-		if (vfd->vidioc_try_ext_ctrls) {
-			dbgarg(cmd, "count=%d\n", p->count);
-
-			ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
-		}
+		p->error_idx = p->count;
+		if (!vfd->vidioc_try_ext_ctrls)
+			break;
+		v4l_print_ext_ctrls(cmd, vfd, p, 1);
+		if (check_ext_ctrls(p, 0))
+			ret = vfd->vidioc_try_ext_ctrls(file, fh, p);
 		break;
 	}
 	case VIDIOC_QUERYMENU:
 	{
-		struct v4l2_querymenu *p=arg;
+		struct v4l2_querymenu *p = arg;
+
 		if (!vfd->vidioc_querymenu)
 			break;
-		ret=vfd->vidioc_querymenu(file, fh, p);
+		ret = vfd->vidioc_querymenu(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "id=%d, index=%d, name=%s\n",
-						p->id,p->index,p->name);
+			dbgarg(cmd, "id=0x%x, index=%d, name=%s\n",
+				p->id, p->index, p->name);
+		else
+			dbgarg(cmd, "id=0x%x, index=%d\n",
+				p->id, p->index);
 		break;
 	}
 	/* --- audio ---------------------------------------------- */
 	case VIDIOC_ENUMAUDIO:
 	{
-		struct v4l2_audio *p=arg;
+		struct v4l2_audio *p = arg;
 
 		if (!vfd->vidioc_enumaudio)
 			break;
-		dbgarg(cmd, "Enum for index=%d\n", p->index);
-		ret=vfd->vidioc_enumaudio(file, fh, p);
+		ret = vfd->vidioc_enumaudio(file, fh, p);
 		if (!ret)
-			dbgarg2("index=%d, name=%s, capability=%d, "
-					"mode=%d\n",p->index,p->name,
+			dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+					"mode=0x%x\n", p->index, p->name,
 					p->capability, p->mode);
+		else
+			dbgarg(cmd, "index=%d\n", p->index);
 		break;
 	}
 	case VIDIOC_G_AUDIO:
 	{
-		struct v4l2_audio *p=arg;
-		__u32 index=p->index;
+		struct v4l2_audio *p = arg;
+		__u32 index = p->index;
 
 		if (!vfd->vidioc_g_audio)
 			break;
 
-		memset(p,0,sizeof(*p));
-		p->index=index;
-		dbgarg(cmd, "Get for index=%d\n", p->index);
-		ret=vfd->vidioc_g_audio(file, fh, p);
+		memset(p, 0, sizeof(*p));
+		p->index = index;
+		ret = vfd->vidioc_g_audio(file, fh, p);
 		if (!ret)
-			dbgarg2("index=%d, name=%s, capability=%d, "
-					"mode=%d\n",p->index,
-					p->name,p->capability, p->mode);
+			dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+					"mode=0x%x\n", p->index,
+					p->name, p->capability, p->mode);
+		else
+			dbgarg(cmd, "index=%d\n", p->index);
 		break;
 	}
 	case VIDIOC_S_AUDIO:
 	{
-		struct v4l2_audio *p=arg;
+		struct v4l2_audio *p = arg;
 
 		if (!vfd->vidioc_s_audio)
 			break;
-		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
-					"mode=%d\n", p->index, p->name,
+		dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+					"mode=0x%x\n", p->index, p->name,
 					p->capability, p->mode);
-		ret=vfd->vidioc_s_audio(file, fh, p);
+		ret = vfd->vidioc_s_audio(file, fh, p);
 		break;
 	}
 	case VIDIOC_ENUMAUDOUT:
@@ -1521,9 +1640,9 @@
 		struct v4l2_crop *p=arg;
 		if (!vfd->vidioc_g_crop)
 			break;
+		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		ret=vfd->vidioc_g_crop(file, fh, p);
 		if (!ret) {
-			dbgarg(cmd, "type=%d\n", p->type);
 			dbgrect(vfd, "", &p->c);
 		}
 		break;
@@ -1533,21 +1652,24 @@
 		struct v4l2_crop *p=arg;
 		if (!vfd->vidioc_s_crop)
 			break;
-		dbgarg(cmd, "type=%d\n", p->type);
+		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		dbgrect(vfd, "", &p->c);
 		ret=vfd->vidioc_s_crop(file, fh, p);
 		break;
 	}
 	case VIDIOC_CROPCAP:
 	{
-		struct v4l2_cropcap *p=arg;
+		struct v4l2_cropcap *p = arg;
+
 		/*FIXME: Should also show v4l2_fract pixelaspect */
 		if (!vfd->vidioc_cropcap)
 			break;
-		dbgarg(cmd, "type=%d\n", p->type);
-		dbgrect(vfd, "bounds ", &p->bounds);
-		dbgrect(vfd, "defrect ", &p->defrect);
-		ret=vfd->vidioc_cropcap(file, fh, p);
+		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+		ret = vfd->vidioc_cropcap(file, fh, p);
+		if (!ret) {
+			dbgrect(vfd, "bounds ", &p->bounds);
+			dbgrect(vfd, "defrect ", &p->defrect);
+		}
 		break;
 	}
 	case VIDIOC_G_JPEGCOMP:
@@ -1590,26 +1712,26 @@
 	}
 	case VIDIOC_ENCODER_CMD:
 	{
-		struct v4l2_encoder_cmd *p=arg;
+		struct v4l2_encoder_cmd *p = arg;
 
 		if (!vfd->vidioc_encoder_cmd)
 			break;
-		ret=vfd->vidioc_encoder_cmd(file, fh, p);
+		memset(&p->raw, 0, sizeof(p->raw));
+		ret = vfd->vidioc_encoder_cmd(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "cmd=%d, flags=%d\n",
-					p->cmd,p->flags);
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
 		break;
 	}
 	case VIDIOC_TRY_ENCODER_CMD:
 	{
-		struct v4l2_encoder_cmd *p=arg;
+		struct v4l2_encoder_cmd *p = arg;
 
 		if (!vfd->vidioc_try_encoder_cmd)
 			break;
-		ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
+		memset(&p->raw, 0, sizeof(p->raw));
+		ret = vfd->vidioc_try_encoder_cmd(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "cmd=%d, flags=%d\n",
-					p->cmd,p->flags);
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
 		break;
 	}
 	case VIDIOC_G_PARM:
@@ -1649,54 +1771,57 @@
 	}
 	case VIDIOC_G_TUNER:
 	{
-		struct v4l2_tuner *p=arg;
-		__u32 index=p->index;
+		struct v4l2_tuner *p = arg;
+		__u32 index = p->index;
 
 		if (!vfd->vidioc_g_tuner)
 			break;
 
-		memset(p,0,sizeof(*p));
-		p->index=index;
+		memset(p, 0, sizeof(*p));
+		p->index = index;
 
-		ret=vfd->vidioc_g_tuner(file, fh, p);
+		ret = vfd->vidioc_g_tuner(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "index=%d, name=%s, type=%d, "
-					"capability=%d, rangelow=%d, "
+			dbgarg(cmd, "index=%d, name=%s, type=%d, "
+					"capability=0x%x, rangelow=%d, "
 					"rangehigh=%d, signal=%d, afc=%d, "
-					"rxsubchans=%d, audmode=%d\n",
+					"rxsubchans=0x%x, audmode=%d\n",
 					p->index, p->name, p->type,
 					p->capability, p->rangelow,
-					p->rangehigh, p->rxsubchans,
-					p->audmode, p->signal, p->afc);
+					p->rangehigh, p->signal, p->afc,
+					p->rxsubchans, p->audmode);
 		break;
 	}
 	case VIDIOC_S_TUNER:
 	{
-		struct v4l2_tuner *p=arg;
+		struct v4l2_tuner *p = arg;
+
 		if (!vfd->vidioc_s_tuner)
 			break;
-		dbgarg (cmd, "index=%d, name=%s, type=%d, "
-				"capability=%d, rangelow=%d, rangehigh=%d, "
-				"signal=%d, afc=%d, rxsubchans=%d, "
-				"audmode=%d\n",p->index, p->name, p->type,
-				p->capability, p->rangelow,p->rangehigh,
-				p->rxsubchans, p->audmode, p->signal,
-				p->afc);
-		ret=vfd->vidioc_s_tuner(file, fh, p);
+		dbgarg(cmd, "index=%d, name=%s, type=%d, "
+				"capability=0x%x, rangelow=%d, "
+				"rangehigh=%d, signal=%d, afc=%d, "
+				"rxsubchans=0x%x, audmode=%d\n",
+				p->index, p->name, p->type,
+				p->capability, p->rangelow,
+				p->rangehigh, p->signal, p->afc,
+				p->rxsubchans, p->audmode);
+		ret = vfd->vidioc_s_tuner(file, fh, p);
 		break;
 	}
 	case VIDIOC_G_FREQUENCY:
 	{
-		struct v4l2_frequency *p=arg;
+		struct v4l2_frequency *p = arg;
+
 		if (!vfd->vidioc_g_frequency)
 			break;
 
-		memset(p,0,sizeof(*p));
+		memset(p->reserved, 0, sizeof(p->reserved));
 
-		ret=vfd->vidioc_g_frequency(file, fh, p);
+		ret = vfd->vidioc_g_frequency(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
-						p->tuner,p->type,p->frequency);
+			dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
+					p->tuner, p->type, p->frequency);
 		break;
 	}
 	case VIDIOC_S_FREQUENCY:
@@ -1711,12 +1836,17 @@
 	}
 	case VIDIOC_G_SLICED_VBI_CAP:
 	{
-		struct v4l2_sliced_vbi_cap *p=arg;
+		struct v4l2_sliced_vbi_cap *p = arg;
+		__u32 type = p->type;
+
 		if (!vfd->vidioc_g_sliced_vbi_cap)
 			break;
-		ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+		memset(p, 0, sizeof(*p));
+		p->type = type;
+		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+		ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
 		if (!ret)
-			dbgarg (cmd, "service_set=%d\n", p->service_set);
+			dbgarg2("service_set=%d\n", p->service_set);
 		break;
 	}
 	case VIDIOC_LOG_STATUS:
@@ -1763,13 +1893,23 @@
 		ret = vfd->vidioc_default(file, fh, cmd, arg);
 		break;
 	}
+	case VIDIOC_S_HW_FREQ_SEEK:
+	{
+		struct v4l2_hw_freq_seek *p = arg;
+		if (!vfd->vidioc_s_hw_freq_seek)
+			break;
+		dbgarg(cmd,
+			"tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n",
+			p->tuner, p->type, p->seek_upward, p->wrap_around);
+		ret = vfd->vidioc_s_hw_freq_seek(file, fh, p);
+		break;
+	}
 	} /* switch */
 
 	if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
-		if (ret<0) {
-			printk("%s: err: on ", vfd->name);
+		if (ret < 0) {
 			v4l_print_ioctl(vfd->name, cmd);
-			printk("\n");
+			printk(KERN_CONT " error %d\n", ret);
 		}
 	}
 
@@ -1871,8 +2011,55 @@
 }
 EXPORT_SYMBOL(video_ioctl2);
 
+/**
+ * get_index - assign stream number based on parent device
+ * @vdev: video_device to assign index number to, vdev->dev should be assigned
+ * @num: -1 if auto assign, requested number otherwise
+ *
+ *
+ * returns -ENFILE if num is already in use, a free index number if
+ * successful.
+ */
+static int get_index(struct video_device *vdev, int num)
+{
+	u32 used = 0;
+	const int max_index = sizeof(used) * 8 - 1;
+	int i;
+
+	/* Currently a single v4l driver instance cannot create more than
+	   32 devices.
+	   Increase to u64 or an array of u32 if more are needed. */
+	if (num > max_index) {
+		printk(KERN_ERR "videodev: %s num is too large\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+		if (video_device[i] != NULL &&
+		    video_device[i] != vdev &&
+		    video_device[i]->dev == vdev->dev) {
+			used |= 1 << video_device[i]->index;
+		}
+	}
+
+	if (num >= 0) {
+		if (used & (1 << num))
+			return -ENFILE;
+		return num;
+	}
+
+	i = ffz(used);
+	return i > max_index ? -ENFILE : i;
+}
+
 static const struct file_operations video_fops;
 
+int video_register_device(struct video_device *vfd, int type, int nr)
+{
+	return video_register_device_index(vfd, type, nr, -1);
+}
+EXPORT_SYMBOL(video_register_device);
+
 /**
  *	video_register_device - register video4linux devices
  *	@vfd:  video device structure we want to register
@@ -1898,7 +2085,8 @@
  *	%VFL_TYPE_RADIO - A radio card
  */
 
-int video_register_device(struct video_device *vfd, int type, int nr)
+int video_register_device_index(struct video_device *vfd, int type, int nr,
+					int index)
 {
 	int i=0;
 	int base;
@@ -1955,20 +2143,29 @@
 	}
 	video_device[i]=vfd;
 	vfd->minor=i;
+
+	ret = get_index(vfd, index);
+	vfd->index = ret;
+
 	mutex_unlock(&videodev_lock);
+
+	if (ret < 0) {
+		printk(KERN_ERR "%s: get_index failed\n", __func__);
+		goto fail_minor;
+	}
+
 	mutex_init(&vfd->lock);
 
 	/* sysfs class */
 	memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
-	if (vfd->dev)
-		vfd->class_dev.parent = vfd->dev;
 	vfd->class_dev.class       = &video_class;
 	vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
+	if (vfd->dev)
+		vfd->class_dev.parent = vfd->dev;
 	sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
 	ret = device_register(&vfd->class_dev);
 	if (ret < 0) {
-		printk(KERN_ERR "%s: device_register failed\n",
-		       __func__);
+		printk(KERN_ERR "%s: device_register failed\n", __func__);
 		goto fail_minor;
 	}
 
@@ -1988,7 +2185,7 @@
 	mutex_unlock(&videodev_lock);
 	return ret;
 }
-EXPORT_SYMBOL(video_register_device);
+EXPORT_SYMBOL(video_register_device_index);
 
 /**
  *	video_unregister_device - unregister a video4linux device
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 5ff9a58..059b01c 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -39,6 +39,8 @@
 #include <linux/highmem.h>
 #include <linux/freezer.h>
 
+#define VIVI_MODULE_NAME "vivi"
+
 /* Wake up at about 30 fps */
 #define WAKE_NUMERATOR 30
 #define WAKE_DENOMINATOR 1001
@@ -47,7 +49,7 @@
 #include "font.h"
 
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 4
+#define VIVI_MINOR_VERSION 5
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
 	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -630,7 +632,7 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (f->index > 0)
@@ -641,7 +643,7 @@
 	return 0;
 }
 
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct vivi_fh *fh = priv;
@@ -658,7 +660,7 @@
 	return (0);
 }
 
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct vivi_fh  *fh  = priv;
@@ -706,13 +708,13 @@
 }
 
 /*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
 	struct vivi_fh  *fh = priv;
 	struct videobuf_queue *q = &fh->vb_vidq;
 
-	int ret = vidioc_try_fmt_cap(file, fh, f);
+	int ret = vidioc_try_fmt_vid_cap(file, fh, f);
 	if (ret < 0)
 		return (ret);
 
@@ -1017,10 +1019,15 @@
 		list_del(list);
 		dev = list_entry(list, struct vivi_dev, vivi_devlist);
 
-		if (-1 != dev->vfd->minor)
+		if (-1 != dev->vfd->minor) {
 			video_unregister_device(dev->vfd);
-		else
+			printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
+				VIVI_MODULE_NAME, dev->vfd->minor);
+		} else {
 			video_device_release(dev->vfd);
+			printk(KERN_INFO "%s: /dev/video%d released.\n",
+				VIVI_MODULE_NAME, dev->vfd->minor);
+		}
 
 		kfree(dev);
 	}
@@ -1066,10 +1073,10 @@
 	.release	= video_device_release,
 
 	.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_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
 	.vidioc_reqbufs       = vidioc_reqbufs,
 	.vidioc_querybuf      = vidioc_querybuf,
 	.vidioc_qbuf          = vidioc_qbuf,
@@ -1131,6 +1138,8 @@
 			video_nr++;
 
 		dev->vfd = vfd;
+		printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
+			VIVI_MODULE_NAME, vfd->minor);
 	}
 
 	if (ret < 0) {
@@ -1138,7 +1147,9 @@
 		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
 	} else
 		printk(KERN_INFO "Video Technology Magazine Virtual Video "
-				 "Capture Board successfully loaded.\n");
+			"Capture Board ver %u.%u.%u successfully loaded.\n",
+			(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
+			VIVI_VERSION & 0xFF);
 	return ret;
 }
 
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index a1f76ee..cbecb3c 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -166,4 +166,3 @@
 	.remove = vp27smpx_remove,
 	.id_table = vp27smpx_id,
 };
-
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index fc50299..7be47a2 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -327,4 +327,3 @@
 	.remove = wm8739_remove,
 	.id_table = wm8739_id,
 };
-
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 506378a..c2ab70a 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -42,7 +42,6 @@
 
 static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
 
-
 I2C_CLIENT_INSMOD;
 
 
@@ -230,4 +229,3 @@
 	.remove = wm8775_remove,
 	.id_table = wm8775_id,
 };
-
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 006d488..0929edb 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -59,8 +59,6 @@
 #include "zoran_device.h"
 #include "zoran_procfs.h"
 
-#define I2C_NAME(x) (x)->name
-
 extern const struct zoran_format zoran_formats[];
 
 static int card[BUZ_MAX] = { -1, -1, -1, -1 };
@@ -360,14 +358,6 @@
 	case I2C_DRIVERID_VPX3220:
 		name = "vpx3220";
 		break;
-/*	case I2C_DRIVERID_VPX3224:
-		name = "vpx3224";
-		break;
-	case I2C_DRIVERID_MSE3000:
-		name = "mse3000";
-		break;*/
-	default:
-		break;
 	}
 
 	return name;
@@ -388,8 +378,6 @@
 	case CODEC_TYPE_ZR36016:
 		name = "zr36016";
 		break;
-	default:
-		break;
 	}
 
 	return name;
@@ -430,7 +418,6 @@
 		.type = DC10_old,
 		.name = "DC10(old)",
 		.i2c_decoder = I2C_DRIVERID_VPX3220,
-		/*.i2c_encoder = I2C_DRIVERID_MSE3000,*/
 		.video_codec = CODEC_TYPE_ZR36050,
 		.video_vfe = CODEC_TYPE_ZR36016,
 
@@ -809,7 +796,7 @@
 	return res;
 }
 
-static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
 	.setsda = zoran_i2c_setsda,
 	.setscl = zoran_i2c_setscl,
 	.getsda = zoran_i2c_getsda,
@@ -818,24 +805,17 @@
 	.timeout = 100,
 };
 
-static struct i2c_adapter zoran_i2c_adapter_template = {
-	.name = "zr36057",
-	.id = I2C_HW_B_ZR36067,
-	.algo = NULL,
-	.client_register = zoran_i2c_client_register,
-	.client_unregister = zoran_i2c_client_unregister,
-};
-
 static int
 zoran_register_i2c (struct zoran *zr)
 {
 	memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
 	       sizeof(struct i2c_algo_bit_data));
 	zr->i2c_algo.data = zr;
-	memcpy(&zr->i2c_adapter, &zoran_i2c_adapter_template,
-	       sizeof(struct i2c_adapter));
-	strncpy(I2C_NAME(&zr->i2c_adapter), ZR_DEVNAME(zr),
-		sizeof(I2C_NAME(&zr->i2c_adapter)) - 1);
+	zr->i2c_adapter.id = I2C_HW_B_ZR36067;
+	zr->i2c_adapter.client_register = zoran_i2c_client_register;
+	zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
+	strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+		sizeof(zr->i2c_adapter.name));
 	i2c_set_adapdata(&zr->i2c_adapter, zr);
 	zr->i2c_adapter.algo_data = &zr->i2c_algo;
 	zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
@@ -1147,7 +1127,7 @@
 		goto exit_free;
 	}
 	for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
-		zr->stat_com[j] = 1;	/* mark as unavailable to zr36057 */
+		zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
 	}
 
 	/*
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 5394d7a..c067592 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -94,7 +94,6 @@
 				V4L2_CAP_VIDEO_OVERLAY \
 			      )
 
-#include <asm/byteorder.h>
 
 #if defined(CONFIG_VIDEO_V4L1_COMPAT)
 #define ZFMT(pal, fcc, cs) \
@@ -2795,7 +2794,7 @@
 	{
 		struct v4l2_format *fmt = arg;
 		int i, res = 0;
-		__u32 printformat;
+		__le32 printformat;
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
 			ZR_DEVNAME(zr), fmt->type);
@@ -3040,7 +3039,7 @@
 	{
 		int i, res = 0;
 		struct v4l2_framebuffer *fb = arg;
-		__u32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+		__le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
 
 		dprintk(3,
 			KERN_DEBUG
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index a0e49dc..485df2e 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -521,7 +521,7 @@
 	return 0;
 }
 
-static int zr364xx_vidioc_enum_fmt_cap(struct file *file,
+static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
 				       void *priv, struct v4l2_fmtdesc *f)
 {
 	if (f->index > 0)
@@ -537,7 +537,7 @@
 	return 0;
 }
 
-static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 				      struct v4l2_format *f)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -564,7 +564,7 @@
 	return 0;
 }
 
-static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 				    struct v4l2_format *f)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -589,7 +589,7 @@
 	return 0;
 }
 
-static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 				    struct v4l2_format *f)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -770,10 +770,10 @@
 	.minor = -1,
 
 	.vidioc_querycap	= zr364xx_vidioc_querycap,
-	.vidioc_enum_fmt_cap	= zr364xx_vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap	= zr364xx_vidioc_try_fmt_cap,
-	.vidioc_s_fmt_cap	= zr364xx_vidioc_s_fmt_cap,
-	.vidioc_g_fmt_cap	= zr364xx_vidioc_g_fmt_cap,
+	.vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= zr364xx_vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= zr364xx_vidioc_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= zr364xx_vidioc_g_fmt_vid_cap,
 	.vidioc_enum_input	= zr364xx_vidioc_enum_input,
 	.vidioc_g_input		= zr364xx_vidioc_g_input,
 	.vidioc_s_input		= zr364xx_vidioc_s_input,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ae96bd6..260bade 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -17,7 +17,7 @@
 
 config MFD_ASIC3
 	bool "Support for Compaq ASIC3"
-	depends on GENERIC_HARDIRQS && ARM
+	depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM
 	 ---help---
 	  This driver supports the ASIC3 multifunction chip found on many
 	  PDAs (mainly iPAQ and HTC based ones)
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index ef8a492..3b870e7 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -9,7 +9,7 @@
  *
  * Copyright 2001 Compaq Computer Corporation.
  * Copyright 2004-2005 Phil Blundell
- * Copyright 2007 OpenedHand Ltd.
+ * Copyright 2007-2008 OpenedHand Ltd.
  *
  * Authors: Phil Blundell <pb@handhelds.org>,
  *	    Samuel Ortiz <sameo@openedhand.com>
@@ -19,12 +19,26 @@
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 
 #include <linux/mfd/asic3.h>
 
+struct asic3 {
+	void __iomem *mapping;
+	unsigned int bus_shift;
+	unsigned int irq_nr;
+	unsigned int irq_base;
+	spinlock_t lock;
+	u16 irq_bothedge[4];
+	struct gpio_chip gpio;
+	struct device *dev;
+};
+
+static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
+
 static inline void asic3_write_register(struct asic3 *asic,
 				 unsigned int reg, u32 value)
 {
@@ -41,8 +55,8 @@
 
 /* IRQs */
 #define MAX_ASIC_ISR_LOOPS    20
-#define ASIC3_GPIO_Base_INCR \
-	(ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base)
+#define ASIC3_GPIO_BASE_INCR \
+	(ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)
 
 static void asic3_irq_flip_edge(struct asic3 *asic,
 				u32 base, int bit)
@@ -52,10 +66,10 @@
 
 	spin_lock_irqsave(&asic->lock, flags);
 	edge = asic3_read_register(asic,
-				   base + ASIC3_GPIO_EdgeTrigger);
+				   base + ASIC3_GPIO_EDGE_TRIGGER);
 	edge ^= bit;
 	asic3_write_register(asic,
-			     base + ASIC3_GPIO_EdgeTrigger, edge);
+			     base + ASIC3_GPIO_EDGE_TRIGGER, edge);
 	spin_unlock_irqrestore(&asic->lock, flags);
 }
 
@@ -75,7 +89,7 @@
 
 		spin_lock_irqsave(&asic->lock, flags);
 		status = asic3_read_register(asic,
-					     ASIC3_OFFSET(INTR, PIntStat));
+					     ASIC3_OFFSET(INTR, P_INT_STAT));
 		spin_unlock_irqrestore(&asic->lock, flags);
 
 		/* Check all ten register bits */
@@ -87,17 +101,17 @@
 			if (status & (1 << bank)) {
 				unsigned long base, istat;
 
-				base = ASIC3_GPIO_A_Base
-				       + bank * ASIC3_GPIO_Base_INCR;
+				base = ASIC3_GPIO_A_BASE
+				       + bank * ASIC3_GPIO_BASE_INCR;
 
 				spin_lock_irqsave(&asic->lock, flags);
 				istat = asic3_read_register(asic,
 							    base +
-							    ASIC3_GPIO_IntStatus);
+							    ASIC3_GPIO_INT_STATUS);
 				/* Clearing IntStatus */
 				asic3_write_register(asic,
 						     base +
-						     ASIC3_GPIO_IntStatus, 0);
+						     ASIC3_GPIO_INT_STATUS, 0);
 				spin_unlock_irqrestore(&asic->lock, flags);
 
 				for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) {
@@ -123,7 +137,7 @@
 		for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) {
 			/* They start at bit 4 and go up */
 			if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) {
-				desc = irq_desc +  + i;
+				desc = irq_desc + asic->irq_base + i;
 				desc->handle_irq(asic->irq_base + i,
 						 desc);
 			}
@@ -131,8 +145,7 @@
 	}
 
 	if (iter >= MAX_ASIC_ISR_LOOPS)
-		printk(KERN_ERR "%s: interrupt processing overrun\n",
-		       __func__);
+		dev_err(asic->dev, "interrupt processing overrun\n");
 }
 
 static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
@@ -141,7 +154,7 @@
 
 	n = (irq - asic->irq_base) >> 4;
 
-	return (n * (ASIC3_GPIO_B_Base - ASIC3_GPIO_A_Base));
+	return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE));
 }
 
 static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
@@ -159,9 +172,9 @@
 	index = asic3_irq_to_index(asic, irq);
 
 	spin_lock_irqsave(&asic->lock, flags);
-	val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
+	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
 	val |= 1 << index;
-	asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
+	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
 	spin_unlock_irqrestore(&asic->lock, flags);
 }
 
@@ -173,15 +186,15 @@
 
 	spin_lock_irqsave(&asic->lock, flags);
 	regval = asic3_read_register(asic,
-				     ASIC3_INTR_Base +
-				     ASIC3_INTR_IntMask);
+				     ASIC3_INTR_BASE +
+				     ASIC3_INTR_INT_MASK);
 
 	regval &= ~(ASIC3_INTMASK_MASK0 <<
 		    (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
 
 	asic3_write_register(asic,
-			     ASIC3_INTR_Base +
-			     ASIC3_INTR_IntMask,
+			     ASIC3_INTR_BASE +
+			     ASIC3_INTR_INT_MASK,
 			     regval);
 	spin_unlock_irqrestore(&asic->lock, flags);
 }
@@ -196,9 +209,9 @@
 	index = asic3_irq_to_index(asic, irq);
 
 	spin_lock_irqsave(&asic->lock, flags);
-	val = asic3_read_register(asic, bank + ASIC3_GPIO_Mask);
+	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
 	val &= ~(1 << index);
-	asic3_write_register(asic, bank + ASIC3_GPIO_Mask, val);
+	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
 	spin_unlock_irqrestore(&asic->lock, flags);
 }
 
@@ -210,15 +223,15 @@
 
 	spin_lock_irqsave(&asic->lock, flags);
 	regval = asic3_read_register(asic,
-				     ASIC3_INTR_Base +
-				     ASIC3_INTR_IntMask);
+				     ASIC3_INTR_BASE +
+				     ASIC3_INTR_INT_MASK);
 
 	regval |= (ASIC3_INTMASK_MASK0 <<
 		   (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
 
 	asic3_write_register(asic,
-			     ASIC3_INTR_Base +
-			     ASIC3_INTR_IntMask,
+			     ASIC3_INTR_BASE +
+			     ASIC3_INTR_INT_MASK,
 			     regval);
 	spin_unlock_irqrestore(&asic->lock, flags);
 }
@@ -236,11 +249,11 @@
 
 	spin_lock_irqsave(&asic->lock, flags);
 	level = asic3_read_register(asic,
-				    bank + ASIC3_GPIO_LevelTrigger);
+				    bank + ASIC3_GPIO_LEVEL_TRIGGER);
 	edge = asic3_read_register(asic,
-				   bank + ASIC3_GPIO_EdgeTrigger);
+				   bank + ASIC3_GPIO_EDGE_TRIGGER);
 	trigger = asic3_read_register(asic,
-				      bank + ASIC3_GPIO_TriggerType);
+				      bank + ASIC3_GPIO_TRIGGER_TYPE);
 	asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
 
 	if (type == IRQT_RISING) {
@@ -251,7 +264,7 @@
 		edge &= ~bit;
 	} else if (type == IRQT_BOTHEDGE) {
 		trigger |= bit;
-		if (asic3_gpio_get_value(asic, irq - asic->irq_base))
+		if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
 			edge &= ~bit;
 		else
 			edge |= bit;
@@ -268,13 +281,13 @@
 		 * be careful to not unmask them if mask was also called.
 		 * Probably need internal state for mask.
 		 */
-		printk(KERN_NOTICE "asic3: irq type not changed.\n");
+		dev_notice(asic->dev, "irq type not changed\n");
 	}
-	asic3_write_register(asic, bank + ASIC3_GPIO_LevelTrigger,
+	asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER,
 			     level);
-	asic3_write_register(asic, bank + ASIC3_GPIO_EdgeTrigger,
+	asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER,
 			     edge);
-	asic3_write_register(asic, bank + ASIC3_GPIO_TriggerType,
+	asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE,
 			     trigger);
 	spin_unlock_irqrestore(&asic->lock, flags);
 	return 0;
@@ -295,11 +308,12 @@
 	.unmask		= asic3_unmask_irq,
 };
 
-static int asic3_irq_probe(struct platform_device *pdev)
+static int __init asic3_irq_probe(struct platform_device *pdev)
 {
 	struct asic3 *asic = platform_get_drvdata(pdev);
 	unsigned long clksel = 0;
 	unsigned int irq, irq_base;
+	int map_size;
 
 	asic->irq_nr = platform_get_irq(pdev, 0);
 	if (asic->irq_nr < 0)
@@ -323,7 +337,7 @@
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	asic3_write_register(asic, ASIC3_OFFSET(INTR, IntMask),
+	asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK),
 			     ASIC3_INTMASK_GINTMASK);
 
 	set_irq_chained_handler(asic->irq_nr, asic3_irq_demux);
@@ -350,149 +364,182 @@
 }
 
 /* GPIOs */
-static inline u32 asic3_get_gpio(struct asic3 *asic, unsigned int base,
-				 unsigned int function)
+static int asic3_gpio_direction(struct gpio_chip *chip,
+				unsigned offset, int out)
 {
-	return asic3_read_register(asic, base + function);
-}
-
-static void asic3_set_gpio(struct asic3 *asic, unsigned int base,
-			   unsigned int function, u32 bits, u32 val)
-{
+	u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg;
+	unsigned int gpio_base;
 	unsigned long flags;
+	struct asic3 *asic;
 
-	spin_lock_irqsave(&asic->lock, flags);
-	val |= (asic3_read_register(asic, base + function) & ~bits);
+	asic = container_of(chip, struct asic3, gpio);
+	gpio_base = ASIC3_GPIO_TO_BASE(offset);
 
-	asic3_write_register(asic, base + function, val);
-	spin_unlock_irqrestore(&asic->lock, flags);
-}
-
-#define asic3_get_gpio_a(asic, fn) \
-	asic3_get_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn)
-#define asic3_get_gpio_b(asic, fn) \
-	asic3_get_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn)
-#define asic3_get_gpio_c(asic, fn) \
-	asic3_get_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn)
-#define asic3_get_gpio_d(asic, fn) \
-	asic3_get_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn)
-
-#define asic3_set_gpio_a(asic, fn, bits, val) \
-	asic3_set_gpio(asic, ASIC3_GPIO_A_Base, ASIC3_GPIO_##fn, bits, val)
-#define asic3_set_gpio_b(asic, fn, bits, val) \
-	asic3_set_gpio(asic, ASIC3_GPIO_B_Base, ASIC3_GPIO_##fn, bits, val)
-#define asic3_set_gpio_c(asic, fn, bits, val) \
-	asic3_set_gpio(asic, ASIC3_GPIO_C_Base, ASIC3_GPIO_##fn, bits, val)
-#define asic3_set_gpio_d(asic, fn, bits, val) \
-	asic3_set_gpio(asic, ASIC3_GPIO_D_Base, ASIC3_GPIO_##fn, bits, val)
-
-#define asic3_set_gpio_banks(asic, fn, bits, pdata, field) 		  \
-	do {								  \
-	     asic3_set_gpio_a((asic), fn, (bits), (pdata)->gpio_a.field); \
-	     asic3_set_gpio_b((asic), fn, (bits), (pdata)->gpio_b.field); \
-	     asic3_set_gpio_c((asic), fn, (bits), (pdata)->gpio_c.field); \
-	     asic3_set_gpio_d((asic), fn, (bits), (pdata)->gpio_d.field); \
-	} while (0)
-
-int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
-{
-	u32 mask = ASIC3_GPIO_bit(gpio);
-
-	switch (gpio >> 4) {
-	case ASIC3_GPIO_BANK_A:
-		return asic3_get_gpio_a(asic, Status) & mask;
-	case ASIC3_GPIO_BANK_B:
-		return asic3_get_gpio_b(asic, Status) & mask;
-	case ASIC3_GPIO_BANK_C:
-		return asic3_get_gpio_c(asic, Status) & mask;
-	case ASIC3_GPIO_BANK_D:
-		return asic3_get_gpio_d(asic, Status) & mask;
-	default:
-		printk(KERN_ERR "%s: invalid GPIO value 0x%x",
-		       __func__, gpio);
+	if (gpio_base > ASIC3_GPIO_D_BASE) {
+		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
+			gpio_base, offset);
 		return -EINVAL;
 	}
-}
-EXPORT_SYMBOL(asic3_gpio_get_value);
 
-void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
-{
-	u32 mask = ASIC3_GPIO_bit(gpio);
-	u32 bitval = 0;
-	if (val)
-		bitval = mask;
+	spin_lock_irqsave(&asic->lock, flags);
 
-	switch (gpio >> 4) {
-	case ASIC3_GPIO_BANK_A:
-		asic3_set_gpio_a(asic, Out, mask, bitval);
-		return;
-	case ASIC3_GPIO_BANK_B:
-		asic3_set_gpio_b(asic, Out, mask, bitval);
-		return;
-	case ASIC3_GPIO_BANK_C:
-		asic3_set_gpio_c(asic, Out, mask, bitval);
-		return;
-	case ASIC3_GPIO_BANK_D:
-		asic3_set_gpio_d(asic, Out, mask, bitval);
-		return;
-	default:
-		printk(KERN_ERR "%s: invalid GPIO value 0x%x",
-		       __func__, gpio);
-		return;
-	}
-}
-EXPORT_SYMBOL(asic3_gpio_set_value);
+	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION);
 
-static int asic3_gpio_probe(struct platform_device *pdev)
-{
-	struct asic3_platform_data *pdata = pdev->dev.platform_data;
-	struct asic3 *asic = platform_get_drvdata(pdev);
+	/* Input is 0, Output is 1 */
+	if (out)
+		out_reg |= mask;
+	else
+		out_reg &= ~mask;
 
-	asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, Mask), 0xffff);
-	asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, Mask), 0xffff);
-	asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, Mask), 0xffff);
-	asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, Mask), 0xffff);
+	asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg);
 
-	asic3_set_gpio_a(asic, SleepMask, 0xffff, 0xffff);
-	asic3_set_gpio_b(asic, SleepMask, 0xffff, 0xffff);
-	asic3_set_gpio_c(asic, SleepMask, 0xffff, 0xffff);
-	asic3_set_gpio_d(asic, SleepMask, 0xffff, 0xffff);
-
-	if (pdata) {
-		asic3_set_gpio_banks(asic, Out, 0xffff, pdata, init);
-		asic3_set_gpio_banks(asic, Direction, 0xffff, pdata, dir);
-		asic3_set_gpio_banks(asic, SleepMask, 0xffff, pdata,
-				     sleep_mask);
-		asic3_set_gpio_banks(asic, SleepOut, 0xffff, pdata, sleep_out);
-		asic3_set_gpio_banks(asic, BattFaultOut, 0xffff, pdata,
-				     batt_fault_out);
-		asic3_set_gpio_banks(asic, SleepConf, 0xffff, pdata,
-				     sleep_conf);
-		asic3_set_gpio_banks(asic, AltFunction, 0xffff, pdata,
-				     alt_function);
-	}
+	spin_unlock_irqrestore(&asic->lock, flags);
 
 	return 0;
+
 }
 
-static void asic3_gpio_remove(struct platform_device *pdev)
+static int asic3_gpio_direction_input(struct gpio_chip *chip,
+				      unsigned offset)
 {
+	return asic3_gpio_direction(chip, offset, 0);
+}
+
+static int asic3_gpio_direction_output(struct gpio_chip *chip,
+				       unsigned offset, int value)
+{
+	return asic3_gpio_direction(chip, offset, 1);
+}
+
+static int asic3_gpio_get(struct gpio_chip *chip,
+			  unsigned offset)
+{
+	unsigned int gpio_base;
+	u32 mask = ASIC3_GPIO_TO_MASK(offset);
+	struct asic3 *asic;
+
+	asic = container_of(chip, struct asic3, gpio);
+	gpio_base = ASIC3_GPIO_TO_BASE(offset);
+
+	if (gpio_base > ASIC3_GPIO_D_BASE) {
+		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
+			gpio_base, offset);
+		return -EINVAL;
+	}
+
+	return asic3_read_register(asic, gpio_base + ASIC3_GPIO_STATUS) & mask;
+}
+
+static void asic3_gpio_set(struct gpio_chip *chip,
+			   unsigned offset, int value)
+{
+	u32 mask, out_reg;
+	unsigned int gpio_base;
+	unsigned long flags;
+	struct asic3 *asic;
+
+	asic = container_of(chip, struct asic3, gpio);
+	gpio_base = ASIC3_GPIO_TO_BASE(offset);
+
+	if (gpio_base > ASIC3_GPIO_D_BASE) {
+		dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n",
+			gpio_base, offset);
+		return;
+	}
+
+	mask = ASIC3_GPIO_TO_MASK(offset);
+
+	spin_lock_irqsave(&asic->lock, flags);
+
+	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT);
+
+	if (value)
+		out_reg |= mask;
+	else
+		out_reg &= ~mask;
+
+	asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg);
+
+	spin_unlock_irqrestore(&asic->lock, flags);
+
 	return;
 }
 
+static __init int asic3_gpio_probe(struct platform_device *pdev,
+				   u16 *gpio_config, int num)
+{
+	struct asic3 *asic = platform_get_drvdata(pdev);
+	u16 alt_reg[ASIC3_NUM_GPIO_BANKS];
+	u16 out_reg[ASIC3_NUM_GPIO_BANKS];
+	u16 dir_reg[ASIC3_NUM_GPIO_BANKS];
+	int i;
+
+	memzero(alt_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+	memzero(out_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+	memzero(dir_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+
+	/* Enable all GPIOs */
+	asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff);
+	asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff);
+	asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff);
+	asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff);
+
+	for (i = 0; i < num; i++) {
+		u8 alt, pin, dir, init, bank_num, bit_num;
+		u16 config = gpio_config[i];
+
+		pin = ASIC3_CONFIG_GPIO_PIN(config);
+		alt = ASIC3_CONFIG_GPIO_ALT(config);
+		dir = ASIC3_CONFIG_GPIO_DIR(config);
+		init = ASIC3_CONFIG_GPIO_INIT(config);
+
+		bank_num = ASIC3_GPIO_TO_BANK(pin);
+		bit_num = ASIC3_GPIO_TO_BIT(pin);
+
+		alt_reg[bank_num] |= (alt << bit_num);
+		out_reg[bank_num] |= (init << bit_num);
+		dir_reg[bank_num] |= (dir << bit_num);
+	}
+
+	for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) {
+		asic3_write_register(asic,
+				     ASIC3_BANK_TO_BASE(i) +
+				     ASIC3_GPIO_DIRECTION,
+				     dir_reg[i]);
+		asic3_write_register(asic,
+				     ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT,
+				     out_reg[i]);
+		asic3_write_register(asic,
+				     ASIC3_BANK_TO_BASE(i) +
+				     ASIC3_GPIO_ALT_FUNCTION,
+				     alt_reg[i]);
+	}
+
+	return gpiochip_add(&asic->gpio);
+}
+
+static int asic3_gpio_remove(struct platform_device *pdev)
+{
+	struct asic3 *asic = platform_get_drvdata(pdev);
+
+	return gpiochip_remove(&asic->gpio);
+}
+
 
 /* Core */
-static int asic3_probe(struct platform_device *pdev)
+static int __init asic3_probe(struct platform_device *pdev)
 {
 	struct asic3_platform_data *pdata = pdev->dev.platform_data;
 	struct asic3 *asic;
 	struct resource *mem;
 	unsigned long clksel;
-	int ret;
+	int ret = 0;
 
 	asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
-	if (!asic)
+	if (asic == NULL) {
+		printk(KERN_ERR "kzalloc failed\n");
 		return -ENOMEM;
+	}
 
 	spin_lock_init(&asic->lock);
 	platform_set_drvdata(pdev, asic);
@@ -501,49 +548,58 @@
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem) {
 		ret = -ENOMEM;
-		printk(KERN_ERR "asic3: no MEM resource\n");
-		goto err_out_1;
+		dev_err(asic->dev, "no MEM resource\n");
+		goto out_free;
 	}
 
-	asic->mapping = ioremap(mem->start, PAGE_SIZE);
+	map_size = mem->end - mem->start + 1;
+	asic->mapping = ioremap(mem->start, map_size);
 	if (!asic->mapping) {
 		ret = -ENOMEM;
-		printk(KERN_ERR "asic3: couldn't ioremap\n");
-		goto err_out_1;
+		dev_err(asic->dev, "Couldn't ioremap\n");
+		goto out_free;
 	}
 
 	asic->irq_base = pdata->irq_base;
 
-	if (pdata && pdata->bus_shift)
-		asic->bus_shift = 2 - pdata->bus_shift;
-	else
-		asic->bus_shift = 0;
+	/* calculate bus shift from mem resource */
+	asic->bus_shift = 2 - (map_size >> 12);
 
 	clksel = 0;
 	asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel);
 
 	ret = asic3_irq_probe(pdev);
 	if (ret < 0) {
-		printk(KERN_ERR "asic3: couldn't probe IRQs\n");
-		goto err_out_2;
-	}
-	asic3_gpio_probe(pdev);
-
-	if (pdata->children) {
-		int i;
-		for (i = 0; i < pdata->n_children; i++) {
-			pdata->children[i]->dev.parent = &pdev->dev;
-			platform_device_register(pdata->children[i]);
-		}
+		dev_err(asic->dev, "Couldn't probe IRQs\n");
+		goto out_unmap;
 	}
 
-	printk(KERN_INFO "ASIC3 Core driver\n");
+	asic->gpio.base = pdata->gpio_base;
+	asic->gpio.ngpio = ASIC3_NUM_GPIOS;
+	asic->gpio.get = asic3_gpio_get;
+	asic->gpio.set = asic3_gpio_set;
+	asic->gpio.direction_input = asic3_gpio_direction_input;
+	asic->gpio.direction_output = asic3_gpio_direction_output;
+
+	ret = asic3_gpio_probe(pdev,
+			       pdata->gpio_config,
+			       pdata->gpio_config_num);
+	if (ret < 0) {
+		dev_err(asic->dev, "GPIO probe failed\n");
+		goto out_irq;
+	}
+
+	dev_info(asic->dev, "ASIC3 Core driver\n");
 
 	return 0;
 
- err_out_2:
+ out_irq:
+	asic3_irq_remove(pdev);
+
+ out_unmap:
 	iounmap(asic->mapping);
- err_out_1:
+
+ out_free:
 	kfree(asic);
 
 	return ret;
@@ -551,9 +607,12 @@
 
 static int asic3_remove(struct platform_device *pdev)
 {
+	int ret;
 	struct asic3 *asic = platform_get_drvdata(pdev);
 
-	asic3_gpio_remove(pdev);
+	ret = asic3_gpio_remove(pdev);
+	if (ret < 0)
+		return ret;
 	asic3_irq_remove(pdev);
 
 	asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0);
@@ -573,7 +632,6 @@
 	.driver		= {
 		.name	= "asic3",
 	},
-	.probe		= asic3_probe,
 	.remove		= __devexit_p(asic3_remove),
 	.shutdown	= asic3_shutdown,
 };
@@ -581,7 +639,7 @@
 static int __init asic3_init(void)
 {
 	int retval = 0;
-	retval = platform_driver_register(&asic3_device_driver);
+	retval = platform_driver_probe(&asic3_device_driver, asic3_probe);
 	return retval;
 }
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 611e9fb..3e5e64c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -325,15 +325,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called apne.
 
-config APOLLO_ELPLUS
-	tristate "Apollo 3c505 support"
-	depends on APOLLO
-	help
-	  Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
-	  If you don't have one made for Apollos, you can use one from a PC,
-	  except that your Apollo won't be able to boot from it (because the
-	  code in the ROM will be for a PC).
-
 config MAC8390
 	bool "Macintosh NS 8390 based ethernet cards"
 	depends on MAC
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 10f3a19..29e53eb 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -98,7 +98,6 @@
     volatile u_short *rx_buff[RX_RING_SIZE];
     int cur_tx, cur_rx;			/* The next free ring entry */
     int dirty_tx;			/* The ring entries to be free()ed. */
-    struct net_device_stats stats;
     char tx_full;
 };
 
@@ -378,20 +377,19 @@
 
 static int ariadne_close(struct net_device *dev)
 {
-    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
 
     netif_stop_queue(dev);
 
     lance->RAP = CSR112;	/* Missed Frame Count */
-    priv->stats.rx_missed_errors = swapw(lance->RDP);
+    dev->stats.rx_missed_errors = swapw(lance->RDP);
     lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
 
     if (ariadne_debug > 1) {
 	printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 	       dev->name, lance->RDP);
 	printk(KERN_DEBUG "%s: %lu packets missed\n", dev->name,
-	       priv->stats.rx_missed_errors);
+	       dev->stats.rx_missed_errors);
     }
 
     /* We stop the LANCE here -- it occasionally polls memory if we don't. */
@@ -502,16 +500,16 @@
 		if (status & TF_ERR) {
 		    /* There was an major error, log it. */
 		    int err_status = priv->tx_ring[entry]->TMD3;
-		    priv->stats.tx_errors++;
+		    dev->stats.tx_errors++;
 		    if (err_status & EF_RTRY)
-			priv->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 		    if (err_status & EF_LCAR)
-			priv->stats.tx_carrier_errors++;
+			dev->stats.tx_carrier_errors++;
 		    if (err_status & EF_LCOL)
-			priv->stats.tx_window_errors++;
+			dev->stats.tx_window_errors++;
 		    if (err_status & EF_UFLO) {
 			/* Ackk!  On FIFO errors the Tx unit is turned off! */
-			priv->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 			/* Remove this verbosity later! */
 			printk(KERN_ERR "%s: Tx FIFO error! Status %4.4x.\n",
 			       dev->name, csr0);
@@ -520,8 +518,8 @@
 		    }
 		} else {
 		    if (status & (TF_MORE|TF_ONE))
-			priv->stats.collisions++;
-		    priv->stats.tx_packets++;
+			dev->stats.collisions++;
+		    dev->stats.tx_packets++;
 		}
 		dirty_tx++;
 	    }
@@ -547,11 +545,11 @@
 	/* Log misc errors. */
 	if (csr0 & BABL) {
 	    handled = 1;
-	    priv->stats.tx_errors++;	/* Tx babble. */
+	    dev->stats.tx_errors++;	/* Tx babble. */
 	}
 	if (csr0 & MISS) {
 	    handled = 1;
-	    priv->stats.rx_errors++;	/* Missed a Rx frame. */
+	    dev->stats.rx_errors++;	/* Missed a Rx frame. */
 	}
 	if (csr0 & MERR) {
 	    handled = 1;
@@ -672,7 +670,7 @@
 	priv->cur_tx -= TX_RING_SIZE;
 	priv->dirty_tx -= TX_RING_SIZE;
     }
-    priv->stats.tx_bytes += len;
+    dev->stats.tx_bytes += len;
 
     /* Trigger an immediate send poll. */
     lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
@@ -707,15 +705,15 @@
 		buffers, with only the last correctly noting the error. */
 	    if (status & RF_ENP)
 		/* Only count a general error at the end of a packet.*/
-		priv->stats.rx_errors++;
+		dev->stats.rx_errors++;
 	    if (status & RF_FRAM)
-		priv->stats.rx_frame_errors++;
+		dev->stats.rx_frame_errors++;
 	    if (status & RF_OFLO)
-		priv->stats.rx_over_errors++;
+		dev->stats.rx_over_errors++;
 	    if (status & RF_CRC)
-		priv->stats.rx_crc_errors++;
+		dev->stats.rx_crc_errors++;
 	    if (status & RF_BUFF)
-		priv->stats.rx_fifo_errors++;
+		dev->stats.rx_fifo_errors++;
 	    priv->rx_ring[entry]->RMD1 &= 0xff00|RF_STP|RF_ENP;
 	} else {
 	    /* Malloc up new buffer, compatible with net-3. */
@@ -731,7 +729,7 @@
 			break;
 
 		if (i > RX_RING_SIZE-2) {
-		    priv->stats.rx_dropped++;
+		    dev->stats.rx_dropped++;
 		    priv->rx_ring[entry]->RMD1 |= RF_OWN;
 		    priv->cur_rx++;
 		}
@@ -764,8 +762,8 @@
 
 	    netif_rx(skb);
 	    dev->last_rx = jiffies;
-	    priv->stats.rx_packets++;
-	    priv->stats.rx_bytes += pkt_len;
+	    dev->stats.rx_packets++;
+	    dev->stats.rx_bytes += pkt_len;
 	}
 
 	priv->rx_ring[entry]->RMD1 |= RF_OWN;
@@ -783,7 +781,6 @@
 
 static struct net_device_stats *ariadne_get_stats(struct net_device *dev)
 {
-    struct ariadne_private *priv = netdev_priv(dev);
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
     short saved_addr;
     unsigned long flags;
@@ -791,11 +788,11 @@
     local_irq_save(flags);
     saved_addr = lance->RAP;
     lance->RAP = CSR112;		/* Missed Frame Count */
-    priv->stats.rx_missed_errors = swapw(lance->RDP);
+    dev->stats.rx_missed_errors = swapw(lance->RDP);
     lance->RAP = saved_addr;
     local_irq_restore(flags);
 
-    return &priv->stats;
+    return &dev->stats;
 }
 
 
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index ffc937f..0f501d2 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -775,7 +775,7 @@
 	return err;
 }
 
-static struct tty_ldisc sp_ldisc = {
+static struct tty_ldisc_ops sp_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
 	.name		= "6pack",
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index b8740e6..3249df5 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -971,7 +971,7 @@
 	mkiss_put(ax);
 }
 
-static struct tty_ldisc ax_ldisc = {
+static struct tty_ldisc_ops ax_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
 	.name		= "mkiss",
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index e6f40b7..9e33196 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -533,7 +533,7 @@
 
 /* ------------------------------------------------------- */
 
-static struct tty_ldisc irda_ldisc = {
+static struct tty_ldisc_ops irda_ldisc = {
 	.magic		= TTY_LDISC_MAGIC,
  	.name		= "irda",
 	.flags		= 0,
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 387a133..e13966b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -585,9 +585,8 @@
  * Group operations and type for netconsole_subsys.
  */
 
-static int make_netconsole_target(struct config_group *group,
-				  const char *name,
-				  struct config_item **new_item)
+static struct config_item *make_netconsole_target(struct config_group *group,
+						  const char *name)
 {
 	unsigned long flags;
 	struct netconsole_target *nt;
@@ -599,7 +598,7 @@
 	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 	if (!nt) {
 		printk(KERN_ERR "netconsole: failed to allocate memory\n");
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	nt->np.name = "netconsole";
@@ -616,8 +615,7 @@
 	list_add(&nt->list, &target_list);
 	spin_unlock_irqrestore(&target_list_lock, flags);
 
-	*new_item = &nt->item;
-	return 0;
+	return &nt->item;
 }
 
 static void drop_netconsole_target(struct config_group *group,
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index f1a52de..451bdb5 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -378,7 +378,7 @@
 }
 
 
-static struct tty_ldisc ppp_ldisc = {
+static struct tty_ldisc_ops ppp_ldisc = {
 	.owner  = THIS_MODULE,
 	.magic	= TTY_LDISC_MAGIC,
 	.name	= "ppp",
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index b8f0369..801d8f9 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -418,7 +418,7 @@
 }
 
 
-static struct tty_ldisc ppp_sync_ldisc = {
+static struct tty_ldisc_ops ppp_sync_ldisc = {
 	.owner	= THIS_MODULE,
 	.magic	= TTY_LDISC_MAGIC,
 	.name	= "pppsync",
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 84af68f..1d58991 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -1301,7 +1301,7 @@
 #endif
 /* VSV changes end */
 
-static struct tty_ldisc	sl_ldisc = {
+static struct tty_ldisc_ops sl_ldisc = {
 	.owner 		= THIS_MODULE,
 	.magic 		= TTY_LDISC_MAGIC,
 	.name 		= "slip",
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index eae94ab..4518d0a 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -688,9 +688,9 @@
 				if (cpc_tty->tty) {
 					ld = tty_ldisc_ref(cpc_tty->tty);
 					if (ld) {
-						if (ld->receive_buf) {
+						if (ld->ops->receive_buf) {
 							CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
-							ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
+							ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
 						}
 						tty_ldisc_deref(ld);
 					}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 069f8bb..2a6c7a6 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -754,7 +754,7 @@
 	dev->flags		= IFF_NOARP;
 }
 
-static struct tty_ldisc x25_ldisc = {
+static struct tty_ldisc_ops x25_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
 	.name		= "X.25",
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 883af89..417e9e6 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -2728,7 +2728,7 @@
 /************************************************************************/
 /* Initialization							*/
 
-static struct tty_ldisc strip_ldisc = {
+static struct tty_ldisc_ops strip_ldisc = {
 	.magic = TTY_LDISC_MAGIC,
 	.name = "strip",
 	.owner = THIS_MODULE,
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 0276471..6558a40 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -4,8 +4,6 @@
  * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
  *
  * Based on drivers/char/serial.c
- *
- *  $Id: 21285.c,v 1.37 2002/07/28 10:03:27 rmk Exp $
  */
 #include <linux/module.h>
 #include <linux/tty.h>
@@ -88,7 +86,7 @@
 static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	unsigned int status, ch, flag, rxs, max_count = 256;
 
 	status = *CSR_UARTFLG;
@@ -237,8 +235,8 @@
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
 	quot = uart_get_divisor(port, baud);
 
-	if (port->info && port->info->tty) {
-		struct tty_struct *tty = port->info->tty;
+	if (port->info && port->info->port.tty) {
+		struct tty_struct *tty = port->info->port.tty;
 		unsigned int b = port->uartclk / (16 * quot);
 		tty_encode_baud_rate(tty, b, b);
 	}
@@ -494,7 +492,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "Serial: 21285 driver $Revision: 1.37 $\n");
+	printk(KERN_INFO "Serial: 21285 driver\n");
 
 	serial21285_setup_ports();
 
@@ -515,5 +513,5 @@
 module_exit(serial21285_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $");
+MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
 MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index bbf5bc5..381b12a 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -249,7 +249,7 @@
 {
 #if 0
 	if(status & DCD) {
-		if((info->tty->termios->c_cflag & CRTSCTS) &&
+		if((info->port.tty->termios->c_cflag & CRTSCTS) &&
 		   ((info->curregs[3] & AUTO_ENAB)==0)) {
 			info->curregs[3] |= AUTO_ENAB;
 			info->pendregs[3] |= AUTO_ENAB;
@@ -274,7 +274,7 @@
 
 static void receive_chars(struct m68k_serial *info, unsigned short rx)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned char ch, flag;
 
@@ -345,7 +345,7 @@
 		goto clear_and_return;
 	}
 
-	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+	if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
 		/* That's peculiar... TX ints off */
 		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
 		goto clear_and_return;
@@ -403,7 +403,7 @@
 	struct m68k_serial	*info = container_of(work, struct m68k_serial, tqueue);
 	struct tty_struct	*tty;
 	
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty)
 		return;
 #if 0
@@ -427,7 +427,7 @@
 	struct m68k_serial	*info = container_of(work, struct m68k_serial, tqueue_hangup);
 	struct tty_struct	*tty;
 	
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty)
 		return;
 
@@ -471,8 +471,8 @@
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 #endif
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
@@ -506,8 +506,8 @@
 		info->xmit_buf = 0;
 	}
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	
 	info->flags &= ~S_INITIALIZED;
 	local_irq_restore(flags);
@@ -573,9 +573,9 @@
 	unsigned cflag;
 	int	i;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 	if (!(port = info->port))
 		return;
 
@@ -1131,7 +1131,7 @@
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
-	info->tty = 0;
+	info->port.tty = NULL;
 #warning "This is not and has never been valid so fix it"	
 #if 0
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1169,7 +1169,7 @@
 	info->event = 0;
 	info->count = 0;
 	info->flags &= ~S_NORMAL_ACTIVE;
-	info->tty = 0;
+	info->port.tty = NULL;
 	wake_up_interruptible(&info->open_wait);
 }
 
@@ -1286,7 +1286,7 @@
 
 	info->count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
 	/*
 	 * Start up serial port
@@ -1363,7 +1363,7 @@
 	    info = &m68k_soft[i];
 	    info->magic = SERIAL_MAGIC;
 	    info->port = (int) &uart_addr[i];
-	    info->tty = 0;
+	    info->port.tty = NULL;
 	    info->irq = uart_irqs[i];
 	    info->custom_divisor = 16;
 	    info->close_delay = 50;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index d9d4e95..24661cd 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -393,7 +393,7 @@
 
 static _INLINE_ void receive_chars(ser_info_t *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	unsigned char ch, flag, *cp;
 	/*int	ignored = 0;*/
 	int	i;
@@ -514,7 +514,7 @@
 
 static _INLINE_ void receive_break(ser_info_t *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	info->state->icount.brk++;
 	/* Check to see if there is room in the tty buffer for
@@ -528,7 +528,7 @@
 {
 
 	if ((info->flags & TX_WAKEUP) ||
-	    (info->tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+	    (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
 		schedule_work(&info->tqueue);
 	}
 
@@ -584,12 +584,12 @@
 		}
 	}
 	if (info->flags & ASYNC_CTS_FLOW) {
-		if (info->tty->hw_stopped) {
+		if (info->port.tty->hw_stopped) {
 			if (status & UART_MSR_CTS) {
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
 				printk("CTS tx start...");
 #endif
-				info->tty->hw_stopped = 0;
+				info->port.tty->hw_stopped = 0;
 				info->IER |= UART_IER_THRI;
 				serial_out(info, UART_IER, info->IER);
 				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
@@ -600,7 +600,7 @@
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
 				printk("CTS tx stop...");
 #endif
-				info->tty->hw_stopped = 1;
+				info->port.tty->hw_stopped = 1;
 				info->IER &= ~UART_IER_THRI;
 				serial_out(info, UART_IER, info->IER);
 			}
@@ -670,7 +670,7 @@
 	ser_info_t	*info = (ser_info_t *) private_;
 	struct tty_struct	*tty;
 	
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty)
 		return;
 
@@ -693,7 +693,7 @@
 	struct async_struct	*info = (struct async_struct *) private_;
 	struct tty_struct	*tty;
 	
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty)
 		return;
 
@@ -721,8 +721,8 @@
 
 #ifdef maybe
 	if (!state->port || !state->type) {
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		if (info->port.tty)
+			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		goto errout;
 	}
 #endif
@@ -734,12 +734,12 @@
 
 #ifdef modem_control
 	info->MCR = 0;
-	if (info->tty->termios->c_cflag & CBAUD)
+	if (info->port.tty->termios->c_cflag & CBAUD)
 		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
 #endif
 	
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	/*
 	 * and set the speed of the serial port
@@ -842,8 +842,8 @@
 			smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
 	}
 	
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	info->flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
@@ -863,9 +863,9 @@
 	volatile struct smc_regs	*smcp;
 	volatile struct scc_regs	*sccp;
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 
 	state = info->state;
 
@@ -936,24 +936,24 @@
 	 * Set up parity check flag
 	 */
 	info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
-	if (I_INPCK(info->tty))
+	if (I_INPCK(info->port.tty))
 		info->read_status_mask |= BD_SC_FR | BD_SC_PR;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
 		info->read_status_mask |= BD_SC_BR;
 	
 	/*
 	 * Characters to ignore
 	 */
 	info->ignore_status_mask = 0;
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		info->ignore_status_mask |= BD_SC_BR;
 		/*
 		 * If we're ignore parity and break indicators, ignore 
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			info->ignore_status_mask |= BD_SC_OV;
 	}
 	/*
@@ -1658,7 +1658,7 @@
 	tty_ldisc_flush(tty);		
 	tty->closing = 0;
 	info->event = 0;
-	info->tty = 0;
+	info->port.tty = NULL;
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			msleep_interruptible(jiffies_to_msecs(info->close_delay));
@@ -1758,7 +1758,7 @@
 	info->event = 0;
 	state->count = 0;
 	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = 0;
+	info->port.tty = NULL;
 	wake_up_interruptible(&info->open_wait);
 }
 
@@ -1919,7 +1919,7 @@
 	printk("rs_open %s, count = %d\n", tty->name, info->state->count);
 #endif
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
 	/*
 	 * Start up serial port
@@ -1976,7 +1976,7 @@
 		info->port = state->port;
 		info->flags = state->flags;
 		info->quot = 0;
-		info->tty = 0;
+		info->port.tty = NULL;
 	}
 	local_irq_disable();
 	status = serial_in(info, UART_MSR);
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index be95e55..ce948b6 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -12,8 +12,6 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- *  $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $
- *
  * A note about mapbase / membase
  *
  *  mapbase is the physical address of the IO port.
@@ -1289,7 +1287,7 @@
 static void
 receive_chars(struct uart_8250_port *up, unsigned int *status)
 {
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned char ch, lsr = *status;
 	int max_count = 256;
 	char flag;
@@ -2934,7 +2932,7 @@
 	if (nr_uarts > UART_NR)
 		nr_uarts = UART_NR;
 
-	printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
+	printk(KERN_INFO "Serial: 8250/16550 driver"
 		"%d ports, IRQ sharing %sabled\n", nr_uarts,
 		share_irqs ? "en" : "dis");
 
@@ -2995,7 +2993,7 @@
 EXPORT_SYMBOL(serial8250_resume_port);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
 
 module_param(share_irqs, uint, 0644);
 MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 91bd28f..78c0016 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -11,8 +11,6 @@
  * 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.
- *
- *  $Id: 8250.h,v 1.8 2002/07/21 21:32:30 rmk Exp $
  */
 
 #include <linux/serial_8250.h>
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 788c3559..1b36087 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -10,8 +10,6 @@
  * 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.
- *
- *  $Id: 8250_pci.c,v 1.28 2002/11/02 11:14:18 rmk Exp $
  */
 #include <linux/module.h>
 #include <linux/init.h>
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 638b686..fde7f9c 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -12,8 +12,6 @@
  * 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.
- *
- *  $Id: 8250_pnp.c,v 1.10 2002/07/21 21:32:30 rmk Exp $
  */
 #include <linux/module.h>
 #include <linux/init.h>
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 18ca907..8fc7451 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1,8 +1,6 @@
 #
 # Serial device configuration
 #
-# $Id: Kconfig,v 1.11 2004/03/11 18:08:04 lethal Exp $
-#
 
 menu "Serial drivers"
 	depends on HAS_IOMEM
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7d85c1f..3a0bbbe 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -1,8 +1,6 @@
 #
 # Makefile for the kernel serial device drivers.
 #
-#  $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
-#
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index e88da72..90b56c2 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -22,8 +22,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- *  $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
- *
  * This is a generic driver for ARM AMBA-type serial ports.  They
  * have a lot of 16550-like features, but are not register compatible.
  * Note that although they do have CTS, DCD and DSR inputs, they do
@@ -119,7 +117,7 @@
 
 static void pl010_rx_chars(struct uart_amba_port *uap)
 {
-	struct tty_struct *tty = uap->port.info->tty;
+	struct tty_struct *tty = uap->port.info->port.tty;
 	unsigned int status, ch, flag, rsr, max_count = 256;
 
 	status = readb(uap->port.membase + UART01x_FR);
@@ -791,7 +789,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "Serial: AMBA driver $Revision: 1.41 $\n");
+	printk(KERN_INFO "Serial: AMBA driver\n");
 
 	ret = uart_register_driver(&amba_reg);
 	if (ret == 0) {
@@ -812,5 +810,5 @@
 module_exit(pl010_exit);
 
 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $");
+MODULE_DESCRIPTION("ARM AMBA serial port driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 08adc1d..9d08f27 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -22,8 +22,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- *  $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
- *
  * This is a generic driver for ARM AMBA-type serial ports.  They
  * have a lot of 16550-like features, but are not register compatible.
  * Note that although they do have CTS, DCD and DSR inputs, they do
@@ -109,7 +107,7 @@
 
 static void pl011_rx_chars(struct uart_amba_port *uap)
 {
-	struct tty_struct *tty = uap->port.info->tty;
+	struct tty_struct *tty = uap->port.info->port.tty;
 	unsigned int status, ch, flag, max_count = 256;
 
 	status = readw(uap->port.membase + UART01x_FR);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 6aeef22b..1fee12c 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -662,14 +662,14 @@
 	 * uart_start(), which takes the lock.
 	 */
 	spin_unlock(&port->lock);
-	tty_flip_buffer_push(port->info->tty);
+	tty_flip_buffer_push(port->info->port.tty);
 	spin_lock(&port->lock);
 }
 
 static void atmel_rx_from_dma(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	struct atmel_dma_buffer *pdc;
 	int rx_idx = atmel_port->pdc_rx_idx;
 	unsigned int head;
@@ -794,7 +794,7 @@
 static int atmel_startup(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	int retval;
 
 	/*
@@ -956,6 +956,20 @@
 }
 
 /*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void atmel_flush_buffer(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	if (atmel_use_dma_tx(port)) {
+		UART_PUT_TCR(port, 0);
+		atmel_port->pdc_tx.ofs = 0;
+	}
+}
+
+/*
  * Power / Clock management.
  */
 static void atmel_serial_pm(struct uart_port *port, unsigned int state,
@@ -1189,6 +1203,7 @@
 	.break_ctl	= atmel_break_ctl,
 	.startup	= atmel_startup,
 	.shutdown	= atmel_shutdown,
+	.flush_buffer	= atmel_flush_buffer,
 	.set_termios	= atmel_set_termios,
 	.type		= atmel_type,
 	.release_port	= atmel_release_port,
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index fd9bb77..9d85437 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -175,7 +175,7 @@
 #ifdef CONFIG_SERIAL_BFIN_PIO
 static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
 {
-	struct tty_struct *tty = uart->port.info->tty;
+	struct tty_struct *tty = uart->port.info->port.tty;
 	unsigned int status, ch, flg;
 	static struct timeval anomaly_start = { .tv_sec = 0 };
 
@@ -393,7 +393,7 @@
 
 static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 {
-	struct tty_struct *tty = uart->port.info->tty;
+	struct tty_struct *tty = uart->port.info->port.tty;
 	int i, flg, status;
 
 	status = UART_GET_LSR(uart);
@@ -552,7 +552,7 @@
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
 	unsigned int status;
 	struct uart_info *info = uart->port.info;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	status = bfin_serial_get_mctrl(&uart->port);
 	uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
@@ -814,10 +814,10 @@
 	int line = port->line;
 	unsigned short val;
 
-	if (line >= port->info->tty->driver->num)
+	if (line >= port->info->port.tty->driver->num)
 		return;
 
-	switch (port->info->tty->ldisc.num) {
+	switch (port->info->port.tty->ldisc.num) {
 	case N_IRDA:
 		val = UART_GET_GCTL(&bfin_serial_ports[line]);
 		val |= (IREN | RPOLC);
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
index aca1240..dd8564d 100644
--- a/drivers/serial/bfin_sport_uart.c
+++ b/drivers/serial/bfin_sport_uart.c
@@ -174,7 +174,7 @@
 static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
 {
 	struct sport_uart_port *up = dev_id;
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned int ch;
 
 	do {
@@ -201,7 +201,7 @@
 static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
 {
 	struct sport_uart_port *up = dev_id;
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned int stat = SPORT_GET_STAT(up);
 
 	/* Overflow in RX FIFO */
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
index 2382718..fc1fa92 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -21,9 +21,6 @@
  * 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
- *
- *  $Id: clps711x.c,v 1.42 2002/07/28 10:03:28 rmk Exp $
- *
  */
 
 #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -96,7 +93,7 @@
 static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	unsigned int status, ch, flg;
 
 	status = clps_readl(SYSFLG(port));
@@ -551,7 +548,7 @@
 {
 	int ret, i;
 
-	printk(KERN_INFO "Serial: CLPS711x driver $Revision: 1.42 $\n");
+	printk(KERN_INFO "Serial: CLPS711x driver\n");
 
 	ret = uart_register_driver(&clps711x_reg);
 	if (ret)
@@ -577,6 +574,6 @@
 module_exit(clps711xuart_exit);
 
 MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.42 $");
+MODULE_DESCRIPTION("CLPS-711x generic serial driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 3e0366e..8249ac4 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -968,7 +968,7 @@
 /* Calculate the chartime depending on baudrate, numbor of bits etc. */
 static void update_char_time(struct e100_serial * info)
 {
-	tcflag_t cflags = info->tty->termios->c_cflag;
+	tcflag_t cflags = info->port.tty->termios->c_cflag;
 	int bits;
 
 	/* calc. number of bits / data byte */
@@ -1483,7 +1483,8 @@
 				CIRC_CNT(info->xmit.head,
 					 info->xmit.tail,SERIAL_XMIT_SIZE)));
 
-		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
+				STOP_CHAR(info->port.tty));
 		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
 		if (tty->termios->c_iflag & IXON ) {
 			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
@@ -1772,7 +1773,7 @@
 
 		info->icount.rx++;
 	} else {
-		struct tty_struct *tty = info->tty;
+		struct tty_struct *tty = info->port.tty;
 		tty_insert_flip_char(tty, data, flag);
 		info->icount.rx++;
 	}
@@ -1838,7 +1839,7 @@
 		descr->status = 0;
 
 		DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
-			if (info->tty->stopped) {
+			if (info->port.tty->stopped) {
 				unsigned char *buf = phys_to_virt(descr->buf);
 				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
 				DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
@@ -1872,7 +1873,7 @@
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
 		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty) /* Something wrong... */
 		return;
 
@@ -2122,7 +2123,7 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	tty = info->tty;
+	tty = info->port.tty;
 
 	if (!tty) {
 		local_irq_restore(flags);
@@ -2287,7 +2288,7 @@
 struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
 {
 	unsigned long data_read;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	if (!tty) {
 		printk("!NO TTY!\n");
@@ -2350,7 +2351,7 @@
 					data_in, data_read);
 				char flag = TTY_NORMAL;
 				if (info->errorcode == ERRCODE_INSERT_BREAK) {
-					struct tty_struct *tty = info->tty;
+					struct tty_struct *tty = info->port.tty;
 					tty_insert_flip_char(tty, 0, flag);
 					info->icount.rx++;
 				}
@@ -2396,7 +2397,7 @@
 		goto more_data;
 	}
 
-	tty_flip_buffer_push(info->tty);
+	tty_flip_buffer_push(info->port.tty);
 	return info;
 }
 
@@ -2547,8 +2548,8 @@
 		rstat = info->port[REG_STATUS];
 		DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
 		e100_disable_serial_tx_ready_irq(info);
-		if (info->tty->stopped)
-			rs_stop(info->tty);
+		if (info->port.tty->stopped)
+			rs_stop(info->port.tty);
 		/* Enable the DMA channel and tell it to continue */
 		e100_enable_txdma_channel(info);
 		/* Wait 12 cycles before doing the DMA command */
@@ -2561,9 +2562,10 @@
 	}
 	/* Normal char-by-char interrupt */
 	if (info->xmit.head == info->xmit.tail
-	    || info->tty->stopped
-	    || info->tty->hw_stopped) {
-		DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped));
+	    || info->port.tty->stopped
+	    || info->port.tty->hw_stopped) {
+		DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
+				info->port.tty->stopped));
 		e100_disable_serial_tx_ready_irq(info);
 		info->tr_running = 0;
 		return;
@@ -2725,7 +2727,7 @@
 
 	info = container_of(work, struct e100_serial, work);
 
-	tty = info->tty;
+	tty = info->port.tty;
 	if (!tty)
 		return;
 
@@ -2767,8 +2769,8 @@
 	/* Bits and pieces collected from below.  Better to have them
 	   in one ifdef:ed clause than to mix in a lot of ifdefs,
 	   right? */
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	info->xmit.head = info->xmit.tail = 0;
 	info->first_recv_buffer = info->last_recv_buffer = NULL;
@@ -2825,8 +2827,8 @@
 		e100_disable_txdma_channel(info);
 	}
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	info->xmit.head = info->xmit.tail = 0;
 	info->first_recv_buffer = info->last_recv_buffer = NULL;
@@ -2940,14 +2942,14 @@
 			descr[i].buf = 0;
 		}
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
 		/* hang up DTR and RTS if HUPCL is enabled */
 		e100_dtr(info, 0);
 		e100_rts(info, 0); /* could check CRTSCTS before doing this */
 	}
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	info->flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
@@ -2964,12 +2966,12 @@
 	unsigned long flags;
 	/* first some safety checks */
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
 	if (!info->port)
 		return;
 
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 
 	/* possibly, the tx/rx should be disabled first to do this safely */
 
@@ -3097,10 +3099,11 @@
 
 	info->port[REG_TR_CTRL] = info->tx_ctrl;
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
 	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-	if (info->tty->termios->c_iflag & IXON ) {
-		DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty)));
+	if (info->port.tty->termios->c_iflag & IXON ) {
+		DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
+				STOP_CHAR(info->port.tty)));
 		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
 	}
 
@@ -3475,7 +3478,7 @@
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
 	info->closing_wait = new_serial.closing_wait;
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
  check_and_exit:
 	if (info->flags & ASYNC_INITIALIZED) {
@@ -3811,7 +3814,7 @@
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	info->event = 0;
-	info->tty = 0;
+	info->port.tty = NULL;
 	if (info->blocked_open) {
 		if (info->close_delay)
 			schedule_timeout_interruptible(info->close_delay);
@@ -3915,7 +3918,7 @@
 	info->event = 0;
 	info->count = 0;
 	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = 0;
+	info->port.tty = NULL;
 	wake_up_interruptible(&info->open_wait);
 }
 
@@ -4077,9 +4080,9 @@
 
 	info->count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
@@ -4267,14 +4270,14 @@
 		       (unsigned long)info->max_recv_cnt);
 
 #if 1
-	if (info->tty) {
+	if (info->port.tty) {
 
-		if (info->tty->stopped)
+		if (info->port.tty->stopped)
 			ret += sprintf(buf+ret, " stopped:%i",
-				       (int)info->tty->stopped);
-		if (info->tty->hw_stopped)
+				       (int)info->port.tty->stopped);
+		if (info->port.tty->hw_stopped)
 			ret += sprintf(buf+ret, " hw_stopped:%i",
-				       (int)info->tty->hw_stopped);
+				       (int)info->port.tty->hw_stopped);
 	}
 
 	{
@@ -4465,7 +4468,7 @@
 		info->uses_dma_in = 0;
 		info->uses_dma_out = 0;
 		info->line = i;
-		info->tty = 0;
+		info->port.tty = NULL;
 		info->type = PORT_ETRAX;
 		info->tr_running = 0;
 		info->forced_eop = 0;
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 0dddd68..a81d2c2 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -197,7 +197,7 @@
 	while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
 		dport = &mux->dport[LINE(status)];
 		uport = &dport->port;
-		tty = uport->info->tty;		/* point to the proper dev */
+		tty = uport->info->port.tty;	/* point to the proper dev */
 
 		ch = UCHAR(status);		/* grab the char */
 		flag = TTY_NORMAL;
@@ -249,7 +249,7 @@
 	}
 	for (i = 0; i < DZ_NB_PORT; i++)
 		if (lines_rx[i])
-			tty_flip_buffer_push(mux->dport[i].port.info->tty);
+			tty_flip_buffer_push(mux->dport[i].port.info->port.tty);
 }
 
 /*
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 64acb39..e0da4dc 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -372,7 +372,7 @@
 {
 	struct imx_port *sport = dev_id;
 	unsigned int rx,flg,ignored = 0;
-	struct tty_struct *tty = sport->port.info->tty;
+	struct tty_struct *tty = sport->port.info->port.tty;
 	unsigned long flags, temp;
 
 	spin_lock_irqsave(&sport->port.lock,flags);
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 4f1af71..6dd98f9 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -905,7 +905,7 @@
 		return;
 
 	info = the_port->info;
-	tty = info->tty;
+	tty = info->port.tty;
 
 	if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
 		/* Nothing to do or hw stopped */
@@ -997,14 +997,14 @@
 
 	the_port->ignore_status_mask = N_ALL_INPUT;
 
-	info->tty->low_latency = 1;
+	info->port.tty->low_latency = 1;
 
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		the_port->ignore_status_mask &= ~(N_PARITY_ERROR
 						  | N_FRAMING_ERROR);
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		the_port->ignore_status_mask &= ~N_BREAK;
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
 	}
 	if (!(cflag & CREAD)) {
@@ -1399,14 +1399,14 @@
 	/* Make sure all the pointers are "good" ones */
 	if (!info)
 		return 0;
-	if (!info->tty)
+	if (!info->port.tty)
 		return 0;
 
 	if (!(port->ip_flags & INPUT_ENABLE))
 		return 0;
 
 	spin_lock_irqsave(&the_port->lock, pflags);
-	tty = info->tty;
+	tty = info->port.tty;
 
 	read_count = do_read(the_port, ch, MAX_CHARS);
 	if (read_count > 0) {
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 49b8a82..6bab63c 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -1635,7 +1635,7 @@
 		return;
 
 	info = the_port->info;
-	tty = info->tty;
+	tty = info->port.tty;
 
 	if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
 		/* Nothing to do or hw stopped */
@@ -1738,14 +1738,14 @@
 
 	the_port->ignore_status_mask = N_ALL_INPUT;
 
-	info->tty->low_latency = 1;
+	info->port.tty->low_latency = 1;
 
-	if (I_IGNPAR(info->tty))
+	if (I_IGNPAR(info->port.tty))
 		the_port->ignore_status_mask &= ~(N_PARITY_ERROR
 						| N_FRAMING_ERROR);
-	if (I_IGNBRK(info->tty)) {
+	if (I_IGNBRK(info->port.tty)) {
 		the_port->ignore_status_mask &= ~N_BREAK;
-		if (I_IGNPAR(info->tty))
+		if (I_IGNPAR(info->port.tty))
 			the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
 	}
 	if (!(cflag & CREAD)) {
@@ -1801,7 +1801,8 @@
 	ioc4_set_proto(port, the_port->mapbase);
 
 	/* set the speed of the serial port */
-	ioc4_change_speed(the_port, info->tty->termios, (struct ktermios *)0);
+	ioc4_change_speed(the_port, info->port.tty->termios,
+			  (struct ktermios *)0);
 
 	return 0;
 }
@@ -2346,11 +2347,11 @@
 	/* Make sure all the pointers are "good" ones */
 	if (!info)
 		return;
-	if (!info->tty)
+	if (!info->port.tty)
 		return;
 
 	spin_lock_irqsave(&the_port->lock, pflags);
-	tty = info->tty;
+	tty = info->port.tty;
 
 	request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
 
@@ -2440,8 +2441,8 @@
 
 	wake_up_interruptible(&info->delta_msr_wait);
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	spin_lock_irqsave(&the_port->lock, port_flags);
 	set_notification(port, N_ALL, 0);
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 9c95bc0..0d9acbd 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -257,8 +257,8 @@
 
 	tty = NULL;
 	if (up->port.info != NULL &&
-	    up->port.info->tty != NULL)
-		tty = up->port.info->tty;
+	    up->port.info->port.tty != NULL)
+		tty = up->port.info->port.tty;
 
 	for (;;) {
 		ch = readb(&channel->control);
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index b2d6f5b..b7584ca 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -998,7 +998,7 @@
 			{     50, B50     },
 		};
 
-		cflag = C_BAUD(ch->uart_port.info->tty);
+		cflag = C_BAUD(ch->uart_port.info->port.tty);
 		baud = 9600;
 		for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
 			if (baud_rates[i].cflag == cflag) {
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 94ec663..a697914 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -145,7 +145,7 @@
 	struct ktermios *termios;
 
 	spin_lock_irqsave(&port->lock, lock_flags);
-	termios = port->info->tty->termios;
+	termios = port->info->port.tty->termios;
 	if (ch == termios->c_cc[VSTART])
 		channel->ch_bd->bd_ops->send_start_character(channel);
 
@@ -239,7 +239,7 @@
 	channel->ch_cached_lsr = 0;
 	channel->ch_stops_sent = 0;
 
-	termios = port->info->tty->termios;
+	termios = port->info->port.tty->termios;
 	channel->ch_c_cflag	= termios->c_cflag;
 	channel->ch_c_iflag	= termios->c_iflag;
 	channel->ch_c_oflag	= termios->c_oflag;
@@ -272,7 +272,7 @@
 	jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
 
 	bd = channel->ch_bd;
-	ts = channel->uart_port.info->tty->termios;
+	ts = channel->uart_port.info->port.tty->termios;
 
 	channel->ch_flags &= ~(CH_STOPI);
 
@@ -515,7 +515,7 @@
 	if (!ch)
 		return;
 
-	tp = ch->uart_port.info->tty;
+	tp = ch->uart_port.info->port.tty;
 
 	bd = ch->ch_bd;
 	if(!bd)
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index c2bb11c..23d0305 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -325,7 +325,7 @@
 
 static void receive_chars(struct uart_sio_port *up, int *status)
 {
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned char ch;
 	unsigned char flag;
 	int max_count = 256;
@@ -1160,7 +1160,7 @@
 {
 	int ret, i;
 
-	printk(KERN_INFO "Serial: M32R SIO driver $Revision: 1.11 $ ");
+	printk(KERN_INFO "Serial: M32R SIO driver\n");
 
 	for (i = 0; i < NR_IRQS; i++)
 		spin_lock_init(&irq_lists[i].lock);
@@ -1189,4 +1189,4 @@
 EXPORT_SYMBOL(m32r_sio_resume_port);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic M32R SIO serial driver $Revision: 1.11 $");
+MODULE_DESCRIPTION("Generic M32R SIO serial driver");
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
index 7e164e0..b2001c5 100644
--- a/drivers/serial/mcf.c
+++ b/drivers/serial/mcf.c
@@ -312,7 +312,7 @@
 		uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
 	}
 
-	tty_flip_buffer_push(port->info->tty);
+	tty_flip_buffer_push(port->info->port.tty);
 }
 
 /****************************************************************************/
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 56007cc..fbe3835 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -327,7 +327,7 @@
 static inline void receive_chars(struct mcf_serial *info)
 {
 	volatile unsigned char	*uartp;
-	struct tty_struct	*tty = info->tty;
+	struct tty_struct	*tty = info->port.tty;
 	unsigned char		status, ch, flag;
 
 	if (!tty)
@@ -382,7 +382,7 @@
 		info->stats.tx++;
 	}
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped) {
+	if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
 		info->imr &= ~MCFUART_UIR_TXREADY;
 		uartp[MCFUART_UIMR] = info->imr;
 		return;
@@ -428,7 +428,7 @@
 static void mcfrs_offintr(struct work_struct *work)
 {
 	struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	
 	if (tty)
 		tty_wakeup(tty);
@@ -498,7 +498,7 @@
 static void do_serial_hangup(struct work_struct *work)
 {
 	struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 	
 	if (tty)
 		tty_hangup(tty);
@@ -532,8 +532,8 @@
 	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
 	mcfrs_setsignals(info, 1, 1);
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
@@ -578,7 +578,7 @@
 	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
 	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
 		mcfrs_setsignals(info, 0, 0);
 
 	if (info->xmit_buf) {
@@ -586,8 +586,8 @@
 		info->xmit_buf = 0;
 	}
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	
 	info->flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
@@ -609,9 +609,9 @@
 	unsigned int		fraction;
 #endif
 
-	if (!info->tty || !info->tty->termios)
+	if (!info->port.tty || !info->port.tty->termios)
 		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = info->port.tty->termios->c_cflag;
 	if (info->addr == 0)
 		return;
 
@@ -623,7 +623,7 @@
 	if (i & CBAUDEX) {
 		i &= ~CBAUDEX;
 		if (i < 1 || i > 4)
-			info->tty->termios->c_cflag &= ~CBAUDEX;
+			info->port.tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			i += 15;
 	}
@@ -1216,7 +1216,7 @@
 	
 	tty->closing = 0;
 	info->event = 0;
-	info->tty = 0;
+	info->port.tty = NULL;
 #if 0	
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
 		if (tty->ldisc.close)
@@ -1325,7 +1325,7 @@
 	info->event = 0;
 	info->count = 0;
 	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = 0;
+	info->port.tty = NULL;
 	wake_up_interruptible(&info->open_wait);
 }
 
@@ -1452,7 +1452,7 @@
 #endif
 	info->count++;
 	tty->driver_data = info;
-	info->tty = tty;
+	info->port.tty = tty;
 
 	/*
 	 * Start up serial port
@@ -1767,7 +1767,7 @@
 	for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
 		info->magic = SERIAL_MAGIC;
 		info->line = i;
-		info->tty = 0;
+		info->port.tty = NULL;
 		info->custom_divisor = 16;
 		info->close_delay = 50;
 		info->closing_wait = 3000;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index efc971d..3612607 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -732,7 +732,7 @@
 static inline int
 mpc52xx_uart_int_rx_chars(struct uart_port *port)
 {
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	unsigned char ch, flag;
 	unsigned short status;
 
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index e8819c4..c9f53e7 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -932,7 +932,7 @@
 static int mpsc_rx_intr(struct mpsc_port_info *pi)
 {
 	struct mpsc_rx_desc *rxre;
-	struct tty_struct *tty = pi->port.info->tty;
+	struct tty_struct *tty = pi->port.info->port.tty;
 	u32	cmdstat, bytes_in, i;
 	int	rc = 0;
 	u8	*bp;
@@ -1972,7 +1972,7 @@
 {
 	int	rc;
 
-	printk(KERN_INFO "Serial: MPSC driver $Revision: 1.00 $\n");
+	printk(KERN_INFO "Serial: MPSC driver\n");
 
 	memset(mpsc_ports, 0, sizeof(mpsc_ports));
 	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
@@ -2004,7 +2004,7 @@
 module_exit(mpsc_drv_exit);
 
 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver $Revision: 1.00 $");
+MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
 MODULE_VERSION(MPSC_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index e940317..953a5ff 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -243,7 +243,7 @@
 static void mux_read(struct uart_port *port)
 {
 	int data;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	__u32 start_count = port->icount.rx;
 
 	while(1) {
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index 81ac9bb..9f8ccb7 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -203,7 +203,7 @@
 static void netx_rxint(struct uart_port *port)
 {
 	unsigned char rx, flg, status;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 
 	while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
 		rx = readl(port->membase + UART_DR);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 794bd0f..317b061 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -242,12 +242,12 @@
 	}
 
 	/* Sanity check, make sure the old bug is no longer happening */
-	if (uap->port.info == NULL || uap->port.info->tty == NULL) {
+	if (uap->port.info == NULL || uap->port.info->port.tty == NULL) {
 		WARN_ON(1);
 		(void)read_zsdata(uap);
 		return NULL;
 	}
-	tty = uap->port.info->tty;
+	tty = uap->port.info->port.tty;
 
 	while (1) {
 		error = 0;
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c
index d0e5a79..22e30d2 100644
--- a/drivers/serial/pnx8xxx_uart.c
+++ b/drivers/serial/pnx8xxx_uart.c
@@ -181,7 +181,7 @@
 
 static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
 {
-	struct tty_struct *tty = sport->port.info->tty;
+	struct tty_struct *tty = sport->port.info->port.tty;
 	unsigned int status, ch, flg;
 
 	status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
@@ -824,7 +824,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "Serial: PNX8XXX driver $Revision: 1.2 $\n");
+	printk(KERN_INFO "Serial: PNX8XXX driver\n");
 
 	pnx8xxx_init_ports();
 
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index b4f7ffb..b9a93f3 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -101,7 +101,7 @@
 
 static inline void receive_chars(struct uart_pxa_port *up, int *status)
 {
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned int ch, flag;
 	int max_count = 256;
 
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index 62b3858..a5e76cc 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -20,9 +20,6 @@
  * 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
- *
- *  $Id: sa1100.c,v 1.50 2002/07/29 14:41:04 rmk Exp $
- *
  */
 
 #if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -192,7 +189,7 @@
 static void
 sa1100_rx_chars(struct sa1100_port *sport)
 {
-	struct tty_struct *tty = sport->port.info->tty;
+	struct tty_struct *tty = sport->port.info->port.tty;
 	unsigned int status, ch, flg;
 
 	status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
@@ -892,7 +889,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "Serial: SA11x0 driver $Revision: 1.50 $\n");
+	printk(KERN_INFO "Serial: SA11x0 driver\n");
 
 	sa1100_init_ports();
 
@@ -915,7 +912,7 @@
 module_exit(sa1100_serial_exit);
 
 MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $");
+MODULE_DESCRIPTION("SA1100 generic serial port driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);
 MODULE_ALIAS("platform:sa11x0-uart");
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
index f8e1447..a4fb343a 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/serial/sb1250-duart.c
@@ -384,7 +384,7 @@
 		uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
 	}
 
-	tty_flip_buffer_push(uport->info->tty);
+	tty_flip_buffer_push(uport->info->port.tty);
 }
 
 static void sbd_transmit_chars(struct sbd_port *sport)
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
index ae2a9e2..e0be11c 100644
--- a/drivers/serial/sc26xx.c
+++ b/drivers/serial/sc26xx.c
@@ -141,7 +141,7 @@
 	u8 status;
 
 	if (port->info != NULL)		/* Unopened serial console */
-		tty = port->info->tty;
+		tty = port->info->port.tty;
 
 	while (limit-- > 0) {
 		status = READ_SC_PORT(port, SR);
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 42d2e10..0bce1fe 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -50,7 +50,7 @@
 
 #define HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)
 
-#define uart_users(state)	((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
+#define uart_users(state)	((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0))
 
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
 #define uart_console(port)	((port)->cons && (port)->cons->index == (port)->line)
@@ -113,7 +113,7 @@
 static void uart_tasklet_action(unsigned long data)
 {
 	struct uart_state *state = (struct uart_state *)data;
-	tty_wakeup(state->info->tty);
+	tty_wakeup(state->info->port.tty);
 }
 
 static inline void
@@ -135,7 +135,7 @@
 
 /*
  * Startup the port.  This will be called once per open.  All calls
- * will be serialised by the per-port semaphore.
+ * will be serialised by the per-port mutex.
  */
 static int uart_startup(struct uart_state *state, int init_hw)
 {
@@ -152,7 +152,7 @@
 	 * once we have successfully opened the port.  Also set
 	 * up the tty->alt_speed kludge
 	 */
-	set_bit(TTY_IO_ERROR, &info->tty->flags);
+	set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	if (port->type == PORT_UNKNOWN)
 		return 0;
@@ -162,6 +162,7 @@
 	 * buffer.
 	 */
 	if (!info->xmit.buf) {
+		/* This is protected by the per port mutex */
 		page = get_zeroed_page(GFP_KERNEL);
 		if (!page)
 			return -ENOMEM;
@@ -182,20 +183,20 @@
 			 * Setup the RTS and DTR signals once the
 			 * port is open and ready to respond.
 			 */
-			if (info->tty->termios->c_cflag & CBAUD)
+			if (info->port.tty->termios->c_cflag & CBAUD)
 				uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
 		}
 
 		if (info->flags & UIF_CTS_FLOW) {
 			spin_lock_irq(&port->lock);
 			if (!(port->ops->get_mctrl(port) & TIOCM_CTS))
-				info->tty->hw_stopped = 1;
+				info->port.tty->hw_stopped = 1;
 			spin_unlock_irq(&port->lock);
 		}
 
 		info->flags |= UIF_INITIALIZED;
 
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	}
 
 	if (retval && capable(CAP_SYS_ADMIN))
@@ -217,8 +218,8 @@
 	/*
 	 * Set the TTY IO error marker
 	 */
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 	if (info->flags & UIF_INITIALIZED) {
 		info->flags &= ~UIF_INITIALIZED;
@@ -226,7 +227,7 @@
 		/*
 		 * Turn off DTR and RTS early.
 		 */
-		if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
 			uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 
 		/*
@@ -426,7 +427,7 @@
 static void
 uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
 {
-	struct tty_struct *tty = state->info->tty;
+	struct tty_struct *tty = state->info->port.tty;
 	struct uart_port *port = state->port;
 	struct ktermios *termios;
 
@@ -573,6 +574,8 @@
 
 	spin_lock_irqsave(&port->lock, flags);
 	uart_circ_clear(&state->info->xmit);
+	if (port->ops->flush_buffer)
+		port->ops->flush_buffer(port);
 	spin_unlock_irqrestore(&port->lock, flags);
 	tty_wakeup(tty);
 }
@@ -834,8 +837,8 @@
 	state->closing_wait    = closing_wait;
 	if (new_serial.xmit_fifo_size)
 		port->fifosize = new_serial.xmit_fifo_size;
-	if (state->info->tty)
-		state->info->tty->low_latency =
+	if (state->info->port.tty)
+		state->info->port.tty->low_latency =
 			(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
 
  check_and_exit:
@@ -855,7 +858,7 @@
 				printk(KERN_NOTICE
 				       "%s sets custom speed on %s. This "
 				       "is deprecated.\n", current->comm,
-				       tty_name(state->info->tty, buf));
+				       tty_name(state->info->port.tty, buf));
 			}
 			uart_change_speed(state, NULL);
 		}
@@ -887,7 +890,7 @@
 	 */
 	if (port->x_char ||
 	    ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
-	     !state->info->tty->stopped && !state->info->tty->hw_stopped))
+	     !state->info->port.tty->stopped && !state->info->port.tty->hw_stopped))
 		result &= ~TIOCSER_TEMT;
 
 	return put_user(result, value);
@@ -1237,7 +1240,7 @@
 	 */
 	if (!(old_termios->c_cflag & CLOCAL) &&
 	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&state->info->open_wait);
+		wake_up_interruptible(&state->info->port.open_wait);
 #endif
 }
 
@@ -1318,9 +1321,9 @@
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	state->info->tty = NULL;
+	state->info->port.tty = NULL;
 
-	if (state->info->blocked_open) {
+	if (state->info->port.blocked_open) {
 		if (state->close_delay)
 			msleep_interruptible(state->close_delay);
 	} else if (!uart_console(port)) {
@@ -1331,7 +1334,7 @@
 	 * Wake up anyone trying to open this port.
 	 */
 	state->info->flags &= ~UIF_NORMAL_ACTIVE;
-	wake_up_interruptible(&state->info->open_wait);
+	wake_up_interruptible(&state->info->port.open_wait);
 
  done:
 	mutex_unlock(&state->mutex);
@@ -1415,8 +1418,8 @@
 		uart_shutdown(state);
 		state->count = 0;
 		state->info->flags &= ~UIF_NORMAL_ACTIVE;
-		state->info->tty = NULL;
-		wake_up_interruptible(&state->info->open_wait);
+		state->info->port.tty = NULL;
+		wake_up_interruptible(&state->info->port.open_wait);
 		wake_up_interruptible(&state->info->delta_msr_wait);
 	}
 	mutex_unlock(&state->mutex);
@@ -1430,7 +1433,7 @@
  */
 static void uart_update_termios(struct uart_state *state)
 {
-	struct tty_struct *tty = state->info->tty;
+	struct tty_struct *tty = state->info->port.tty;
 	struct uart_port *port = state->port;
 
 	if (uart_console(port) && port->cons->cflag) {
@@ -1469,17 +1472,17 @@
 	struct uart_port *port = state->port;
 	unsigned int mctrl;
 
-	info->blocked_open++;
+	info->port.blocked_open++;
 	state->count--;
 
-	add_wait_queue(&info->open_wait, &wait);
+	add_wait_queue(&info->port.open_wait, &wait);
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
 		/*
 		 * If we have been hung up, tell userspace/restart open.
 		 */
-		if (tty_hung_up_p(filp) || info->tty == NULL)
+		if (tty_hung_up_p(filp) || info->port.tty == NULL)
 			break;
 
 		/*
@@ -1498,8 +1501,8 @@
 		 * have set TTY_IO_ERROR for a non-existant port.
 		 */
 		if ((filp->f_flags & O_NONBLOCK) ||
-		    (info->tty->termios->c_cflag & CLOCAL) ||
-		    (info->tty->flags & (1 << TTY_IO_ERROR)))
+		    (info->port.tty->termios->c_cflag & CLOCAL) ||
+		    (info->port.tty->flags & (1 << TTY_IO_ERROR)))
 			break;
 
 		/*
@@ -1507,7 +1510,7 @@
 		 * not set RTS here - we want to make sure we catch
 		 * the data from the modem.
 		 */
-		if (info->tty->termios->c_cflag & CBAUD)
+		if (info->port.tty->termios->c_cflag & CBAUD)
 			uart_set_mctrl(port, TIOCM_DTR);
 
 		/*
@@ -1529,15 +1532,15 @@
 			break;
 	}
 	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&info->open_wait, &wait);
+	remove_wait_queue(&info->port.open_wait, &wait);
 
 	state->count++;
-	info->blocked_open--;
+	info->port.blocked_open--;
 
 	if (signal_pending(current))
 		return -ERESTARTSYS;
 
-	if (!info->tty || tty_hung_up_p(filp))
+	if (!info->port.tty || tty_hung_up_p(filp))
 		return -EAGAIN;
 
 	return 0;
@@ -1560,10 +1563,13 @@
 		goto err_unlock;
 	}
 
+	/* BKL: RACE HERE - LEAK */
+	/* We should move this into the uart_state structure and kill off
+	   this whole complexity */
 	if (!state->info) {
 		state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
 		if (state->info) {
-			init_waitqueue_head(&state->info->open_wait);
+			init_waitqueue_head(&state->info->port.open_wait);
 			init_waitqueue_head(&state->info->delta_msr_wait);
 
 			/*
@@ -1620,7 +1626,7 @@
 	 * be re-entered while allocating the info structure, or while we
 	 * request any IRQs that the driver may need.  This also has the nice
 	 * side-effect that it delays the action of uart_hangup, so we can
-	 * guarantee that info->tty will always contain something reasonable.
+	 * guarantee that info->port.tty will always contain something reasonable.
 	 */
 	state = uart_get(drv, line);
 	if (IS_ERR(state)) {
@@ -1636,7 +1642,7 @@
 	tty->driver_data = state;
 	tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
 	tty->alt_speed = 0;
-	state->info->tty = tty;
+	state->info->port.tty = tty;
 
 	/*
 	 * If the port is in the middle of closing, bail out now.
@@ -2099,8 +2105,8 @@
 		/*
 		 * If that's unset, use the tty termios setting.
 		 */
-		if (state->info && state->info->tty && termios.c_cflag == 0)
-			termios = *state->info->tty->termios;
+		if (state->info && state->info->port.tty && termios.c_cflag == 0)
+			termios = *state->info->port.tty->termios;
 
 		uart_change_pm(state, 0);
 		port->ops->set_termios(port, &termios, NULL);
@@ -2519,8 +2525,8 @@
 	tty_unregister_device(drv->tty_driver, port->line);
 
 	info = state->info;
-	if (info && info->tty)
-		tty_vhangup(info->tty);
+	if (info && info->port.tty)
+		tty_vhangup(info->port.tty);
 
 	/*
 	 * All users of this port should now be disconnected from
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
index 8721afe..0edbc5d 100644
--- a/drivers/serial/serial_ks8695.c
+++ b/drivers/serial/serial_ks8695.c
@@ -108,7 +108,7 @@
 static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	unsigned int status, ch, lsr, flg, max_count = 256;
 
 	status = UART_GET_LSR(port);		/* clears pending LSR interrupts */
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index eb18d42..cb49a5a 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -137,7 +137,7 @@
 
 static void lh7a40xuart_rx_chars (struct uart_port* port)
 {
-	struct tty_struct* tty = port->info->tty;
+	struct tty_struct* tty = port->info->port.tty;
 	int cbRxMax = 256;	/* (Gross) limit on receive */
 	unsigned int data;	/* Received data and status */
 	unsigned int flag;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index ce6ee92..208e42b 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -521,7 +521,7 @@
 static inline void sci_receive_chars(struct uart_port *port)
 {
 	struct sci_port *sci_port = (struct sci_port *)port;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	int i, count, copied = 0;
 	unsigned short status;
 	unsigned char flag;
@@ -642,7 +642,7 @@
 {
 	int copied = 0;
 	unsigned short status = sci_in(port, SCxSR);
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 
 	if (status & SCxSR_ORER(port)) {
 		/* overrun error */
@@ -692,7 +692,7 @@
 {
 	int copied = 0;
 	unsigned short status = sci_in(port, SCxSR);
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	struct sci_port *s = &sci_ports[port->line];
 
 	if (uart_handle_break(port))
@@ -762,7 +762,7 @@
 	} else {
 #if defined(SCIF_ORER)
 		if((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
-			struct tty_struct *tty = port->info->tty;
+			struct tty_struct *tty = port->info->port.tty;
 
 			sci_out(port, SCLSR, 0);
 			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 019da2e..b73e3c0 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -471,7 +471,7 @@
 
 	if (port->sc_port.info) {
 		/* The serial_core stuffs are initilized, use them */
-		tty = port->sc_port.info->tty;
+		tty = port->sc_port.info->port.tty;
 	}
 	else {
 		/* Not registered yet - can't pass to tty layer.  */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 2847336..aeeec55 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -185,7 +185,7 @@
 	struct tty_struct *tty = NULL;
 
 	if (port->info != NULL)		/* Unopened serial console */
-		tty = port->info->tty;
+		tty = port->info->port.tty;
 
 	if (sunhv_ops->receive_chars(port, tty))
 		sun_do_break();
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 9ff5b38..15ee497 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -118,7 +118,7 @@
 	int i;
 
 	if (up->port.info != NULL)		/* Unopened serial console */
-		tty = up->port.info->tty;
+		tty = up->port.info->port.tty;
 
 	/* Read number of BYTES (Character + Status) available. */
 	if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 03806a9..e24e682 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.55 2002/01/08 16:00:16 davem Exp $
+/*
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -311,7 +311,7 @@
 static struct tty_struct *
 receive_chars(struct uart_sunsu_port *up, unsigned char *status)
 {
-	struct tty_struct *tty = up->port.info->tty;
+	struct tty_struct *tty = up->port.info->port.tty;
 	unsigned char ch, flag;
 	int max_count = 256;
 	int saw_console_brk = 0;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 7e9fa5e..0f3d69b 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -329,8 +329,8 @@
 
 	tty = NULL;
 	if (up->port.info != NULL &&		/* Unopened serial console */
-	    up->port.info->tty != NULL)		/* Keyboard || mouse */
-		tty = up->port.info->tty;
+	    up->port.info->port.tty != NULL)	/* Keyboard || mouse */
+		tty = up->port.info->port.tty;
 
 	for (;;) {
 
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index b51c242..6a3f8fb 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -75,7 +75,7 @@
 
 static int ulite_receive(struct uart_port *port, int stat)
 {
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	unsigned char ch = 0;
 	char flag = TTY_NORMAL;
 
@@ -162,7 +162,7 @@
 		busy |= ulite_transmit(port, stat);
 	} while (busy);
 
-	tty_flip_buffer_push(port->info->tty);
+	tty_flip_buffer_push(port->info->port.tty);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 566a8b4..5c5d18d 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -466,7 +466,7 @@
 	int i;
 	unsigned char ch, *cp;
 	struct uart_port *port = &qe_port->port;
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 	struct qe_bd *bdp;
 	u16 status;
 	unsigned int flg;
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
index dd98aca..5acf061 100644
--- a/drivers/serial/v850e_uart.c
+++ b/drivers/serial/v850e_uart.c
@@ -300,8 +300,8 @@
 
 	port->icount.rx++;
 
-	tty_insert_flip_char (port->info->tty, ch, ch_stat);
-	tty_schedule_flip (port->info->tty);
+	tty_insert_flip_char (port->info->port.tty, ch, ch_stat);
+	tty_schedule_flip (port->info->port.tty);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index bb6ce6b..0573f3b 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -318,7 +318,7 @@
 	char flag;
 	int max_count = RX_MAX_COUNT;
 
-	tty = port->info->tty;
+	tty = port->info->port.tty;
 	lsr = *status;
 
 	do {
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
index 65f1294..bd45b62 100644
--- a/drivers/serial/zs.c
+++ b/drivers/serial/zs.c
@@ -602,7 +602,7 @@
 		uart_insert_char(uport, status, Rx_OVR, ch, flag);
 	}
 
-	tty_flip_buffer_push(uport->info->tty);
+	tty_flip_buffer_push(uport->info->port.tty);
 }
 
 static void zs_raw_transmit_chars(struct zs_port *zport)
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 05a328c..45c154a 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -2383,6 +2383,9 @@
 		goto amifb_error;
 	}
 
+	fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
+				 &fb_info.modelist);
+
 	round_down_bpp = 0;
 	chipptr = chipalloc(fb_info.fix.smem_len+
 	                    SPRITEMEMSIZE+
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index dff3547..fa55d35 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -3110,7 +3110,7 @@
 	printk("atafb_init: start\n");
 
 	if (!MACH_IS_ATARI)
-		return -ENXIO;
+		return -ENODEV;
 
 	do {
 #ifdef ATAFB_EXT
@@ -3230,6 +3230,9 @@
 		return -EINVAL;
 	}
 
+	fb_videomode_to_modelist(atafb_modedb, NUM_TOTAL_MODES,
+				 &fb_info.modelist);
+
 	atafb_set_disp(&fb_info);
 
 	fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c
index 5c30bbd..376bc07 100644
--- a/drivers/video/c2p.c
+++ b/drivers/video/c2p.c
@@ -12,6 +12,7 @@
  *  for more details.
  */
 
+#include <linux/module.h>
 #include <linux/string.h>
 #include "c2p.h"
 
@@ -226,4 +227,6 @@
 	dst += dst_nextline;
     }
 }
+EXPORT_SYMBOL_GPL(c2p);
 
+MODULE_LICENSE("GPL");
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 099b6fb..d47c47f 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -1,6 +1,4 @@
 /*
- *	$Id: proc.c,v 1.1.2.1 1998/06/07 23:21:01 geert Exp $
- *
  *	Procfs interface for the Zorro bus.
  *
  *	Copyright (C) 1998-2003 Geert Uytterhoeven
@@ -160,4 +158,4 @@
 	return 0;
 }
 
-__initcall(zorro_proc_init);
+device_initcall(zorro_proc_init);
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 808b4f8..3da712c 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -15,6 +15,7 @@
 #include <linux/zorro.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/fs.h>
 
 #include "zorro.h"
 
@@ -56,12 +57,6 @@
 	struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device,
 					   kobj));
 	struct ConfigDev cd;
-	unsigned int size = sizeof(cd);
-
-	if (off > size)
-		return 0;
-	if (off+count > size)
-		count = size-off;
 
 	/* Construct a ConfigDev */
 	memset(&cd, 0, sizeof(cd));
@@ -71,8 +66,7 @@
 	cd.cd_BoardAddr = (void *)zorro_resource_start(z);
 	cd.cd_BoardSize = zorro_resource_len(z);
 
-	memcpy(buf, (void *)&cd+off, count);
-	return count;
+	return memory_read_from_buffer(buf, count, &off, &cd, sizeof(cd));
 }
 
 static struct bin_attribute zorro_config_attr = {
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index 4cc42b6..dff16d9 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -1,6 +1,4 @@
 /*
- *    $Id: zorro.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $
- *
  *    Zorro Bus Services
  *
  *    Copyright (C) 1995-2003 Geert Uytterhoeven
diff --git a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids
index 560fef2..0c0f99e 100644
--- a/drivers/zorro/zorro.ids
+++ b/drivers/zorro/zorro.ids
@@ -4,8 +4,6 @@
 #	Maintained by Geert Uytterhoeven <zorro@linux-m68k.org>
 #	If you have any new entries, please send them to the maintainer.
 #
-#	$Id: zorro.ids,v 1.19 2002/10/14 13:08:58 geert Exp $
-#
 
 # Manufacturers and Products. Please keep sorted.
 
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 0e64312..179589b 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1027,9 +1027,10 @@
 
 static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-	int ret, module_got = 0;
-	struct config_group *group;
-	struct config_item *item;
+	int ret = 0;
+	int module_got = 0;
+	struct config_group *group = NULL;
+	struct config_item *item = NULL;
 	struct config_item *parent_item;
 	struct configfs_subsystem *subsys;
 	struct configfs_dirent *sd;
@@ -1070,25 +1071,30 @@
 	snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);
 
 	mutex_lock(&subsys->su_mutex);
-	group = NULL;
-	item = NULL;
 	if (type->ct_group_ops->make_group) {
-		ret = type->ct_group_ops->make_group(to_config_group(parent_item), name, &group);
-		if (!ret) {
+		group = type->ct_group_ops->make_group(to_config_group(parent_item), name);
+		if (!group)
+			group = ERR_PTR(-ENOMEM);
+		if (!IS_ERR(group)) {
 			link_group(to_config_group(parent_item), group);
 			item = &group->cg_item;
-		}
+		} else
+			ret = PTR_ERR(group);
 	} else {
-		ret = type->ct_group_ops->make_item(to_config_group(parent_item), name, &item);
-		if (!ret)
+		item = type->ct_group_ops->make_item(to_config_group(parent_item), name);
+		if (!item)
+			item = ERR_PTR(-ENOMEM);
+		if (!IS_ERR(item))
 			link_obj(parent_item, item);
+		else
+			ret = PTR_ERR(item);
 	}
 	mutex_unlock(&subsys->su_mutex);
 
 	kfree(name);
 	if (ret) {
 		/*
-		 * If ret != 0, then link_obj() was never called.
+		 * If item == NULL, then link_obj() was never called.
 		 * There are no extra references to clean up.
 		 */
 		goto out_put;
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 492d8ca..c4e7d72 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -41,20 +41,16 @@
 struct nodes;
 struct node;
 
-static int make_cluster(struct config_group *, const char *,
-			struct config_group **);
+static struct config_group *make_cluster(struct config_group *, const char *);
 static void drop_cluster(struct config_group *, struct config_item *);
 static void release_cluster(struct config_item *);
-static int make_space(struct config_group *, const char *,
-		      struct config_group **);
+static struct config_group *make_space(struct config_group *, const char *);
 static void drop_space(struct config_group *, struct config_item *);
 static void release_space(struct config_item *);
-static int make_comm(struct config_group *, const char *,
-		     struct config_item **);
+static struct config_item *make_comm(struct config_group *, const char *);
 static void drop_comm(struct config_group *, struct config_item *);
 static void release_comm(struct config_item *);
-static int make_node(struct config_group *, const char *,
-		     struct config_item **);
+static struct config_item *make_node(struct config_group *, const char *);
 static void drop_node(struct config_group *, struct config_item *);
 static void release_node(struct config_item *);
 
@@ -396,8 +392,8 @@
 	return i ? container_of(i, struct node, item) : NULL;
 }
 
-static int make_cluster(struct config_group *g, const char *name,
-			struct config_group **new_g)
+static struct config_group *make_cluster(struct config_group *g,
+					 const char *name)
 {
 	struct cluster *cl = NULL;
 	struct spaces *sps = NULL;
@@ -435,15 +431,14 @@
 
 	space_list = &sps->ss_group;
 	comm_list = &cms->cs_group;
-	*new_g = &cl->group;
-	return 0;
+	return &cl->group;
 
  fail:
 	kfree(cl);
 	kfree(gps);
 	kfree(sps);
 	kfree(cms);
-	return -ENOMEM;
+	return ERR_PTR(-ENOMEM);
 }
 
 static void drop_cluster(struct config_group *g, struct config_item *i)
@@ -471,8 +466,7 @@
 	kfree(cl);
 }
 
-static int make_space(struct config_group *g, const char *name,
-		      struct config_group **new_g)
+static struct config_group *make_space(struct config_group *g, const char *name)
 {
 	struct space *sp = NULL;
 	struct nodes *nds = NULL;
@@ -495,14 +489,13 @@
 	INIT_LIST_HEAD(&sp->members);
 	mutex_init(&sp->members_lock);
 	sp->members_count = 0;
-	*new_g = &sp->group;
-	return 0;
+	return &sp->group;
 
  fail:
 	kfree(sp);
 	kfree(gps);
 	kfree(nds);
-	return -ENOMEM;
+	return ERR_PTR(-ENOMEM);
 }
 
 static void drop_space(struct config_group *g, struct config_item *i)
@@ -529,21 +522,19 @@
 	kfree(sp);
 }
 
-static int make_comm(struct config_group *g, const char *name,
-		     struct config_item **new_i)
+static struct config_item *make_comm(struct config_group *g, const char *name)
 {
 	struct comm *cm;
 
 	cm = kzalloc(sizeof(struct comm), GFP_KERNEL);
 	if (!cm)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	config_item_init_type_name(&cm->item, name, &comm_type);
 	cm->nodeid = -1;
 	cm->local = 0;
 	cm->addr_count = 0;
-	*new_i = &cm->item;
-	return 0;
+	return &cm->item;
 }
 
 static void drop_comm(struct config_group *g, struct config_item *i)
@@ -563,15 +554,14 @@
 	kfree(cm);
 }
 
-static int make_node(struct config_group *g, const char *name,
-		     struct config_item **new_i)
+static struct config_item *make_node(struct config_group *g, const char *name)
 {
 	struct space *sp = to_space(g->cg_item.ci_parent);
 	struct node *nd;
 
 	nd = kzalloc(sizeof(struct node), GFP_KERNEL);
 	if (!nd)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	config_item_init_type_name(&nd->item, name, &node_type);
 	nd->nodeid = -1;
@@ -583,8 +573,7 @@
 	sp->members_count++;
 	mutex_unlock(&sp->members_lock);
 
-	*new_i = &nd->item;
-	return 0;
+	return &nd->item;
 }
 
 static void drop_node(struct config_group *g, struct config_item *i)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 443d108..7dce161 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1489,31 +1489,22 @@
 		: NULL;
 }
 
-static int o2hb_heartbeat_group_make_item(struct config_group *group,
-					  const char *name,
-					  struct config_item **new_item)
+static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group,
+							  const char *name)
 {
 	struct o2hb_region *reg = NULL;
-	int ret = 0;
 
 	reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL);
-	if (reg == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (reg == NULL)
+		return ERR_PTR(-ENOMEM);
 
 	config_item_init_type_name(&reg->hr_item, name, &o2hb_region_type);
 
-	*new_item = &reg->hr_item;
-
 	spin_lock(&o2hb_live_lock);
 	list_add_tail(&reg->hr_all_item, &o2hb_all_regions);
 	spin_unlock(&o2hb_live_lock);
-out:
-	if (ret)
-		kfree(reg);
 
-	return ret;
+	return &reg->hr_item;
 }
 
 static void o2hb_heartbeat_group_drop_item(struct config_group *group,
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index b364b70..816a3f6 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -644,35 +644,23 @@
 	return ret;
 }
 
-static int o2nm_node_group_make_item(struct config_group *group,
-				     const char *name,
-				     struct config_item **new_item)
+static struct config_item *o2nm_node_group_make_item(struct config_group *group,
+						     const char *name)
 {
 	struct o2nm_node *node = NULL;
-	int ret = 0;
 
-	if (strlen(name) > O2NM_MAX_NAME_LEN) {
-		ret = -ENAMETOOLONG;
-		goto out;
-	}
+	if (strlen(name) > O2NM_MAX_NAME_LEN)
+		return ERR_PTR(-ENAMETOOLONG);
 
 	node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL);
-	if (node == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (node == NULL)
+		return ERR_PTR(-ENOMEM);
 
 	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
 	config_item_init_type_name(&node->nd_item, name, &o2nm_node_type);
 	spin_lock_init(&node->nd_lock);
 
-	*new_item = &node->nd_item;
-
-out:
-	if (ret)
-		kfree(node);
-
-	return ret;
+	return &node->nd_item;
 }
 
 static void o2nm_node_group_drop_item(struct config_group *group,
@@ -756,31 +744,25 @@
 }
 #endif
 
-static int o2nm_cluster_group_make_group(struct config_group *group,
-					 const char *name,
-					 struct config_group **new_group)
+static struct config_group *o2nm_cluster_group_make_group(struct config_group *group,
+							  const char *name)
 {
 	struct o2nm_cluster *cluster = NULL;
 	struct o2nm_node_group *ns = NULL;
-	struct config_group *o2hb_group = NULL;
+	struct config_group *o2hb_group = NULL, *ret = NULL;
 	void *defs = NULL;
-	int ret = 0;
 
 	/* this runs under the parent dir's i_mutex; there can be only
 	 * one caller in here at a time */
-	if (o2nm_single_cluster) {
-		ret = -ENOSPC;
-		goto out;
-	}
+	if (o2nm_single_cluster)
+		return ERR_PTR(-ENOSPC);
 
 	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
 	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
 	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
 	o2hb_group = o2hb_alloc_hb_set();
-	if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL) {
-		ret = -ENOMEM;
+	if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL)
 		goto out;
-	}
 
 	config_group_init_type_name(&cluster->cl_group, name,
 				    &o2nm_cluster_type);
@@ -797,15 +779,16 @@
 	cluster->cl_idle_timeout_ms    = O2NET_IDLE_TIMEOUT_MS_DEFAULT;
 	cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT;
 
-	*new_group = &cluster->cl_group;
+	ret = &cluster->cl_group;
 	o2nm_single_cluster = cluster;
 
 out:
-	if (ret) {
+	if (ret == NULL) {
 		kfree(cluster);
 		kfree(ns);
 		o2hb_free_hb_set(o2hb_group);
 		kfree(defs);
+		ret = ERR_PTR(-ENOMEM);
 	}
 
 	return ret;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 21f490f..d153946 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -136,54 +136,6 @@
 	.release	= seq_release,
 };
 
-static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-	return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	(*pos)++;
-	return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-	int i = *(loff_t *)v;
-	struct tty_ldisc *ld;
-	
-	ld = tty_ldisc_get(i);
-	if (ld == NULL)
-		return 0;
-	seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i);
-	tty_ldisc_put(i);
-	return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-	.start	= tty_ldiscs_seq_start,
-	.next	= tty_ldiscs_seq_next,
-	.stop	= tty_ldiscs_seq_stop,
-	.show	= tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-static const struct file_operations tty_ldiscs_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= proc_tty_ldiscs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
 /*
  * This function is called by tty_register_driver() to handle
  * registering the driver's /proc handler into /proc/tty/driver/<foo>
diff --git a/include/asm-avr32/ioctls.h b/include/asm-avr32/ioctls.h
index 0500426..0cf2c0a 100644
--- a/include/asm-avr32/ioctls.h
+++ b/include/asm-avr32/ioctls.h
@@ -47,6 +47,10 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TCSETSF2	_IOW('T',0x2D, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
diff --git a/include/asm-cris/Kbuild b/include/asm-cris/Kbuild
index 1745545..b7037d8 100644
--- a/include/asm-cris/Kbuild
+++ b/include/asm-cris/Kbuild
@@ -1,7 +1,8 @@
 include include/asm-generic/Kbuild.asm
 
-header-$(CONFIG_ETRAX_ARCH_V10) += arch-v10/
-header-$(CONFIG_ETRAX_ARCH_V32) += arch-v32/
+header-y += arch/
+header-y += arch-v10/
+header-y += arch-v32/
 
 header-y += ethernet.h
 header-y += rtc.h
diff --git a/include/asm-frv/ioctls.h b/include/asm-frv/ioctls.h
index 341c7dd..d0c30e3 100644
--- a/include/asm-frv/ioctls.h
+++ b/include/asm-frv/ioctls.h
@@ -47,6 +47,10 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TCSETSF2	_IOW('T',0x2D, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
diff --git a/include/asm-frv/termbits.h b/include/asm-frv/termbits.h
index 74851b4..5568492 100644
--- a/include/asm-frv/termbits.h
+++ b/include/asm-frv/termbits.h
@@ -141,6 +141,7 @@
 #define HUPCL	0002000
 #define CLOCAL	0004000
 #define CBAUDEX 0010000
+#define    BOTHER 0010000
 #define    B57600 0010001
 #define   B115200 0010002
 #define   B230400 0010003
@@ -156,11 +157,13 @@
 #define  B3000000 0010015
 #define  B3500000 0010016
 #define  B4000000 0010017
-#define CIBAUD	  002003600000	/* input baud rate (not used) */
+#define CIBAUD	  002003600000		/* Input baud rate */
 #define CTVB	  004000000000		/* VisioBraille Terminal flow control */
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 
+#define IBSHIFT	16			/* Shift from CBAUD to CIBAUD */
+
 /* c_lflag bits */
 #define ISIG	0000001
 #define ICANON	0000002
diff --git a/include/asm-ia64/kvm_host.h b/include/asm-ia64/kvm_host.h
index c082c20..1efe513 100644
--- a/include/asm-ia64/kvm_host.h
+++ b/include/asm-ia64/kvm_host.h
@@ -38,6 +38,7 @@
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
 
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 
 /* define exit reasons from vmm to kvm*/
 #define EXIT_REASON_VM_PANIC		0
@@ -521,4 +522,6 @@
 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
 void kvm_sal_emul(struct kvm_vcpu *vcpu);
 
+static inline void kvm_inject_nmi(struct kvm_vcpu *vcpu) {}
+
 #endif
diff --git a/include/asm-m68k/amigahw.h b/include/asm-m68k/amigahw.h
index a16fe4e..5ca5dd9 100644
--- a/include/asm-m68k/amigahw.h
+++ b/include/asm-m68k/amigahw.h
@@ -22,8 +22,6 @@
      *  Different Amiga models
      */
 
-extern unsigned long amiga_model;
-
 #define AMI_UNKNOWN	(0)
 #define AMI_500		(1)
 #define AMI_500PLUS	(2)
@@ -59,11 +57,9 @@
      */
 
 extern unsigned long amiga_eclock;	/* 700 kHz E Peripheral Clock */
-extern unsigned long amiga_masterclock;	/* 28 MHz Master Clock */
 extern unsigned long amiga_colorclock;	/* 3.5 MHz Color Clock */
 extern unsigned long amiga_chip_size;	/* Chip RAM Size (bytes) */
 extern unsigned char amiga_vblank;	/* VBLANK Frequency */
-extern unsigned char amiga_psfreq;	/* Power Supply Frequency */
 
 
 #define AMIGAHW_DECLARE(name)	unsigned name : 1
diff --git a/include/asm-m68k/amigaints.h b/include/asm-m68k/amigaints.h
index 7c87134..b1bcdb8 100644
--- a/include/asm-m68k/amigaints.h
+++ b/include/asm-m68k/amigaints.h
@@ -98,6 +98,8 @@
 #define CIA_ICR_ALL	0x1f
 #define CIA_ICR_SETCLR	0x80
 
+extern void amiga_init_IRQ(void);
+
 /* to access the interrupt control registers of CIA's use only
 ** these functions, they behave exactly like the amiga os routines
 */
diff --git a/include/asm-m68k/apollodma.h b/include/asm-m68k/apollodma.h
index 6821e3b..954adc8 100644
--- a/include/asm-m68k/apollodma.h
+++ b/include/asm-m68k/apollodma.h
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/*
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
diff --git a/include/asm-m68k/dvma.h b/include/asm-m68k/dvma.h
index e1112de..4fff408 100644
--- a/include/asm-m68k/dvma.h
+++ b/include/asm-m68k/dvma.h
@@ -1,4 +1,4 @@
-/* $Id: dvma.h,v 1.4 1999/03/27 20:23:41 tsbogend Exp $
+/*
  * include/asm-m68k/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -63,8 +63,6 @@
 	return 0;
 }
 
-extern unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr);
-
 #else /* Sun3x */
 
 /* sun3x dvma page support */
diff --git a/include/asm-m68k/fpu.h b/include/asm-m68k/fpu.h
index 59701d7..ffb6b8c 100644
--- a/include/asm-m68k/fpu.h
+++ b/include/asm-m68k/fpu.h
@@ -7,15 +7,15 @@
  */
 
 #if defined(CONFIG_M68020) || defined(CONFIG_M68030)
-#define FPSTATESIZE (216/sizeof(unsigned char))
+#define FPSTATESIZE (216)
 #elif defined(CONFIG_M68040)
-#define FPSTATESIZE (96/sizeof(unsigned char))
+#define FPSTATESIZE (96)
 #elif defined(CONFIG_M68KFPU_EMU)
-#define FPSTATESIZE (28/sizeof(unsigned char))
+#define FPSTATESIZE (28)
 #elif defined(CONFIG_M68060)
-#define FPSTATESIZE (12/sizeof(unsigned char))
+#define FPSTATESIZE (12)
 #else
-#define FPSTATESIZE error no_cpu_type_configured
+#define FPSTATESIZE (0)
 #endif
 
 #endif /* __M68K_FPU_H */
diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
index eb29a52..226bfc0 100644
--- a/include/asm-m68k/irq.h
+++ b/include/asm-m68k/irq.h
@@ -24,7 +24,7 @@
 #elif defined(CONFIG_HP300)
 #define NR_IRQS	8
 #else
-#error unknown nr of irqs
+#define NR_IRQS	0
 #endif
 
 /*
diff --git a/include/asm-m68k/mac_baboon.h b/include/asm-m68k/mac_baboon.h
index e878508..c2a042b 100644
--- a/include/asm-m68k/mac_baboon.h
+++ b/include/asm-m68k/mac_baboon.h
@@ -29,6 +29,4 @@
 				 */
 };
 
-extern volatile struct baboon *baboon;
-
 #endif /* __ASSEMBLY **/
diff --git a/include/asm-m68k/mac_via.h b/include/asm-m68k/mac_via.h
index 59b758c..39afb43 100644
--- a/include/asm-m68k/mac_via.h
+++ b/include/asm-m68k/mac_via.h
@@ -253,7 +253,6 @@
 
 extern volatile __u8 *via1,*via2;
 extern int rbv_present,via_alt_mapping;
-extern __u8 rbv_clear;
 
 static inline int rbv_set_video_bpp(int bpp)
 {
diff --git a/include/asm-m68k/machines.h b/include/asm-m68k/machines.h
index da6015a..be667e8 100644
--- a/include/asm-m68k/machines.h
+++ b/include/asm-m68k/machines.h
@@ -1,4 +1,4 @@
-/* $Id: machines.h,v 1.4 1995/11/25 02:31:58 davem Exp $
+/*
  * machines.h:  Defines for taking apart the machine type value in the
  *              idprom and determining the kind of machine we are on.
  *
@@ -21,8 +21,6 @@
 //#define NUM_SUN_MACHINES   23
 #define NUM_SUN_MACHINES  8
 
-extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
-
 /* The machine type in the idprom area looks like this:
  *
  * ---------------
diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h
index 28b0f49..05309f7 100644
--- a/include/asm-m68k/macintosh.h
+++ b/include/asm-m68k/macintosh.h
@@ -12,8 +12,6 @@
 extern void mac_poweroff(void);
 extern void mac_init_IRQ(void);
 extern int mac_irq_pending(unsigned int);
-extern void mac_identify(void);
-extern void mac_report_hardware(void);
 
 /*
  *	Floppy driver magic hook - probably shouldnt be here
@@ -21,9 +19,6 @@
 
 extern void via1_set_head(int);
 
-extern void parse_booter(char *ptr);
-extern void print_booter(char *ptr);
-
 /*
  *	Macintosh Table
  */
diff --git a/include/asm-m68k/md.h b/include/asm-m68k/md.h
index 467ea08..d2f78f2 100644
--- a/include/asm-m68k/md.h
+++ b/include/asm-m68k/md.h
@@ -1,4 +1,4 @@
-/* $Id: md.h,v 1.1 1997/12/15 15:12:04 jj Exp $
+/*
  * md.h: High speed xor_block operation for RAID4/5
  *
  */
diff --git a/include/asm-m68k/openprom.h b/include/asm-m68k/openprom.h
index 869ab91..d33cdad 100644
--- a/include/asm-m68k/openprom.h
+++ b/include/asm-m68k/openprom.h
@@ -1,4 +1,3 @@
-/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */
 #ifndef __SPARC_OPENPROM_H
 #define __SPARC_OPENPROM_H
 
diff --git a/include/asm-m68k/oplib.h b/include/asm-m68k/oplib.h
index 06caa2d..f082d03 100644
--- a/include/asm-m68k/oplib.h
+++ b/include/asm-m68k/oplib.h
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.12 1996/10/31 06:29:13 davem Exp $
+/*
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -19,7 +19,6 @@
 	PROM_V2,      /* sun4c and early sun4m V2 prom */
 	PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
 	PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
-        PROM_AP1000,  /* actually no prom at all */
 };
 
 extern enum prom_major_version prom_vers;
diff --git a/include/asm-m68k/sbus.h b/include/asm-m68k/sbus.h
index 3b25c00..bfe3ba1 100644
--- a/include/asm-m68k/sbus.h
+++ b/include/asm-m68k/sbus.h
@@ -12,11 +12,6 @@
 	} reg_addrs[1];
 };
 
-extern void *sparc_alloc_io (u32, void *, int, char *, u32, int);
-#define sparc_alloc_io(a,b,c,d,e,f)	(a)
-
-#define ARCH_SUN4  0
-
 /* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */
 /* No SBUS on the Sun3, kludge -- sam */
 
diff --git a/include/asm-m68k/sun3-head.h b/include/asm-m68k/sun3-head.h
index e74f384..05af2f1 100644
--- a/include/asm-m68k/sun3-head.h
+++ b/include/asm-m68k/sun3-head.h
@@ -1,4 +1,3 @@
-/* $Id: head.h,v 1.32 1996/12/04 00:12:48 ecd Exp $ */
 #ifndef __SUN3_HEAD_H
 #define __SUN3_HEAD_H
 
diff --git a/include/asm-m68k/tlbflush.h b/include/asm-m68k/tlbflush.h
index 17707ec..acb6bf2 100644
--- a/include/asm-m68k/tlbflush.h
+++ b/include/asm-m68k/tlbflush.h
@@ -16,7 +16,7 @@
 				     ".chip 68k"
 				     : : "a" (addr));
 		set_fs(old_fs);
-	} else
+	} else if (CPU_IS_020_OR_030)
 		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
 }
 
@@ -29,7 +29,7 @@
 		__asm__ __volatile__(".chip 68040\n\t"
 				     "pflushan\n\t"
 				     ".chip 68k");
-	else
+	else if (CPU_IS_020_OR_030)
 		__asm__ __volatile__("pflush #0,#4");
 }
 
@@ -45,7 +45,7 @@
 {
 	if (CPU_IS_040_OR_060)
 		__flush_tlb040_one(addr);
-	else
+	else if (CPU_IS_020_OR_030)
 		__asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
 }
 
@@ -60,7 +60,7 @@
 		__asm__ __volatile__(".chip 68040\n\t"
 				     "pflusha\n\t"
 				     ".chip 68k");
-	else
+	else if (CPU_IS_020_OR_030)
 		__asm__ __volatile__("pflusha");
 }
 
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index 9a7274b..49df8c4 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -82,7 +82,7 @@
 		"2:	b	1b					\n"
 		"	.previous					\n"
 		: "=&r" (temp), "=m" (*m)
-		: "i" (bit), "m" (*m), "r" (~0));
+		: "ir" (bit), "m" (*m), "r" (~0));
 #endif /* CONFIG_CPU_MIPSR2 */
 	} else if (cpu_has_llsc) {
 		__asm__ __volatile__(
@@ -147,7 +147,7 @@
 		"2:	b	1b					\n"
 		"	.previous					\n"
 		: "=&r" (temp), "=m" (*m)
-		: "i" (bit), "m" (*m));
+		: "ir" (bit), "m" (*m));
 #endif /* CONFIG_CPU_MIPSR2 */
 	} else if (cpu_has_llsc) {
 		__asm__ __volatile__(
@@ -428,7 +428,7 @@
 		"2:	b	1b					\n"
 		"	.previous					\n"
 		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "i" (bit), "m" (*m)
+		: "ir" (bit), "m" (*m)
 		: "memory");
 #endif
 	} else if (cpu_has_llsc) {
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index d39e143..610fe3a 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -51,6 +51,12 @@
 #define MACH_MSP7120_FPGA       5	/* PMC-Sierra MSP7120 Emulation */
 #define MACH_MSP_OTHER        255	/* PMC-Sierra unknown board type */
 
+/*
+ * Valid machtype for group Mikrotik
+ */
+#define	MACH_MIKROTIK_RB532	0	/* Mikrotik RouterBoard 532 	*/
+#define MACH_MIKROTIK_RB532A	1	/* Mikrotik RouterBoard 532A 	*/
+
 #define CL_SIZE			COMMAND_LINE_SIZE
 
 extern char *system_type;
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
index e59d4c0..8a3ef24 100644
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -35,6 +35,8 @@
 extern asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc);
 
 extern void fpu_emulator_init_fpu(void);
+extern int fpu_emulator_save_context(struct sigcontext __user *sc);
+extern int fpu_emulator_restore_context(struct sigcontext __user *sc);
 extern void _init_fpu(void);
 extern void _save_fp(struct task_struct *);
 extern void _restore_fp(struct task_struct *);
diff --git a/include/asm-mips/mach-rc32434/cpu-feature-overrides.h b/include/asm-mips/mach-rc32434/cpu-feature-overrides.h
new file mode 100644
index 0000000..f3bc7ef
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/cpu-feature-overrides.h
@@ -0,0 +1,81 @@
+/*
+ *  IDT RC32434 specific CPU feature overrides
+ *
+ *  Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  This file was derived from: include/asm-mips/cpu-features.h
+ *	Copyright (C) 2003, 2004 Ralf Baechle
+ *	Copyright (C) 2004 Maciej W. Rozycki
+ *
+ *  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., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+#ifndef __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * The IDT RC32434 SOC has a built-in MIPS 4Kc core.
+ */
+#define cpu_has_tlb			1
+#define cpu_has_4kex			1
+#define cpu_has_3k_cache		0
+#define cpu_has_4k_cache		1
+#define cpu_has_tx39_cache		0
+#define cpu_has_sb1_cache		0
+#define cpu_has_fpu			0
+#define cpu_has_32fpr			0
+#define cpu_has_counter			1
+#define cpu_has_watch			1
+#define cpu_has_divec			1
+#define cpu_has_vce			0
+#define cpu_has_cache_cdex_p		0
+#define cpu_has_cache_cdex_s		0
+#define cpu_has_prefetch		1
+#define cpu_has_mcheck			1
+#define cpu_has_ejtag			1
+#define cpu_has_llsc			1
+
+#define cpu_has_mips16			0
+#define cpu_has_mdmx			0
+#define cpu_has_mips3d			0
+#define cpu_has_smartmips		0
+
+#define cpu_has_vtag_icache		0
+/* #define cpu_has_dc_aliases		? */
+/* #define cpu_has_ic_fills_f_dc	? */
+/* #define cpu_has_pindexed_dcache	? */
+
+/* #define cpu_icache_snoops_remote_store	? */
+
+#define cpu_has_mips32r1		1
+#define cpu_has_mips32r2		0
+#define cpu_has_mips64r1		0
+#define cpu_has_mips64r2		0
+
+#define cpu_has_dsp			0
+#define cpu_has_mipsmt			0
+
+/* #define cpu_has_nofpuex		? */
+#define cpu_has_64bits			0
+#define cpu_has_64bit_zero_reg		0
+#define cpu_has_64bit_gp_regs		0
+#define cpu_has_64bit_addresses		0
+
+#define cpu_has_inclusive_pcaches	0
+
+#define cpu_dcache_line_size()		16
+#define cpu_icache_line_size()		16
+
+#endif /* __ASM_MACH_RC32434_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-rc32434/ddr.h b/include/asm-mips/mach-rc32434/ddr.h
new file mode 100644
index 0000000..291e2cf
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/ddr.h
@@ -0,0 +1,141 @@
+/*
+ *  Definitions for the DDR registers
+ *
+ *  Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 _ASM_RC32434_DDR_H_
+#define _ASM_RC32434_DDR_H_
+
+#include <asm/mach-rc32434/rb.h>
+
+/* DDR register structure */
+struct ddr_ram {
+	u32 ddrbase;
+	u32 ddrmask;
+	u32 res1;
+	u32 res2;
+	u32 ddrc;
+	u32 ddrabase;
+	u32 ddramask;
+	u32 ddramap;
+	u32 ddrcust;
+	u32 ddrrdc;
+	u32 ddrspare;
+};
+
+#define DDR0_PHYS_ADDR		0x18018000
+
+/* DDR banks masks */
+#define DDR_MASK		0xffff0000
+#define DDR0_BASE_MSK		DDR_MASK
+#define DDR1_BASE_MSK		DDR_MASK
+
+/* DDR bank0 registers */
+#define RC32434_DDR0_ATA_BIT		5
+#define RC32434_DDR0_ATA_MSK		0x000000E0
+#define RC32434_DDR0_DBW_BIT		8
+#define RC32434_DDR0_DBW_MSK		0x00000100
+#define RC32434_DDR0_WR_BIT		9
+#define RC32434_DDR0_WR_MSK		0x00000600
+#define RC32434_DDR0_PS_BIT		11
+#define RC32434_DDR0_PS_MSK		0x00001800
+#define RC32434_DDR0_DTYPE_BIT		13
+#define RC32434_DDR0_DTYPE_MSK		0x0000e000
+#define RC32434_DDR0_RFC_BIT		16
+#define RC32434_DDR0_RFC_MSK		0x000f0000
+#define RC32434_DDR0_RP_BIT		20
+#define RC32434_DDR0_RP_MSK		0x00300000
+#define RC32434_DDR0_AP_BIT		22
+#define RC32434_DDR0_AP_MSK		0x00400000
+#define RC32434_DDR0_RCD_BIT		23
+#define RC32434_DDR0_RCD_MSK		0x01800000
+#define RC32434_DDR0_CL_BIT		25
+#define RC32434_DDR0_CL_MSK		0x06000000
+#define RC32434_DDR0_DBM_BIT		27
+#define RC32434_DDR0_DBM_MSK		0x08000000
+#define RC32434_DDR0_SDS_BIT		28
+#define RC32434_DDR0_SDS_MSK		0x10000000
+#define RC32434_DDR0_ATP_BIT		29
+#define RC32434_DDR0_ATP_MSK		0x60000000
+#define RC32434_DDR0_RE_BIT		31
+#define RC32434_DDR0_RE_MSK		0x80000000
+
+/* DDR bank C registers */
+#define RC32434_DDRC_MSK(x)		BIT_TO_MASK(x)
+#define RC32434_DDRC_CES_BIT		0
+#define RC32434_DDRC_ACE_BIT		1
+
+/* Custom DDR bank registers */
+#define RC32434_DCST_MSK(x)		BIT_TO_MASK(x)
+#define RC32434_DCST_CS_BIT		0
+#define RC32434_DCST_CS_MSK		0x00000003
+#define RC32434_DCST_WE_BIT		2
+#define RC32434_DCST_RAS_BIT		3
+#define RC32434_DCST_CAS_BIT		4
+#define RC32434_DSCT_CKE_BIT		5
+#define RC32434_DSCT_BA_BIT		6
+#define RC32434_DSCT_BA_MSK		0x000000c0
+
+/* DDR QSC registers */
+#define RC32434_QSC_DM_BIT		0
+#define RC32434_QSC_DM_MSK		0x00000003
+#define RC32434_QSC_DQSBS_BIT		2
+#define RC32434_QSC_DQSBS_MSK		0x000000fc
+#define RC32434_QSC_DB_BIT		8
+#define RC32434_QSC_DB_MSK		0x00000100
+#define RC32434_QSC_DBSP_BIT		9
+#define RC32434_QSC_DBSP_MSK		0x01fffe00
+#define RC32434_QSC_BDP_BIT		25
+#define RC32434_QSC_BDP_MSK		0x7e000000
+
+/* DDR LLC registers */
+#define RC32434_LLC_EAO_BIT		0
+#define RC32434_LLC_EAO_MSK		0x00000001
+#define RC32434_LLC_EO_BIT		1
+#define RC32434_LLC_EO_MSK		0x0000003e
+#define RC32434_LLC_FS_BIT		6
+#define RC32434_LLC_FS_MSK		0x000000c0
+#define RC32434_LLC_AS_BIT		8
+#define RC32434_LLC_AS_MSK		0x00000700
+#define RC32434_LLC_SP_BIT		11
+#define RC32434_LLC_SP_MSK		0x001ff800
+
+/* DDR LLFC registers */
+#define RC32434_LLFC_MSK(x)		BIT_TO_MASK(x)
+#define RC32434_LLFC_MEN_BIT		0
+#define RC32434_LLFC_EAN_BIT		1
+#define RC32434_LLFC_FF_BIT		2
+
+/* DDR DLLTA registers */
+#define RC32434_DLLTA_ADDR_BIT		2
+#define RC32434_DLLTA_ADDR_MSK		0xfffffffc
+
+/* DDR DLLED registers */
+#define RC32434_DLLED_MSK(x)		BIT_TO_MASK(x)
+#define RC32434_DLLED_DBE_BIT		0
+#define RC32434_DLLED_DTE_BIT		1
+
+#endif  /* _ASM_RC32434_DDR_H_ */
diff --git a/include/asm-mips/mach-rc32434/dma.h b/include/asm-mips/mach-rc32434/dma.h
new file mode 100644
index 0000000..5f898b5
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/dma.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2002 Integrated Device Technology, Inc.
+ *		All rights reserved.
+ *
+ * DMA register definition.
+ *
+ * Author : ryan.holmQVist@idt.com
+ * Date   : 20011005
+ */
+
+#ifndef __ASM_RC32434_DMA_H
+#define __ASM_RC32434_DMA_H
+
+#include <asm/mach-rc32434/rb.h>
+
+#define DMA0_BASE_ADDR			0x18040000
+
+/*
+ * DMA descriptor (in physical memory).
+ */
+
+struct dma_desc {
+	u32 control;			/* Control. use DMAD_* */
+	u32 ca;				/* Current Address. */
+	u32 devcs;			/* Device control and status. */
+	u32 link;			/* Next descriptor in chain. */
+};
+
+#define DMA_DESC_SIZ			sizeof(struct dma_desc)
+#define DMA_DESC_COUNT_BIT		0
+#define DMA_DESC_COUNT_MSK		0x0003ffff
+#define DMA_DESC_DS_BIT			20
+#define DMA_DESC_DS_MSK			0x00300000
+
+#define DMA_DESC_DEV_CMD_BIT		22
+#define DMA_DESC_DEV_CMD_MSK		0x01c00000
+
+/* DMA command sizes */
+#define DMA_DESC_DEV_CMD_BYTE		0
+#define DMA_DESC_DEV_CMD_HLF_WD		1
+#define DMA_DESC_DEV_CMD_WORD		2
+#define DMA_DESC_DEV_CMD_2WORDS		3
+#define DMA_DESC_DEV_CMD_4WORDS		4
+#define DMA_DESC_DEV_CMD_6WORDS		5
+#define DMA_DESC_DEV_CMD_8WORDS		6
+#define DMA_DESC_DEV_CMD_16WORDS	7
+
+/* DMA descriptors interrupts */
+#define DMA_DESC_COF			(1 << 25) /* Chain on finished */
+#define DMA_DESC_COD			(1 << 26) /* Chain on done */
+#define DMA_DESC_IOF			(1 << 27) /* Interrupt on finished */
+#define DMA_DESC_IOD			(1 << 28) /* Interrupt on done */
+#define DMA_DESC_TERM			(1 << 29) /* Terminated */
+#define DMA_DESC_DONE			(1 << 30) /* Done */
+#define DMA_DESC_FINI			(1 << 31) /* Finished */
+
+/*
+ * DMA register (within Internal Register Map).
+ */
+
+struct dma_reg {
+	u32 dmac;		/* Control. */
+	u32 dmas;		/* Status. */
+	u32 dmasm;		/* Mask. */
+	u32 dmadptr;		/* Descriptor pointer. */
+	u32 dmandptr;		/* Next descriptor pointer. */
+};
+
+/* DMA channels specific registers */
+#define DMA_CHAN_RUN_BIT		(1 << 0)
+#define DMA_CHAN_DONE_BIT		(1 << 1)
+#define DMA_CHAN_MODE_BIT		(1 << 2)
+#define DMA_CHAN_MODE_MSK		0x0000000c
+#define  DMA_CHAN_MODE_AUTO		0
+#define  DMA_CHAN_MODE_BURST		1
+#define  DMA_CHAN_MODE_XFRT		2
+#define  DMA_CHAN_MODE_RSVD		3
+#define DMA_CHAN_ACT_BIT		(1 << 4)
+
+/* DMA status registers */
+#define DMA_STAT_FINI			(1 << 0)
+#define DMA_STAT_DONE			(1 << 1)
+#define DMA_STAT_CHAIN			(1 << 2)
+#define DMA_STAT_ERR			(1 << 3)
+#define DMA_STAT_HALT			(1 << 4)
+
+/*
+ * DMA channel definitions
+ */
+
+#define DMA_CHAN_ETH_RCV		0
+#define DMA_CHAN_ETH_XMT		1
+#define DMA_CHAN_MEM_TO_FIFO		2
+#define DMA_CHAN_FIFO_TO_MEM		3
+#define DMA_CHAN_PCI_TO_MEM		4
+#define DMA_CHAN_MEM_TO_PCI		5
+#define DMA_CHAN_COUNT			6
+
+struct dma_channel {
+	struct dma_reg ch[DMA_CHAN_COUNT];
+};
+
+#endif  /* __ASM_RC32434_DMA_H */
diff --git a/include/asm-mips/mach-rc32434/dma_v.h b/include/asm-mips/mach-rc32434/dma_v.h
new file mode 100644
index 0000000..173a9f9
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/dma_v.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002 Integrated Device Technology, Inc.
+ *		All rights reserved.
+ *
+ * DMA register definition.
+ *
+ * Author : ryan.holmQVist@idt.com
+ * Date   : 20011005
+ */
+
+#ifndef _ASM_RC32434_DMA_V_H_
+#define _ASM_RC32434_DMA_V_H_
+
+#include  <asm/mach-rc32434/dma.h>
+#include  <asm/mach-rc32434/rc32434.h>
+
+#define DMA_CHAN_OFFSET		0x14
+#define IS_DMA_USED(X)		(((X) & \
+				(DMA_DESC_FINI | DMA_DESC_DONE | DMA_DESC_TERM)) \
+				!= 0)
+#define DMA_COUNT(count)	((count) & DMA_DESC_COUNT_MSK)
+
+#define DMA_HALT_TIMEOUT	500
+
+static inline int rc32434_halt_dma(struct dma_reg *ch)
+{
+	int timeout = 1;
+	if (__raw_readl(&ch->dmac) & DMA_CHAN_RUN_BIT) {
+		__raw_writel(0, &ch->dmac);
+		for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
+			if (__raw_readl(&ch->dmas) & DMA_STAT_HALT) {
+				__raw_writel(0, &ch->dmas);
+				break;
+			}
+		}
+	}
+
+	return timeout ? 0 : 1;
+}
+
+static inline void rc32434_start_dma(struct dma_reg *ch, u32 dma_addr)
+{
+	__raw_writel(0, &ch->dmandptr);
+	__raw_writel(dma_addr, &ch->dmadptr);
+}
+
+static inline void rc32434_chain_dma(struct dma_reg *ch, u32 dma_addr)
+{
+	__raw_writel(dma_addr, &ch->dmandptr);
+}
+
+#endif  /* _ASM_RC32434_DMA_V_H_ */
diff --git a/include/asm-mips/mach-rc32434/eth.h b/include/asm-mips/mach-rc32434/eth.h
new file mode 100644
index 0000000..a25cbc5
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/eth.h
@@ -0,0 +1,220 @@
+/*
+ *  Definitions for the Ethernet registers
+ *
+ *  Copyright 2002 Allend Stichter <allen.stichter@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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	__ASM_RC32434_ETH_H
+#define	__ASM_RC32434_ETH_H
+
+
+#define ETH0_BASE_ADDR		0x18060000
+
+struct eth_regs {
+	u32 ethintfc;
+	u32 ethfifott;
+	u32 etharc;
+	u32 ethhash0;
+	u32 ethhash1;
+	u32 ethu0[4];		/* Reserved. */
+	u32 ethpfs;
+	u32 ethmcp;
+	u32 eth_u1[10];		/* Reserved. */
+	u32 ethspare;
+	u32 eth_u2[42];		/* Reserved. */
+	u32 ethsal0;
+	u32 ethsah0;
+	u32 ethsal1;
+	u32 ethsah1;
+	u32 ethsal2;
+	u32 ethsah2;
+	u32 ethsal3;
+	u32 ethsah3;
+	u32 ethrbc;
+	u32 ethrpc;
+	u32 ethrupc;
+	u32 ethrfc;
+	u32 ethtbc;
+	u32 ethgpf;
+	u32 eth_u9[50];		/* Reserved. */
+	u32 ethmac1;
+	u32 ethmac2;
+	u32 ethipgt;
+	u32 ethipgr;
+	u32 ethclrt;
+	u32 ethmaxf;
+	u32 eth_u10;		/* Reserved. */
+	u32 ethmtest;
+	u32 miimcfg;
+	u32 miimcmd;
+	u32 miimaddr;
+	u32 miimwtd;
+	u32 miimrdd;
+	u32 miimind;
+	u32 eth_u11;		/* Reserved. */
+	u32 eth_u12;		/* Reserved. */
+	u32 ethcfsa0;
+	u32 ethcfsa1;
+	u32 ethcfsa2;
+};
+
+/* Ethernet interrupt registers */
+#define ETH_INT_FC_EN		(1 << 0)
+#define ETH_INT_FC_ITS		(1 << 1)
+#define ETH_INT_FC_RIP		(1 << 2)
+#define ETH_INT_FC_JAM		(1 << 3)
+#define ETH_INT_FC_OVR		(1 << 4)
+#define ETH_INT_FC_UND		(1 << 5)
+#define ETH_INT_FC_IOC		0x000000c0
+
+/* Ethernet FIFO registers */
+#define ETH_FIFI_TT_TTH_BIT	0
+#define ETH_FIFO_TT_TTH		0x0000007f
+
+/* Ethernet ARC/multicast registers */
+#define ETH_ARC_PRO		(1 << 0)
+#define ETH_ARC_AM		(1 << 1)
+#define ETH_ARC_AFM		(1 << 2)
+#define ETH_ARC_AB		(1 << 3)
+
+/* Ethernet SAL registers */
+#define ETH_SAL_BYTE_5		0x000000ff
+#define ETH_SAL_BYTE_4		0x0000ff00
+#define ETH_SAL_BYTE_3		0x00ff0000
+#define ETH_SAL_BYTE_2		0xff000000
+
+/* Ethernet SAH registers */
+#define ETH_SAH_BYTE1		0x000000ff
+#define ETH_SAH_BYTE0		0x0000ff00
+
+/* Ethernet GPF register */
+#define ETH_GPF_PTV		0x0000ffff
+
+/* Ethernet PFG register */
+#define ETH_PFS_PFD		(1 << 0)
+
+/* Ethernet CFSA[0-3] registers */
+#define ETH_CFSA0_CFSA4		0x000000ff
+#define ETH_CFSA0_CFSA5		0x0000ff00
+#define ETH_CFSA1_CFSA2		0x000000ff
+#define ETH_CFSA1_CFSA3		0x0000ff00
+#define ETH_CFSA1_CFSA0		0x000000ff
+#define ETH_CFSA1_CFSA1		0x0000ff00
+
+/* Ethernet MAC1 registers */
+#define ETH_MAC1_RE		(1 << 0)
+#define ETH_MAC1_PAF		(1 << 1)
+#define ETH_MAC1_RFC		(1 << 2)
+#define ETH_MAC1_TFC		(1 << 3)
+#define ETH_MAC1_LB		(1 << 4)
+#define ETH_MAC1_MR		(1 << 31)
+
+/* Ethernet MAC2 registers */
+#define ETH_MAC2_FD		(1 << 0)
+#define ETH_MAC2_FLC		(1 << 1)
+#define ETH_MAC2_HFE		(1 << 2)
+#define ETH_MAC2_DC		(1 << 3)
+#define ETH_MAC2_CEN		(1 << 4)
+#define ETH_MAC2_PE		(1 << 5)
+#define ETH_MAC2_VPE		(1 << 6)
+#define ETH_MAC2_APE		(1 << 7)
+#define ETH_MAC2_PPE		(1 << 8)
+#define ETH_MAC2_LPE		(1 << 9)
+#define ETH_MAC2_NB		(1 << 12)
+#define ETH_MAC2_BP		(1 << 13)
+#define ETH_MAC2_ED		(1 << 14)
+
+/* Ethernet IPGT register */
+#define ETH_IPGT		0x0000007f
+
+/* Ethernet IPGR registers */
+#define ETH_IPGR_IPGR2		0x0000007f
+#define ETH_IPGR_IPGR1		0x00007f00
+
+/* Ethernet CLRT registers */
+#define ETH_CLRT_MAX_RET	0x0000000f
+#define ETH_CLRT_COL_WIN	0x00003f00
+
+/* Ethernet MAXF register */
+#define ETH_MAXF		0x0000ffff
+
+/* Ethernet test registers */
+#define ETH_TEST_REG		(1 << 2)
+#define ETH_MCP_DIV		0x000000ff
+
+/* MII registers */
+#define ETH_MII_CFG_RSVD	0x0000000c
+#define ETH_MII_CMD_RD		(1 << 0)
+#define ETH_MII_CMD_SCN		(1 << 1)
+#define ETH_MII_REG_ADDR	0x0000001f
+#define ETH_MII_PHY_ADDR	0x00001f00
+#define ETH_MII_WTD_DATA	0x0000ffff
+#define ETH_MII_RDD_DATA	0x0000ffff
+#define ETH_MII_IND_BSY		(1 << 0)
+#define ETH_MII_IND_SCN		(1 << 1)
+#define ETH_MII_IND_NV		(1 << 2)
+
+/*
+ * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors.
+ */
+
+#define ETH_RX_FD		(1 << 0)
+#define ETH_RX_LD		(1 << 1)
+#define ETH_RX_ROK		(1 << 2)
+#define ETH_RX_FM		(1 << 3)
+#define ETH_RX_MP		(1 << 4)
+#define ETH_RX_BP		(1 << 5)
+#define ETH_RX_VLT		(1 << 6)
+#define ETH_RX_CF		(1 << 7)
+#define ETH_RX_OVR		(1 << 8)
+#define ETH_RX_CRC		(1 << 9)
+#define ETH_RX_CV		(1 << 10)
+#define ETH_RX_DB		(1 << 11)
+#define ETH_RX_LE		(1 << 12)
+#define ETH_RX_LOR		(1 << 13)
+#define ETH_RX_CES		(1 << 14)
+#define ETH_RX_LEN_BIT		16
+#define ETH_RX_LEN		0xffff0000
+
+#define ETH_TX_FD		(1 << 0)
+#define ETH_TX_LD		(1 << 1)
+#define ETH_TX_OEN		(1 << 2)
+#define ETH_TX_PEN		(1 << 3)
+#define ETH_TX_CEN		(1 << 4)
+#define ETH_TX_HEN		(1 << 5)
+#define ETH_TX_TOK		(1 << 6)
+#define ETH_TX_MP		(1 << 7)
+#define ETH_TX_BP		(1 << 8)
+#define ETH_TX_UND		(1 << 9)
+#define ETH_TX_OF		(1 << 10)
+#define ETH_TX_ED		(1 << 11)
+#define ETH_TX_EC		(1 << 12)
+#define ETH_TX_LC		(1 << 13)
+#define ETH_TX_TD		(1 << 14)
+#define ETH_TX_CRC		(1 << 15)
+#define ETH_TX_LE		(1 << 16)
+#define ETH_TX_CC		0x001E0000
+
+#endif  /* __ASM_RC32434_ETH_H */
diff --git a/include/asm-mips/mach-rc32434/gpio.h b/include/asm-mips/mach-rc32434/gpio.h
new file mode 100644
index 0000000..f946f5f
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/gpio.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2002 Integrated Device Technology, Inc.
+ *	All rights reserved.
+ *
+ * GPIO register definition.
+ *
+ * Author : ryan.holmQVist@idt.com
+ * Date   : 20011005
+ * Copyright (C) 2001, 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ */
+
+#ifndef _RC32434_GPIO_H_
+#define _RC32434_GPIO_H_
+
+#include <linux/types.h>
+
+struct rb532_gpio_reg {
+	u32   gpiofunc;   /* GPIO Function Register
+			   * gpiofunc[x]==0 bit = gpio
+			   * func[x]==1  bit = altfunc
+			   */
+	u32   gpiocfg;	  /* GPIO Configuration Register
+			   * gpiocfg[x]==0 bit = input
+			   * gpiocfg[x]==1 bit = output
+			   */
+	u32   gpiod;	  /* GPIO Data Register
+			   * gpiod[x] read/write gpio pinX status
+			   */
+	u32   gpioilevel; /* GPIO Interrupt Status Register
+			   * interrupt level (see gpioistat)
+			   */
+	u32   gpioistat;  /* Gpio Interrupt Status Register
+			   * istat[x] = (gpiod[x] == level[x])
+			   * cleared in ISR (STICKY bits)
+			   */
+	u32   gpionmien;  /* GPIO Non-maskable Interrupt Enable Register */
+};
+
+/* UART GPIO signals */
+#define RC32434_UART0_SOUT	(1 << 0)
+#define RC32434_UART0_SIN	(1 << 1)
+#define RC32434_UART0_RTS	(1 << 2)
+#define RC32434_UART0_CTS	(1 << 3)
+
+/* M & P bus GPIO signals */
+#define RC32434_MP_BIT_22	(1 << 4)
+#define RC32434_MP_BIT_23	(1 << 5)
+#define RC32434_MP_BIT_24	(1 << 6)
+#define RC32434_MP_BIT_25	(1 << 7)
+
+/* CPU GPIO signals */
+#define RC32434_CPU_GPIO	(1 << 8)
+
+/* Reserved GPIO signals */
+#define RC32434_AF_SPARE_6	(1 << 9)
+#define RC32434_AF_SPARE_4	(1 << 10)
+#define RC32434_AF_SPARE_3	(1 << 11)
+#define RC32434_AF_SPARE_2	(1 << 12)
+
+/* PCI messaging unit */
+#define RC32434_PCI_MSU_GPIO	(1 << 13)
+
+
+extern void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val);
+extern unsigned get_434_reg(unsigned reg_offs);
+extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask);
+extern unsigned char get_latch_u5(void);
+
+extern int rb532_gpio_get_value(unsigned gpio);
+extern void rb532_gpio_set_value(unsigned gpio, int value);
+extern int rb532_gpio_direction_input(unsigned gpio);
+extern int rb532_gpio_direction_output(unsigned gpio, int value);
+extern void rb532_gpio_set_int_level(unsigned gpio, int value);
+extern int rb532_gpio_get_int_level(unsigned gpio);
+extern void rb532_gpio_set_int_status(unsigned gpio, int value);
+extern int rb532_gpio_get_int_status(unsigned gpio);
+
+
+/* Wrappers for the arch-neutral GPIO API */
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+	/* Not yet implemented */
+	return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+	/* Not yet implemented */
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+	return rb532_gpio_direction_input(gpio);
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+	return rb532_gpio_direction_output(gpio, value);
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return rb532_gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	rb532_gpio_set_value(gpio, value);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return gpio;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return irq;
+}
+
+/* For cansleep */
+#include <asm-generic/gpio.h>
+
+#endif /* _RC32434_GPIO_H_ */
diff --git a/include/asm-mips/mach-rc32434/integ.h b/include/asm-mips/mach-rc32434/integ.h
new file mode 100644
index 0000000..fa65bc3
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/integ.h
@@ -0,0 +1,59 @@
+/*
+ *  Definitions for the Watchdog registers
+ *
+ *  Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 __RC32434_INTEG_H__
+#define __RC32434_INTEG_H__
+
+#include <asm/mach-rc32434/rb.h>
+
+#define INTEG0_BASE_ADDR	0x18030030
+
+struct integ {
+	u32 errcs;			/* sticky use ERRCS_ */
+	u32 wtcount;			/* Watchdog timer count reg. */
+	u32 wtcompare;			/* Watchdog timer timeout value. */
+	u32 wtc;			/* Watchdog timer control. use WTC_ */
+};
+
+/* Error counters */
+#define RC32434_ERR_WTO		0
+#define RC32434_ERR_WNE		1
+#define RC32434_ERR_UCW		2
+#define RC32434_ERR_UCR		3
+#define RC32434_ERR_UPW		4
+#define RC32434_ERR_UPR		5
+#define RC32434_ERR_UDW		6
+#define RC32434_ERR_UDR		7
+#define RC32434_ERR_SAE		8
+#define RC32434_ERR_WRE		9
+
+/* Watchdog control bits */
+#define RC32434_WTC_EN		0
+#define RC32434_WTC_TO		1
+
+#endif	/* __RC32434_INTEG_H__ */
diff --git a/include/asm-mips/mach-rc32434/irq.h b/include/asm-mips/mach-rc32434/irq.h
new file mode 100644
index 0000000..cb9e472
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/irq.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_RC32434_IRQ_H
+#define __ASM_RC32434_IRQ_H
+
+#define NR_IRQS	256
+
+#include <asm/mach-generic/irq.h>
+
+#endif  /* __ASM_RC32434_IRQ_H */
diff --git a/include/asm-mips/mach-rc32434/pci.h b/include/asm-mips/mach-rc32434/pci.h
new file mode 100644
index 0000000..410638f
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/pci.h
@@ -0,0 +1,481 @@
+/*
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ * Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *
+ * Initial Release
+ */
+
+#ifndef _ASM_RC32434_PCI_H_
+#define _ASM_RC32434_PCI_H_
+
+#define epld_mask ((volatile unsigned char *)0xB900000d)
+
+#define PCI0_BASE_ADDR		0x18080000
+#define PCI_LBA_COUNT		4
+
+struct pci_map {
+	u32 address;		/* Address. */
+	u32 control;		/* Control. */
+	u32 mapping;		/* mapping. */
+};
+
+struct pci_reg {
+	u32 pcic;
+	u32 pcis;
+	u32 pcism;
+	u32 pcicfga;
+	u32 pcicfgd;
+	volatile struct pci_map pcilba[PCI_LBA_COUNT];
+	u32 pcidac;
+	u32 pcidas;
+	u32 pcidasm;
+	u32 pcidad;
+	u32 pcidma8c;
+	u32 pcidma9c;
+	u32 pcitc;
+};
+
+#define PCI_MSU_COUNT		2
+
+struct pci_msu {
+	u32 pciim[PCI_MSU_COUNT];
+	u32 pciom[PCI_MSU_COUNT];
+	u32 pciid;
+	u32 pciiic;
+	u32 pciiim;
+	u32 pciiod;
+	u32 pciioic;
+	u32 pciioim;
+};
+
+/*
+ * PCI Control Register
+ */
+
+#define PCI_CTL_EN		(1 << 0)
+#define PCI_CTL_TNR		(1 << 1)
+#define PCI_CTL_SCE		(1 << 2)
+#define PCI_CTL_IEN		(1 << 3)
+#define PCI_CTL_AAA		(1 << 4)
+#define PCI_CTL_EAP		(1 << 5)
+#define PCI_CTL_PCIM_BIT	6
+#define PCI_CTL_PCIM		0x000001c0
+
+#define PCI_CTL_PCIM_DIS	0
+#define PCI_CTL_PCIM_TNR	1 /* Satellite - target not ready */
+#define PCI_CTL_PCIM_SUS	2 /* Satellite - suspended CPU. */
+#define PCI_CTL_PCIM_EXT	3 /* Host - external arbiter. */
+#define PCI_CTL PCIM_PRIO	4 /* Host - fixed priority arb. */
+#define PCI_CTL_PCIM_RR		5 /* Host - round robin priority. */
+#define PCI_CTL_PCIM_RSVD6	6
+#define PCI_CTL_PCIM_RSVD7	7
+
+#define PCI_CTL_IGM		(1 << 9)
+
+/*
+ * PCI Status Register
+ */
+
+#define PCI_STAT_EED		(1 << 0)
+#define PCI_STAT_WR		(1 << 1)
+#define PCI_STAT_NMI		(1 << 2)
+#define PCI_STAT_II		(1 << 3)
+#define PCI_STAT_CWE		(1 << 4)
+#define PCI_STAT_CRE		(1 << 5)
+#define PCI_STAT_MDPE		(1 << 6)
+#define PCI_STAT_STA		(1 << 7)
+#define PCI_STAT_RTA		(1 << 8)
+#define PCI_STAT_RMA		(1 << 9)
+#define PCI_STAT_SSE		(1 << 10)
+#define PCI_STAT_OSE		(1 << 11)
+#define PCI_STAT_PE		(1 << 12)
+#define PCI_STAT_TAE		(1 << 13)
+#define PCI_STAT_RLE		(1 << 14)
+#define PCI_STAT_BME		(1 << 15)
+#define PCI_STAT_PRD		(1 << 16)
+#define PCI_STAT_RIP		(1 << 17)
+
+/*
+ * PCI Status Mask Register
+ */
+
+#define PCI_STATM_EED		PCI_STAT_EED
+#define PCI_STATM_WR		PCI_STAT_WR
+#define PCI_STATM_NMI		PCI_STAT_NMI
+#define PCI_STATM_II		PCI_STAT_II
+#define PCI_STATM_CWE		PCI_STAT_CWE
+#define PCI_STATM_CRE		PCI_STAT_CRE
+#define PCI_STATM_MDPE		PCI_STAT_MDPE
+#define PCI_STATM_STA		PCI_STAT_STA
+#define PCI_STATM_RTA		PCI_STAT_RTA
+#define PCI_STATM_RMA		PCI_STAT_RMA
+#define PCI_STATM_SSE		PCI_STAT_SSE
+#define PCI_STATM_OSE		PCI_STAT_OSE
+#define PCI_STATM_PE		PCI_STAT_PE
+#define PCI_STATM_TAE		PCI_STAT_TAE
+#define PCI_STATM_RLE		PCI_STAT_RLE
+#define PCI_STATM_BME		PCI_STAT_BME
+#define PCI_STATM_PRD		PCI_STAT_PRD
+#define PCI_STATM_RIP		PCI_STAT_RIP
+
+/*
+ * PCI Configuration Address Register
+ */
+#define PCI_CFGA_REG_BIT	2
+#define PCI_CFGA_REG		0x000000fc
+#define	 PCI_CFGA_REG_ID	(0x00 >> 2)	/* use PCFGID */
+#define	 PCI_CFGA_REG_04	(0x04 >> 2)	/* use PCFG04_ */
+#define	 PCI_CFGA_REG_08	(0x08 >> 2)	/* use PCFG08_ */
+#define	 PCI_CFGA_REG_0C	(0x0C >> 2)	/* use PCFG0C_ */
+#define	 PCI_CFGA_REG_PBA0	(0x10 >> 2)	/* use PCIPBA_ */
+#define	 PCI_CFGA_REG_PBA1	(0x14 >> 2)	/* use PCIPBA_ */
+#define	 PCI_CFGA_REG_PBA2	(0x18 >> 2)	/* use PCIPBA_ */
+#define	 PCI_CFGA_REG_PBA3	(0x1c >> 2)	/* use PCIPBA_ */
+#define	 PCI_CFGA_REG_SUBSYS	(0x2c >> 2)	/* use PCFGSS_ */
+#define  PCI_CFGA_REG_3C	(0x3C >> 2)	/* use PCFG3C_ */
+#define	 PCI_CFGA_REG_PBBA0C	(0x44 >> 2)	/* use PCIPBAC_ */
+#define  PCI_CFGA_REG_PBA0M	(0x48 >> 2)
+#define	 PCI_CFGA_REG_PBA1C	(0x4c >> 2)	/* use PCIPBAC_ */
+#define  PCI_CFGA_REG_PBA1M	(0x50 >> 2)
+#define	 PCI_CFGA_REG_PBA2C	(0x54 >> 2)	/* use PCIPBAC_ */
+#define	 PCI_CFGA_REG_PBA2M	(0x58 >> 2)
+#define	 PCI_CFGA_REG_PBA3C	(0x5c >> 2)	/* use PCIPBAC_ */
+#define	 PCI_CFGA_REG_PBA3M	(0x60 >> 2)
+#define	 PCI_CFGA_REG_PMGT	(0x64 >> 2)
+#define PCI_CFGA_FUNC_BIT	8
+#define PCI_CFGA_FUNC		0x00000700
+#define PCI_CFGA_DEV_BIT	11
+#define	PCI_CFGA_DEV		0x0000f800
+#define	PCI_CFGA_DEV_INTERN	0
+#define	PCI_CFGA_BUS_BIT	16
+#define PCI CFGA_BUS		0x00ff0000
+#define PCI_CFGA_BUS_TYPE0	0
+#define PCI_CFGA_EN		(1 << 31)
+
+/* PCI CFG04 commands */
+#define PCI_CFG04_CMD_IO_ENA	(1 << 0)
+#define PCI_CFG04_CMD_MEM_ENA	(1 << 1)
+#define PCI_CFG04_CMD_BM_ENA	(1 << 2)
+#define PCI_CFG04_CMD_MW_INV	(1 << 4)
+#define PCI_CFG04_CMD_PAR_ENA	(1 << 6)
+#define PCI_CFG04_CMD_SER_ENA	(1 << 8)
+#define PCI_CFG04_CMD_FAST_ENA	(1 << 9)
+
+/* PCI CFG04 status fields */
+#define PCI_CFG04_STAT_BIT	16
+#define PCI_CFG04_STAT		0xffff0000
+#define PCI_CFG04_STAT_66_MHZ	(1 << 21)
+#define PCI_CFG04_STAT_FBB	(1 << 23)
+#define PCI_CFG04_STAT_MDPE	(1 << 24)
+#define PCI_CFG04_STAT_DST	(1 << 25)
+#define PCI_CFG04_STAT_STA	(1 << 27)
+#define PCI_CFG04_STAT_RTA	(1 << 28)
+#define PCI_CFG04_STAT_RMA	(1 << 29)
+#define PCI_CFG04_STAT_SSE	(1 << 30)
+#define PCI_CFG04_STAT_PE	(1 << 31)
+
+#define PCI_PBA_MSI		(1 << 0)
+#define PCI_PBA_P		(1 << 2)
+
+/* PCI PBAC registers */
+#define PCI_PBAC_MSI		(1 << 0)
+#define PCI_PBAC_P		(1 << 1)
+#define PCI_PBAC_SIZE_BIT	2
+#define PCI_PBAC_SIZE		0x0000007c
+#define	PCI_PBAC_SB		(1 << 7)
+#define	PCI_PBAC_PP		(1 << 8)
+#define PCI_PBAC_MR_BIT		9
+#define PCI_PBAC_MR		0x00000600
+#define	 PCI_PBAC_MR_RD		0
+#define	 PCI_PBAC_MR_RD_LINE	1
+#define  PCI_PBAC_MR_RD_MULT	2
+#define PCI_PBAC_MRL		(1 << 11)
+#define PCI_PBAC_MRM		(1 << 12)
+#define PCI_PBAC_TRP		(1 << 13)
+
+#define PCI_CFG40_TRDY_TIM	0x000000ff
+#define PCI_CFG40_RET_LIM	0x0000ff00
+
+/*
+ * PCI Local Base Address [0|1|2|3] Register
+ */
+
+#define PCI_LBA_BADDR_BIT	0
+#define PCI_LBA_BADDR		0xffffff00
+
+/*
+ * PCI Local Base Address Control Register
+ */
+
+#define PCI_LBAC_MSI		(1 << 0)
+#define  PCI_LBAC_MSI_MEM	0
+#define  PCI_LBAC_MSI_IO	1
+#define PCI_LBAC_SIZE_BIT	2
+#define PCI_LBAC_SIZE		0x0000007c
+#define PCI_LBAC_SB		(1 << 7)
+#define PCI_LBAC_RT		(1 << 8)
+#define  PCI_LBAC_RT_NO_PREF	0
+#define  PCI_LBAC_RT_PREF	1
+
+/*
+ * PCI Local Base Address [0|1|2|3] Mapping Register
+ */
+#define PCI_LBAM_MADDR_BIT	8
+#define PCI_LBAM_MADDR		0xffffff00
+
+/*
+ * PCI Decoupled Access Control Register
+ */
+#define PCI_DAC_DEN		(1 << 0)
+
+/*
+ * PCI Decoupled Access Status Register
+ */
+#define PCI_DAS_D		(1 << 0)
+#define PCI_DAS_B		(1 << 1)
+#define PCI_DAS_E		(1 << 2)
+#define PCI_DAS_OFE		(1 << 3)
+#define PCI_DAS_OFF		(1 << 4)
+#define PCI_DAS_IFE		(1 << 5)
+#define PCI_DAS_IFF		(1 << 6)
+
+/*
+ * PCI DMA Channel 8 Configuration Register
+ */
+#define PCI_DMA8C_MBS_BIT	0
+#define PCI_DMA8C_MBS		0x00000fff /* Maximum Burst Size. */
+#define PCI_DMA8C_OUR		(1 << 12)
+
+/*
+ * PCI DMA Channel 9 Configuration Register
+ */
+#define PCI_DMA9C_MBS_BIT	0	/* Maximum Burst Size. */
+#define PCI_DMA9C_MBS		0x00000fff
+
+/*
+ * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors
+ */
+
+#define PCI_DMAD_PT_BIT		22		/* in DEVCMD field (descriptor) */
+#define PCI_DMAD_PT		0x00c00000	/* preferred transaction field */
+/* These are for reads (DMA channel 8) */
+#define PCI_DMAD_DEVCMD_MR	0		/* memory read */
+#define	PCI_DMAD_DEVCMD_MRL	1		/* memory read line */
+#define	PCI_DMAD_DEVCMD_MRM	2		/* memory read multiple */
+#define	PCI_DMAD_DEVCMD_IOR	3		/* I/O read */
+/* These are for writes (DMA channel 9) */
+#define PCI_DMAD_DEVCMD_MW	0		/* memory write */
+#define	PCI_DMAD_DEVCMD_MWI	1		/* memory write invalidate */
+#define	PCI_DMAD_DEVCMD_IOW	3		/* I/O write */
+
+/* Swap byte field applies to both DMA channel 8 and 9 */
+#define	PCI_DMAD_SB		(1 << 24)	/* swap byte field */
+
+
+/*
+ * PCI Target Control Register
+ */
+
+#define PCI_TC_RTIMER_BIT	0
+#define PCI_TC_RTIMER		0x000000ff
+#define PCI_TC_DTIMER_BIT	8
+#define PCI_TC_DTIMER		0x0000ff00
+#define PCI_TC_RDR		(1 << 18)
+#define PCI_TC_DDT		(1 << 19)
+
+/*
+ * PCI messaging unit [applies to both inbound and outbound registers ]
+ */
+#define PCI_MSU_M0		(1 << 0)
+#define PCI_MSU_M1		(1 << 1)
+#define PCI_MSU_DB		(1 << 2)
+
+#define PCI_MSG_ADDR	     	0xB8088010
+#define PCI0_ADDR		0xB8080000
+#define rc32434_pci ((struct pci_reg *) PCI0_ADDR)
+#define rc32434_pci_msg ((struct pci_msu *) PCI_MSG_ADDR)
+
+#define PCIM_SHFT		0x6
+#define PCIM_BIT_LEN		0x7
+#define PCIM_H_EA		0x3
+#define PCIM_H_IA_FIX		0x4
+#define PCIM_H_IA_RR		0x5
+#if 0
+#define PCI_ADDR_START		0x13000000
+#endif
+
+#define PCI_ADDR_START		0x50000000
+
+#define CPUTOPCI_MEM_WIN	0x02000000
+#define CPUTOPCI_IO_WIN		0x00100000
+#define PCILBA_SIZE_SHFT	2
+#define PCILBA_SIZE_MASK	0x1F
+#define SIZE_256MB		0x1C
+#define SIZE_128MB		0x1B
+#define SIZE_64MB               0x1A
+#define SIZE_32MB		0x19
+#define SIZE_16MB               0x18
+#define SIZE_4MB		0x16
+#define SIZE_2MB		0x15
+#define SIZE_1MB		0x14
+#define KORINA_CONFIG0_ADDR	0x80000000
+#define KORINA_CONFIG1_ADDR	0x80000004
+#define KORINA_CONFIG2_ADDR	0x80000008
+#define KORINA_CONFIG3_ADDR	0x8000000C
+#define KORINA_CONFIG4_ADDR	0x80000010
+#define KORINA_CONFIG5_ADDR	0x80000014
+#define KORINA_CONFIG6_ADDR	0x80000018
+#define KORINA_CONFIG7_ADDR	0x8000001C
+#define KORINA_CONFIG8_ADDR	0x80000020
+#define KORINA_CONFIG9_ADDR	0x80000024
+#define KORINA_CONFIG10_ADDR	0x80000028
+#define KORINA_CONFIG11_ADDR	0x8000002C
+#define KORINA_CONFIG12_ADDR	0x80000030
+#define KORINA_CONFIG13_ADDR	0x80000034
+#define KORINA_CONFIG14_ADDR	0x80000038
+#define KORINA_CONFIG15_ADDR	0x8000003C
+#define KORINA_CONFIG16_ADDR	0x80000040
+#define KORINA_CONFIG17_ADDR	0x80000044
+#define KORINA_CONFIG18_ADDR	0x80000048
+#define KORINA_CONFIG19_ADDR	0x8000004C
+#define KORINA_CONFIG20_ADDR	0x80000050
+#define KORINA_CONFIG21_ADDR	0x80000054
+#define KORINA_CONFIG22_ADDR	0x80000058
+#define KORINA_CONFIG23_ADDR	0x8000005C
+#define KORINA_CONFIG24_ADDR	0x80000060
+#define KORINA_CONFIG25_ADDR	0x80000064
+#define KORINA_CMD 		(PCI_CFG04_CMD_IO_ENA | \
+				 PCI_CFG04_CMD_MEM_ENA | \
+				 PCI_CFG04_CMD_BM_ENA | \
+				 PCI_CFG04_CMD_MW_INV | \
+				 PCI_CFG04_CMD_PAR_ENA | \
+				 PCI_CFG04_CMD_SER_ENA)
+
+#define KORINA_STAT		(PCI_CFG04_STAT_MDPE | \
+				 PCI_CFG04_STAT_STA | \
+				 PCI_CFG04_STAT_RTA | \
+				 PCI_CFG04_STAT_RMA | \
+				 PCI_CFG04_STAT_SSE | \
+				 PCI_CFG04_STAT_PE)
+
+#define KORINA_CNFG1		((KORINA_STAT<<16)|KORINA_CMD)
+
+#define KORINA_REVID		0
+#define KORINA_CLASS_CODE	0
+#define KORINA_CNFG2		((KORINA_CLASS_CODE<<8) | \
+				  KORINA_REVID)
+
+#define KORINA_CACHE_LINE_SIZE	4
+#define KORINA_MASTER_LAT	0x3c
+#define KORINA_HEADER_TYPE	0
+#define KORINA_BIST		0
+
+#define KORINA_CNFG3 ((KORINA_BIST << 24) | \
+		      (KORINA_HEADER_TYPE<<16) | \
+		      (KORINA_MASTER_LAT<<8) | \
+		      KORINA_CACHE_LINE_SIZE)
+
+#define KORINA_BAR0	0x00000008	/* 128 MB Memory */
+#define KORINA_BAR1	0x18800001	/* 1 MB IO */
+#define KORINA_BAR2	0x18000001	/* 2 MB IO window for Korina
+					   internal Registers */
+#define KORINA_BAR3	0x48000008	/* Spare 128 MB Memory */
+
+#define KORINA_CNFG4	KORINA_BAR0
+#define KORINA_CNFG5    KORINA_BAR1
+#define KORINA_CNFG6 	KORINA_BAR2
+#define KORINA_CNFG7	KORINA_BAR3
+
+#define KORINA_SUBSYS_VENDOR_ID 0x011d
+#define KORINA_SUBSYSTEM_ID	0x0214
+#define KORINA_CNFG8		0
+#define KORINA_CNFG9		0
+#define KORINA_CNFG10		0
+#define KORINA_CNFG11 	((KORINA_SUBSYS_VENDOR_ID<<16) | \
+			  KORINA_SUBSYSTEM_ID)
+#define KORINA_INT_LINE		1
+#define KORINA_INT_PIN		1
+#define KORINA_MIN_GNT		8
+#define KORINA_MAX_LAT		0x38
+#define KORINA_CNFG12		0
+#define KORINA_CNFG13 		0
+#define KORINA_CNFG14		0
+#define KORINA_CNFG15	((KORINA_MAX_LAT<<24) | \
+			 (KORINA_MIN_GNT<<16) | \
+			 (KORINA_INT_PIN<<8)  | \
+			  KORINA_INT_LINE)
+#define	KORINA_RETRY_LIMIT	0x80
+#define KORINA_TRDY_LIMIT	0x80
+#define KORINA_CNFG16 ((KORINA_RETRY_LIMIT<<8) | \
+			KORINA_TRDY_LIMIT)
+#define PCI_PBAxC_R		0x0
+#define PCI_PBAxC_RL		0x1
+#define PCI_PBAxC_RM		0x2
+#define SIZE_SHFT		2
+
+#if defined(__MIPSEB__)
+#define KORINA_PBA0C	(PCI_PBAC_MRL | PCI_PBAC_SB | \
+			  ((PCI_PBAxC_RM & 0x3) << PCI_PBAC_MR_BIT) | \
+			  PCI_PBAC_PP | \
+			  (SIZE_128MB<<SIZE_SHFT) | \
+			   PCI_PBAC_P)
+#else
+#define KORINA_PBA0C	(PCI_PBAC_MRL | \
+			  ((PCI_PBAxC_RM & 0x3) << PCI_PBAC_MR_BIT) | \
+			  PCI_PBAC_PP | \
+			  (SIZE_128MB<<SIZE_SHFT) | \
+			   PCI_PBAC_P)
+#endif
+#define KORINA_CNFG17	KORINA_PBA0C
+#define KORINA_PBA0M	0x0
+#define KORINA_CNFG18	KORINA_PBA0M
+
+#if defined(__MIPSEB__)
+#define KORINA_PBA1C	((SIZE_1MB<<SIZE_SHFT) | PCI_PBAC_SB | \
+			  PCI_PBAC_MSI)
+#else
+#define KORINA_PBA1C	((SIZE_1MB<<SIZE_SHFT) | \
+			  PCI_PBAC_MSI)
+#endif
+#define KORINA_CNFG19	KORINA_PBA1C
+#define KORINA_PBA1M	0x0
+#define KORINA_CNFG20	KORINA_PBA1M
+
+#if defined(__MIPSEB__)
+#define KORINA_PBA2C	((SIZE_2MB<<SIZE_SHFT) | PCI_PBAC_SB | \
+			  PCI_PBAC_MSI)
+#else
+#define KORINA_PBA2C	((SIZE_2MB<<SIZE_SHFT) | \
+			  PCI_PBAC_MSI)
+#endif
+#define KORINA_CNFG21	KORINA_PBA2C
+#define KORINA_PBA2M	0x18000000
+#define KORINA_CNFG22	KORINA_PBA2M
+#define KORINA_PBA3C	0
+#define KORINA_CNFG23	KORINA_PBA3C
+#define KORINA_PBA3M	0
+#define KORINA_CNFG24	KORINA_PBA3M
+
+#define	PCITC_DTIMER_VAL	8
+#define PCITC_RTIMER_VAL	0x10
+
+#endif  /* __ASM_RC32434_PCI_H */
diff --git a/include/asm-mips/mach-rc32434/prom.h b/include/asm-mips/mach-rc32434/prom.h
new file mode 100644
index 0000000..1d66ddc
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/prom.h
@@ -0,0 +1,44 @@
+/*
+ *  Definitions for the PROM
+ *
+ *  Copyright 2002 Ryan Holm <ryan.holmQVist@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ */
+
+#define PROM_ENTRY(x)		(0xbfc00000 + ((x) * 8))
+
+#define GPIO_INIT_NOBUTTON	""
+#define GPIO_INIT_BUTTON	" 2"
+
+#define SR_NMI			0x00180000
+#define SERIAL_SPEED_ENTRY	0x00000001
+
+#define FREQ_TAG		"HZ="
+#define GPIO_TAG		"gpio="
+#define KMAC_TAG		"kmac="
+#define MEM_TAG			"mem="
+#define BOARD_TAG		"board="
+
+#define BOARD_RB532		"500"
+#define BOARD_RB532A		"500r5"
diff --git a/include/asm-mips/mach-rc32434/rb.h b/include/asm-mips/mach-rc32434/rb.h
new file mode 100644
index 0000000..e0a76e3
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/rb.h
@@ -0,0 +1,81 @@
+/*
+ *  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.
+ *
+ *  Copyright (C) 2004 IDT Inc.
+ *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+#ifndef __ASM_RC32434_RB_H
+#define __ASM_RC32434_RB_H
+
+#include <linux/genhd.h>
+
+#define IDT434_REG_BASE	((volatile void *) KSEG1ADDR(0x18000000))
+#define DEV0BASE	0x010000
+#define DEV0MASK	0x010004
+#define DEV0C		0x010008
+#define DEV0T		0x01000C
+#define DEV1BASE	0x010010
+#define DEV1MASK	0x010014
+#define DEV1C		0x010018
+#define DEV1TC		0x01001C
+#define DEV2BASE	0x010020
+#define DEV2MASK	0x010024
+#define DEV2C		0x010028
+#define DEV2TC		0x01002C
+#define DEV3BASE	0x010030
+#define DEV3MASK	0x010034
+#define DEV3C		0x010038
+#define DEV3TC		0x01003C
+#define BTCS		0x010040
+#define BTCOMPARE	0x010044
+#define GPIOBASE	0x050000
+#define GPIOCFG		0x050004
+#define GPIOD		0x050008
+#define GPIOILEVEL	0x05000C
+#define GPIOISTAT	0x050010
+#define GPIONMIEN	0x050014
+#define IMASK6		0x038038
+#define LO_WPX		(1 << 0)
+#define LO_ALE		(1 << 1)
+#define LO_CLE		(1 << 2)
+#define LO_CEX		(1 << 3)
+#define LO_FOFF		(1 << 5)
+#define LO_SPICS	(1 << 6)
+#define LO_ULED		(1 << 7)
+
+#define BIT_TO_MASK(x)	(1 << x)
+
+struct dev_reg {
+	u32	base;
+	u32	mask;
+	u32	ctl;
+	u32	timing;
+};
+
+struct korina_device {
+	char *name;
+	unsigned char mac[6];
+	struct net_device *dev;
+};
+
+struct cf_device {
+	int gpio_pin;
+	void *dev;
+	struct gendisk *gd;
+};
+
+struct mpmc_device {
+	unsigned char	state;
+	spinlock_t	lock;
+	void __iomem 	*base;
+};
+
+#endif  /* __ASM_RC32434_RB_H */
diff --git a/include/asm-mips/mach-rc32434/rc32434.h b/include/asm-mips/mach-rc32434/rc32434.h
new file mode 100644
index 0000000..c4a0214
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/rc32434.h
@@ -0,0 +1,61 @@
+/*
+ * Definitions for IDT RC323434 CPU.
+ */
+
+#ifndef _ASM_RC32434_RC32434_H_
+#define _ASM_RC32434_RC32434_H_
+
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define RC32434_REG_BASE	0x18000000
+#define RC32434_RST		(1 << 15)
+
+#define IDT_CLOCK_MULT		2
+#define MIPS_CPU_TIMER_IRQ	7
+
+/* Interrupt Controller */
+#define IC_GROUP0_PEND		(RC32434_REG_BASE + 0x38000)
+#define IC_GROUP0_MASK		(RC32434_REG_BASE + 0x38008)
+#define IC_GROUP_OFFSET		0x0C
+
+#define NUM_INTR_GROUPS		5
+
+/* 16550 UARTs */
+#define GROUP0_IRQ_BASE		8	/* GRP2 IRQ numbers start here */
+					/* GRP3 IRQ numbers start here */
+#define GROUP1_IRQ_BASE		(GROUP0_IRQ_BASE + 32)
+					/* GRP4 IRQ numbers start here */
+#define GROUP2_IRQ_BASE		(GROUP1_IRQ_BASE + 32)
+					/* GRP5 IRQ numbers start here */
+#define GROUP3_IRQ_BASE		(GROUP2_IRQ_BASE + 32)
+#define GROUP4_IRQ_BASE		(GROUP3_IRQ_BASE + 32)
+
+
+#ifdef __MIPSEB__
+#define RC32434_UART0_BASE	(RC32434_REG_BASE + 0x58003)
+#else
+#define RC32434_UART0_BASE	(RC32434_REG_BASE + 0x58000)
+#endif
+
+#define RC32434_UART0_IRQ	(GROUP3_IRQ_BASE + 0)
+
+/* cpu pipeline flush */
+static inline void rc32434_sync(void)
+{
+	__asm__ volatile ("sync");
+}
+
+static inline void rc32434_sync_udelay(int us)
+{
+	__asm__ volatile ("sync");
+	udelay(us);
+}
+
+static inline void rc32434_sync_delay(int ms)
+{
+	__asm__ volatile ("sync");
+	mdelay(ms);
+}
+
+#endif  /* _ASM_RC32434_RC32434_H_ */
diff --git a/include/asm-mips/mach-rc32434/timer.h b/include/asm-mips/mach-rc32434/timer.h
new file mode 100644
index 0000000..e49b1d5
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/timer.h
@@ -0,0 +1,65 @@
+/*
+ *  Definitions for timer registers
+ *
+ *  Copyright 2004 Philip Rischel <rischelp@idt.com>
+ *  Copyright 2008 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 __ASM_RC32434_TIMER_H
+#define __ASM_RC32434_TIMER_H
+
+#include <asm/mach-rc32434/rb.h>
+
+#define TIMER0_BASE_ADDR		0x18028000
+#define TIMER_COUNT			3
+
+struct timer_counter {
+	u32 count;
+	u32 compare;
+	u32 ctc;		/*use CTC_ */
+};
+
+struct timer {
+	struct timer_counter tim[TIMER_COUNT];
+	u32 rcount;	/* use RCOUNT_ */
+	u32 rcompare;	/* use RCOMPARE_ */
+	u32 rtc;	/* use RTC_ */
+};
+
+#define RC32434_CTC_EN_BIT		0
+#define RC32434_CTC_TO_BIT		1
+
+/* Real time clock registers */
+#define RC32434_RTC_MSK(x)              BIT_TO_MASK(x)
+#define RC32434_RTC_CE_BIT              0
+#define RC32434_RTC_TO_BIT              1
+#define RC32434_RTC_RQE_BIT             2
+
+/* Counter registers */
+#define RC32434_RCOUNT_BIT              0
+#define RC32434_RCOUNT_MSK              0x0000ffff
+#define RC32434_RCOMP_BIT               0
+#define RC32434_RCOMP_MSK               0x0000ffff
+
+#endif  /* __ASM_RC32434_TIMER_H */
diff --git a/include/asm-mips/mach-rc32434/war.h b/include/asm-mips/mach-rc32434/war.h
new file mode 100644
index 0000000..3ddf187
--- /dev/null
+++ b/include/asm-mips/mach-rc32434/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_MIPS_WAR_H
+#define __ASM_MIPS_MACH_MIPS_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR	0
+#define R4600_V1_HIT_CACHEOP_WAR	0
+#define R4600_V2_HIT_CACHEOP_WAR	0
+#define R5432_CP0_INTERRUPT_WAR		0
+#define BCM1250_M3_WAR			0
+#define SIBYTE_1956_WAR			0
+#define MIPS4K_ICACHE_REFILL_WAR	1
+#define MIPS_CACHE_SYNC_WAR		0
+#define TX49XX_ICACHE_INDEX_INV_WAR	0
+#define RM9000_CDEX_SMP_WAR		0
+#define ICACHE_REFILLS_WORKAROUND_WAR	0
+#define R10000_LLSC_WAR			0
+#define MIPS34K_MISSED_ITLB_WAR		0
+
+#endif /* __ASM_MIPS_MACH_MIPS_WAR_H */
diff --git a/include/asm-mips/mips-boards/atlas.h b/include/asm-mips/mips-boards/atlas.h
deleted file mode 100644
index a8ae12d..0000000
--- a/include/asm-mips/mips-boards/atlas.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * Defines of the Atlas board specific address-MAP, registers, etc.
- *
- */
-#ifndef _MIPS_ATLAS_H
-#define _MIPS_ATLAS_H
-
-#include <asm/addrspace.h>
-
-/*
- * Atlas RTC-device indirect register access.
- */
-#define ATLAS_RTC_ADR_REG       0x1f000800
-#define ATLAS_RTC_DAT_REG       0x1f000808
-
-/*
- * Atlas interrupt controller register base.
- */
-#define ATLAS_ICTRL_REGS_BASE   0x1f000000
-
-/*
- * Atlas registers are memory mapped on 64-bit aligned boundaries and
- * only word access are allowed.
- */
-struct atlas_ictrl_regs {
-	volatile unsigned int intraw;
-	int dummy1;
-	volatile unsigned int intseten;
-	int dummy2;
-	volatile unsigned int intrsten;
-	int dummy3;
-	volatile unsigned int intenable;
-	int dummy4;
-	volatile unsigned int intstatus;
-	int dummy5;
-};
-
-/*
- * Atlas UART register base.
- */
-#define ATLAS_UART_REGS_BASE    0x1f000900
-#define ATLAS_BASE_BAUD ( 3686400 / 16 )
-
-/*
- * Atlas PSU standby register.
- */
-#define ATLAS_PSUSTBY_REG       0x1f000600
-#define ATLAS_GOSTBY            0x4d
-
-/*
- * We make a universal assumption about the way the bootloader (YAMON)
- * have located the Philips SAA9730 chip.
- * This is not ideal, but is needed for setting up remote debugging as
- * soon as possible.
- */
-#define ATLAS_SAA9730_REG	0x10800000
-
-#define ATLAS_SAA9730_BAUDCLOCK	3692300
-
-#endif /* !(_MIPS_ATLAS_H) */
diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h
deleted file mode 100644
index 93ba1c1..0000000
--- a/include/asm-mips/mips-boards/atlasint.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 1999, 2006  MIPS Technologies, Inc.  All rights reserved.
- *	Authors: Carsten Langgaard <carstenl@mips.com>
- *		 Maciej W. Rozycki <macro@mips.com>
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * Defines for the Atlas interrupt controller.
- *
- */
-#ifndef _MIPS_ATLASINT_H
-#define _MIPS_ATLASINT_H
-
-#include <irq.h>
-
-/* CPU interrupt offsets */
-#define MIPSCPU_INT_SW0		0
-#define MIPSCPU_INT_SW1		1
-#define MIPSCPU_INT_MB0		2
-#define MIPSCPU_INT_ATLAS	MIPSCPU_INT_MB0
-#define MIPSCPU_INT_MB1		3
-#define MIPSCPU_INT_MB2		4
-#define MIPSCPU_INT_MB3		5
-#define MIPSCPU_INT_MB4		6
-
-/*
- * Interrupts 8..39 are used for Atlas interrupt controller interrupts
- */
-#define ATLAS_INT_BASE		8
-#define ATLAS_INT_UART		(ATLAS_INT_BASE + 0)
-#define ATLAS_INT_TIM0		(ATLAS_INT_BASE + 1)
-#define ATLAS_INT_RES2		(ATLAS_INT_BASE + 2)
-#define ATLAS_INT_RES3		(ATLAS_INT_BASE + 3)
-#define ATLAS_INT_RTC		(ATLAS_INT_BASE + 4)
-#define ATLAS_INT_COREHI	(ATLAS_INT_BASE + 5)
-#define ATLAS_INT_CORELO	(ATLAS_INT_BASE + 6)
-#define ATLAS_INT_RES7		(ATLAS_INT_BASE + 7)
-#define ATLAS_INT_PCIA		(ATLAS_INT_BASE + 8)
-#define ATLAS_INT_PCIB		(ATLAS_INT_BASE + 9)
-#define ATLAS_INT_PCIC		(ATLAS_INT_BASE + 10)
-#define ATLAS_INT_PCID		(ATLAS_INT_BASE + 11)
-#define ATLAS_INT_ENUM		(ATLAS_INT_BASE + 12)
-#define ATLAS_INT_DEG		(ATLAS_INT_BASE + 13)
-#define ATLAS_INT_ATXFAIL	(ATLAS_INT_BASE + 14)
-#define ATLAS_INT_INTA		(ATLAS_INT_BASE + 15)
-#define ATLAS_INT_INTB		(ATLAS_INT_BASE + 16)
-#define ATLAS_INT_ETH		ATLAS_INT_INTB
-#define ATLAS_INT_INTC		(ATLAS_INT_BASE + 17)
-#define ATLAS_INT_SCSI		ATLAS_INT_INTC
-#define ATLAS_INT_INTD		(ATLAS_INT_BASE + 18)
-#define ATLAS_INT_SERR		(ATLAS_INT_BASE + 19)
-#define ATLAS_INT_RES20		(ATLAS_INT_BASE + 20)
-#define ATLAS_INT_RES21		(ATLAS_INT_BASE + 21)
-#define ATLAS_INT_RES22		(ATLAS_INT_BASE + 22)
-#define ATLAS_INT_RES23		(ATLAS_INT_BASE + 23)
-#define ATLAS_INT_RES24		(ATLAS_INT_BASE + 24)
-#define ATLAS_INT_RES25		(ATLAS_INT_BASE + 25)
-#define ATLAS_INT_RES26		(ATLAS_INT_BASE + 26)
-#define ATLAS_INT_RES27		(ATLAS_INT_BASE + 27)
-#define ATLAS_INT_RES28		(ATLAS_INT_BASE + 28)
-#define ATLAS_INT_RES29		(ATLAS_INT_BASE + 29)
-#define ATLAS_INT_RES30		(ATLAS_INT_BASE + 30)
-#define ATLAS_INT_RES31		(ATLAS_INT_BASE + 31)
-#define ATLAS_INT_END		(ATLAS_INT_BASE + 31)
-
-/*
- * Interrupts 64..127 are used for Soc-it Classic interrupts
- */
-#define MSC01C_INT_BASE		64
-
-/* SOC-it Classic interrupt offsets */
-#define MSC01C_INT_TMR		0
-#define MSC01C_INT_PCI		1
-
-/*
- * Interrupts 64..127 are used for Soc-it EIC interrupts
- */
-#define MSC01E_INT_BASE		64
-
-/* SOC-it EIC interrupt offsets */
-#define	MSC01E_INT_SW0		1
-#define	MSC01E_INT_SW1		2
-#define	MSC01E_INT_MB0		3
-#define	MSC01E_INT_ATLAS	MSC01E_INT_MB0
-#define	MSC01E_INT_MB1		4
-#define	MSC01E_INT_MB2		5
-#define	MSC01E_INT_MB3		6
-#define	MSC01E_INT_MB4		7
-#define	MSC01E_INT_TMR		8
-#define	MSC01E_INT_PCI		9
-#define	MSC01E_INT_PERFCTR	10
-#define	MSC01E_INT_CPUCTR	11
-
-#endif /* !(_MIPS_ATLASINT_H) */
diff --git a/include/asm-mips/mips-boards/maltasmp.h b/include/asm-mips/mips-boards/maltasmp.h
deleted file mode 100644
index 8d7e955..0000000
--- a/include/asm-mips/mips-boards/maltasmp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * There are several SMP models supported
- * SMTC is mutually exclusive to other options (atm)
- */
-#if defined(CONFIG_MIPS_MT_SMTC)
-#define malta_smtc	1
-#define malta_cmp	0
-#define malta_smvp	0
-#else
-#define malta_smtc	0
-#if defined(CONFIG_MIPS_CMP)
-extern int gcmp_present;
-#define malta_cmp	gcmp_present
-#else
-#define malta_cmp	0
-#endif
-/* FIXME: should become COMFIG_MIPS_MT_SMVP */
-#if defined(CONFIG_MIPS_MT_SMP)
-#define malta_smvp	1
-#else
-#define malta_smvp	0
-#endif
-#endif
-
-#include <asm/mipsregs.h>
-#include <asm/mipsmtregs.h>
-
-/* malta_smtc */
-#include <asm/smtc.h>
-#include <asm/smtc_ipi.h>
-
-/* malta_cmp */
-#include <asm/cmp.h>
-
-/* malta_smvp */
-#include <asm/smvp.h>
diff --git a/include/asm-mips/mips-boards/saa9730_uart.h b/include/asm-mips/mips-boards/saa9730_uart.h
deleted file mode 100644
index c913143..0000000
--- a/include/asm-mips/mips-boards/saa9730_uart.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * Register definitions for the UART part of the Philips SAA9730 chip.
- *
- */
-
-#ifndef SAA9730_UART_H
-#define SAA9730_UART_H
-
-/* The SAA9730 UART register map, as seen via the PCI bus */
-
-#define SAA9730_UART_REGS_ADDR	0x21800
-
-struct uart_saa9730_regmap {
-	volatile unsigned char Thr_Rbr;
-	volatile unsigned char Ier;
-	volatile unsigned char Iir_Fcr;
-	volatile unsigned char Lcr;
-	volatile unsigned char Mcr;
-	volatile unsigned char Lsr;
-	volatile unsigned char Msr;
-	volatile unsigned char Scr;
-	volatile unsigned char BaudDivLsb;
-	volatile unsigned char BaudDivMsb;
-	volatile unsigned char Junk0;
-	volatile unsigned char Junk1;
-	volatile unsigned int Config;		/* 0x2180c */
-	volatile unsigned int TxStart;		/* 0x21810 */
-	volatile unsigned int TxLength;		/* 0x21814 */
-	volatile unsigned int TxCounter;	/* 0x21818 */
-	volatile unsigned int RxStart;		/* 0x2181c */
-	volatile unsigned int RxLength;		/* 0x21820 */
-	volatile unsigned int RxCounter;	/* 0x21824 */
-};
-typedef volatile struct uart_saa9730_regmap t_uart_saa9730_regmap;
-
-/*
- * Only a subset of the UART control bits are defined here,
- * enough to make the serial debug port work.
- */
-
-#define SAA9730_LCR_DATA8	0x03
-
-#define SAA9730_MCR_DTR		0x01
-#define SAA9730_MCR_RTS		0x02
-
-#define SAA9730_LSR_DR		0x01
-#define SAA9730_LSR_THRE	0x20
-
-#endif /* !(SAA9730_UART_H) */
diff --git a/include/asm-mips/mips-boards/sead.h b/include/asm-mips/mips-boards/sead.h
deleted file mode 100644
index 68c69de..0000000
--- a/include/asm-mips/mips-boards/sead.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * Defines of the SEAD board specific address-MAP, registers, etc.
- *
- */
-#ifndef _MIPS_SEAD_H
-#define _MIPS_SEAD_H
-
-#include <asm/addrspace.h>
-
-/*
- * SEAD UART register base.
- */
-#define SEAD_UART0_REGS_BASE    (0x1f000800)
-#define SEAD_BASE_BAUD ( 3686400 / 16 )
-
-#endif /* !(_MIPS_SEAD_H) */
diff --git a/include/asm-mips/mips-boards/seadint.h b/include/asm-mips/mips-boards/seadint.h
deleted file mode 100644
index e710bae..0000000
--- a/include/asm-mips/mips-boards/seadint.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.
- *
- * Defines for the SEAD interrupt controller.
- */
-#ifndef _MIPS_SEADINT_H
-#define _MIPS_SEADINT_H
-
-#include <irq.h>
-
-#define MIPSCPU_INT_UART0	2
-#define MIPSCPU_INT_UART1	3
-
-#endif /* !(_MIPS_SEADINT_H) */
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index 8735aa0..494f00b 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -34,6 +34,9 @@
 #include <linux/pfn.h>
 #include <asm/io.h>
 
+extern void build_clear_page(void);
+extern void build_copy_page(void);
+
 /*
  * It's normally defined only for FLATMEM config but it's
  * used in our early mem init code for all memory models.
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
index d3be834..c205875 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -173,6 +173,5 @@
 }
 
 extern int pci_probe_only;
-extern unsigned int pcibios_max_latency;
 
 #endif /* _ASM_PCI_H */
diff --git a/include/asm-mips/setup.h b/include/asm-mips/setup.h
index 883f59b..e600ced 100644
--- a/include/asm-mips/setup.h
+++ b/include/asm-mips/setup.h
@@ -3,6 +3,8 @@
 
 #define COMMAND_LINE_SIZE	256
 
+#ifdef  __KERNEL__
 extern void setup_early_printk(void);
+#endif /* __KERNEL__ */
 
 #endif /* __SETUP_H */
diff --git a/include/asm-mips/txx9/generic.h b/include/asm-mips/txx9/generic.h
index d875666..cbae37e 100644
--- a/include/asm-mips/txx9/generic.h
+++ b/include/asm-mips/txx9/generic.h
@@ -12,6 +12,8 @@
 #include <linux/ioport.h>	/* for struct resource */
 
 extern struct resource txx9_ce_res[];
+#define TXX9_CE(n)	(unsigned long)(txx9_ce_res[(n)].start)
+extern unsigned int txx9_pcode;
 extern char txx9_pcode_str[8];
 void txx9_reg_res_init(unsigned int pcode, unsigned long base,
 		       unsigned long size);
@@ -19,6 +21,11 @@
 extern unsigned int txx9_master_clock;
 extern unsigned int txx9_cpu_clock;
 extern unsigned int txx9_gbus_clock;
+#define TXX9_IMCLK	(txx9_gbus_clock / 2)
+
+extern int txx9_ccfg_toeon;
+struct uart_port;
+int early_serial_txx9_setup(struct uart_port *port);
 
 struct pci_dev;
 struct txx9_board_vec {
diff --git a/include/asm-mips/txx9/rbtx4927.h b/include/asm-mips/txx9/rbtx4927.h
index bf19458..6fcec91 100644
--- a/include/asm-mips/txx9/rbtx4927.h
+++ b/include/asm-mips/txx9/rbtx4927.h
@@ -34,7 +34,23 @@
 #define RBTX4927_PCIIO		0x16000000
 #define RBTX4927_PCIIO_SIZE	0x01000000
 
-#define rbtx4927_pcireset_addr	((__u8 __iomem *)0xbc00f006UL)
+#define RBTX4927_IMASK_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002000)
+#define RBTX4927_IMSTAT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002006)
+#define RBTX4927_SOFTRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f000)
+#define RBTX4927_SOFTRESETLOCK_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f002)
+#define RBTX4927_PCIRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000f006)
+#define RBTX4927_BRAMRTC_BASE	(IO_BASE + TXX9_CE(2) + 0x00010000)
+#define RBTX4927_ETHER_BASE	(IO_BASE + TXX9_CE(2) + 0x00020000)
+
+/* Ethernet port address */
+#define RBTX4927_ETHER_ADDR	(RBTX4927_ETHER_BASE + 0x280)
+
+#define rbtx4927_imask_addr	((__u8 __iomem *)RBTX4927_IMASK_ADDR)
+#define rbtx4927_imstat_addr	((__u8 __iomem *)RBTX4927_IMSTAT_ADDR)
+#define rbtx4927_softreset_addr	((__u8 __iomem *)RBTX4927_SOFTRESET_ADDR)
+#define rbtx4927_softresetlock_addr	\
+				((__u8 __iomem *)RBTX4927_SOFTRESETLOCK_ADDR)
+#define rbtx4927_pcireset_addr	((__u8 __iomem *)RBTX4927_PCIRESET_ADDR)
 
 /* bits for ISTAT/IMASK/IMSTAT */
 #define RBTX4927_INTB_PCID	0
@@ -62,13 +78,7 @@
 #define RBTX4927_ISA_IO_OFFSET 0
 #endif
 
-#define RBTX4927_SW_RESET_DO         (void __iomem *)0xbc00f000UL
-#define RBTX4927_SW_RESET_DO_SET                0x01
-
-#define RBTX4927_SW_RESET_ENABLE     (void __iomem *)0xbc00f002UL
-#define RBTX4927_SW_RESET_ENABLE_SET            0x01
-
-#define RBTX4927_RTL_8019_BASE (0x1c020280 - RBTX4927_ISA_IO_OFFSET)
+#define RBTX4927_RTL_8019_BASE (RBTX4927_ETHER_ADDR - mips_io_port_base)
 #define RBTX4927_RTL_8019_IRQ  (TXX9_IRQ_BASE + TX4927_IR_INT(3))
 
 void rbtx4927_prom_init(void);
diff --git a/include/asm-mips/txx9/rbtx4938.h b/include/asm-mips/txx9/rbtx4938.h
index 2f5d5e7..9f0441a 100644
--- a/include/asm-mips/txx9/rbtx4938.h
+++ b/include/asm-mips/txx9/rbtx4938.h
@@ -15,35 +15,31 @@
 #include <asm/txx9irq.h>
 #include <asm/txx9/tx4938.h>
 
-/* CS */
-#define RBTX4938_CE0	0x1c000000	/* 64M */
-#define RBTX4938_CE2	0x17f00000	/* 1M */
-
 /* Address map */
-#define RBTX4938_FPGA_REG_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00000000)
-#define RBTX4938_FPGA_REV_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00000002)
-#define RBTX4938_CONFIG1_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00000004)
-#define RBTX4938_CONFIG2_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00000006)
-#define RBTX4938_CONFIG3_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00000008)
-#define RBTX4938_LED_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00001000)
-#define RBTX4938_DIPSW_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00001002)
-#define RBTX4938_BDIPSW_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00001004)
-#define RBTX4938_IMASK_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00002000)
-#define RBTX4938_IMASK2_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00002002)
-#define RBTX4938_INTPOL_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00002004)
-#define RBTX4938_ISTAT_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00002006)
-#define RBTX4938_ISTAT2_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00002008)
-#define RBTX4938_IMSTAT_ADDR	(KSEG1 + RBTX4938_CE2 + 0x0000200a)
-#define RBTX4938_IMSTAT2_ADDR	(KSEG1 + RBTX4938_CE2 + 0x0000200c)
-#define RBTX4938_SOFTINT_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00003000)
-#define RBTX4938_PIOSEL_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00005000)
-#define RBTX4938_SPICS_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00005002)
-#define RBTX4938_SFPWR_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00005008)
-#define RBTX4938_SFVOL_ADDR	(KSEG1 + RBTX4938_CE2 + 0x0000500a)
-#define RBTX4938_SOFTRESET_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00007000)
-#define RBTX4938_SOFTRESETLOCK_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00007002)
-#define RBTX4938_PCIRESET_ADDR	(KSEG1 + RBTX4938_CE2 + 0x00007004)
-#define RBTX4938_ETHER_BASE	(KSEG1 + RBTX4938_CE2 + 0x00020000)
+#define RBTX4938_FPGA_REG_ADDR	(IO_BASE + TXX9_CE(2) + 0x00000000)
+#define RBTX4938_FPGA_REV_ADDR	(IO_BASE + TXX9_CE(2) + 0x00000002)
+#define RBTX4938_CONFIG1_ADDR	(IO_BASE + TXX9_CE(2) + 0x00000004)
+#define RBTX4938_CONFIG2_ADDR	(IO_BASE + TXX9_CE(2) + 0x00000006)
+#define RBTX4938_CONFIG3_ADDR	(IO_BASE + TXX9_CE(2) + 0x00000008)
+#define RBTX4938_LED_ADDR	(IO_BASE + TXX9_CE(2) + 0x00001000)
+#define RBTX4938_DIPSW_ADDR	(IO_BASE + TXX9_CE(2) + 0x00001002)
+#define RBTX4938_BDIPSW_ADDR	(IO_BASE + TXX9_CE(2) + 0x00001004)
+#define RBTX4938_IMASK_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002000)
+#define RBTX4938_IMASK2_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002002)
+#define RBTX4938_INTPOL_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002004)
+#define RBTX4938_ISTAT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002006)
+#define RBTX4938_ISTAT2_ADDR	(IO_BASE + TXX9_CE(2) + 0x00002008)
+#define RBTX4938_IMSTAT_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000200a)
+#define RBTX4938_IMSTAT2_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000200c)
+#define RBTX4938_SOFTINT_ADDR	(IO_BASE + TXX9_CE(2) + 0x00003000)
+#define RBTX4938_PIOSEL_ADDR	(IO_BASE + TXX9_CE(2) + 0x00005000)
+#define RBTX4938_SPICS_ADDR	(IO_BASE + TXX9_CE(2) + 0x00005002)
+#define RBTX4938_SFPWR_ADDR	(IO_BASE + TXX9_CE(2) + 0x00005008)
+#define RBTX4938_SFVOL_ADDR	(IO_BASE + TXX9_CE(2) + 0x0000500a)
+#define RBTX4938_SOFTRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x00007000)
+#define RBTX4938_SOFTRESETLOCK_ADDR	(IO_BASE + TXX9_CE(2) + 0x00007002)
+#define RBTX4938_PCIRESET_ADDR	(IO_BASE + TXX9_CE(2) + 0x00007004)
+#define RBTX4938_ETHER_BASE	(IO_BASE + TXX9_CE(2) + 0x00020000)
 
 /* Ethernet port address (Jumperless Mode (W12:Open)) */
 #define RBTX4938_ETHER_ADDR	(RBTX4938_ETHER_BASE + 0x280)
diff --git a/include/asm-mips/txx9/tx3927.h b/include/asm-mips/txx9/tx3927.h
index ca414c7..ea79e1b 100644
--- a/include/asm-mips/txx9/tx3927.h
+++ b/include/asm-mips/txx9/tx3927.h
@@ -10,17 +10,18 @@
 
 #include <asm/txx9/txx927.h>
 
-#define TX3927_SDRAMC_REG	0xfffe8000
-#define TX3927_ROMC_REG		0xfffe9000
-#define TX3927_DMA_REG		0xfffeb000
-#define TX3927_IRC_REG		0xfffec000
-#define TX3927_PCIC_REG		0xfffed000
-#define TX3927_CCFG_REG		0xfffee000
+#define TX3927_REG_BASE	0xfffe0000UL
+#define TX3927_SDRAMC_REG	(TX3927_REG_BASE + 0x8000)
+#define TX3927_ROMC_REG		(TX3927_REG_BASE + 0x9000)
+#define TX3927_DMA_REG		(TX3927_REG_BASE + 0xb000)
+#define TX3927_IRC_REG		(TX3927_REG_BASE + 0xc000)
+#define TX3927_PCIC_REG		(TX3927_REG_BASE + 0xd000)
+#define TX3927_CCFG_REG		(TX3927_REG_BASE + 0xe000)
 #define TX3927_NR_TMR	3
-#define TX3927_TMR_REG(ch)	(0xfffef000 + (ch) * 0x100)
+#define TX3927_TMR_REG(ch)	(TX3927_REG_BASE + 0xf000 + (ch) * 0x100)
 #define TX3927_NR_SIO	2
-#define TX3927_SIO_REG(ch)	(0xfffef300 + (ch) * 0x100)
-#define TX3927_PIO_REG		0xfffef500
+#define TX3927_SIO_REG(ch)	(TX3927_REG_BASE + 0xf300 + (ch) * 0x100)
+#define TX3927_PIO_REG		(TX3927_REG_BASE + 0xf500)
 
 struct tx3927_sdramc_reg {
 	volatile unsigned long cr[8];
diff --git a/include/asm-mips/txx9/tx4927.h b/include/asm-mips/txx9/tx4927.h
index 46d60af..ceb4b79 100644
--- a/include/asm-mips/txx9/tx4927.h
+++ b/include/asm-mips/txx9/tx4927.h
@@ -32,32 +32,46 @@
 #include <asm/txx9irq.h>
 #include <asm/txx9/tx4927pcic.h>
 
-#define TX4927_SDRAMC_REG	0xff1f8000
-#define TX4927_EBUSC_REG	0xff1f9000
-#define TX4927_PCIC_REG		0xff1fd000
-#define TX4927_CCFG_REG		0xff1fe000
-#define TX4927_IRC_REG		0xff1ff600
+#ifdef CONFIG_64BIT
+#define TX4927_REG_BASE	0xffffffffff1f0000UL
+#else
+#define TX4927_REG_BASE	0xff1f0000UL
+#endif
+#define TX4927_REG_SIZE	0x00010000
+
+#define TX4927_SDRAMC_REG	(TX4927_REG_BASE + 0x8000)
+#define TX4927_EBUSC_REG	(TX4927_REG_BASE + 0x9000)
+#define TX4927_PCIC_REG		(TX4927_REG_BASE + 0xd000)
+#define TX4927_CCFG_REG		(TX4927_REG_BASE + 0xe000)
+#define TX4927_IRC_REG		(TX4927_REG_BASE + 0xf600)
 #define TX4927_NR_TMR	3
-#define TX4927_TMR_REG(ch)	(0xff1ff000 + (ch) * 0x100)
+#define TX4927_TMR_REG(ch)	(TX4927_REG_BASE + 0xf000 + (ch) * 0x100)
+#define TX4927_NR_SIO	2
+#define TX4927_SIO_REG(ch)	(TX4927_REG_BASE + 0xf300 + (ch) * 0x100)
+#define TX4927_PIO_REG		(TX4927_REG_BASE + 0xf500)
 
 #define TX4927_IR_INT(n)	(2 + (n))
 #define TX4927_IR_SIO(n)	(8 + (n))
 #define TX4927_IR_PCIC		16
+#define TX4927_NUM_IR_TMR	3
+#define TX4927_IR_TMR(n)	(17 + (n))
 #define TX4927_IR_PCIERR	22
 #define TX4927_NUM_IR	32
 
 #define TX4927_IRC_INT	2	/* IP[2] in Status register */
 
+#define TX4927_NUM_PIO	16
+
 struct tx4927_sdramc_reg {
-	volatile unsigned long long cr[4];
-	volatile unsigned long long unused0[4];
-	volatile unsigned long long tr;
-	volatile unsigned long long unused1[2];
-	volatile unsigned long long cmd;
+	u64 cr[4];
+	u64 unused0[4];
+	u64 tr;
+	u64 unused1[2];
+	u64 cmd;
 };
 
 struct tx4927_ebusc_reg {
-	volatile unsigned long long cr[8];
+	u64 cr[8];
 };
 
 struct tx4927_ccfg_reg {
@@ -160,12 +174,28 @@
 #define TX4927_CLKCTR_SIO0RST	0x00000002
 #define TX4927_CLKCTR_SIO1RST	0x00000001
 
-#define tx4927_sdramcptr	((struct tx4927_sdramc_reg *)TX4927_SDRAMC_REG)
+#define tx4927_sdramcptr \
+		((struct tx4927_sdramc_reg __iomem *)TX4927_SDRAMC_REG)
 #define tx4927_pcicptr \
 		((struct tx4927_pcic_reg __iomem *)TX4927_PCIC_REG)
 #define tx4927_ccfgptr \
 		((struct tx4927_ccfg_reg __iomem *)TX4927_CCFG_REG)
-#define tx4927_ebuscptr		((struct tx4927_ebusc_reg *)TX4927_EBUSC_REG)
+#define tx4927_ebuscptr \
+		((struct tx4927_ebusc_reg __iomem *)TX4927_EBUSC_REG)
+#define tx4927_pioptr		((struct txx9_pio_reg __iomem *)TX4927_PIO_REG)
+
+#define TX4927_REV_PCODE()	\
+	((__u32)__raw_readq(&tx4927_ccfgptr->crir) >> 16)
+
+#define TX4927_SDRAMC_CR(ch)	__raw_readq(&tx4927_sdramcptr->cr[(ch)])
+#define TX4927_SDRAMC_BA(ch)	((TX4927_SDRAMC_CR(ch) >> 49) << 21)
+#define TX4927_SDRAMC_SIZE(ch)	\
+	((((TX4927_SDRAMC_CR(ch) >> 33) & 0x7fff) + 1) << 21)
+
+#define TX4927_EBUSC_CR(ch)	__raw_readq(&tx4927_ebuscptr->cr[(ch)])
+#define TX4927_EBUSC_BA(ch)	((TX4927_EBUSC_CR(ch) >> 48) << 20)
+#define TX4927_EBUSC_SIZE(ch)	\
+	(0x00100000 << ((unsigned long)(TX4927_EBUSC_CR(ch) >> 8) & 0xf))
 
 /* utilities */
 static inline void txx9_clear64(__u64 __iomem *adr, __u64 bits)
@@ -212,6 +242,11 @@
 		       &tx4927_ccfgptr->ccfg);
 }
 
+unsigned int tx4927_get_mem_size(void);
+void tx4927_wdr_init(void);
+void tx4927_setup(void);
+void tx4927_time_init(unsigned int tmrnr);
+void tx4927_setup_serial(void);
 int tx4927_report_pciclk(void);
 int tx4927_pciclk66_setup(void);
 void tx4927_irq_init(void);
diff --git a/include/asm-mips/txx9/tx4938.h b/include/asm-mips/txx9/tx4938.h
index 12de68a..1ed969d 100644
--- a/include/asm-mips/txx9/tx4938.h
+++ b/include/asm-mips/txx9/tx4938.h
@@ -15,20 +15,11 @@
 /* some controllers are compatible with 4927 */
 #include <asm/txx9/tx4927.h>
 
-#define tx4938_read_nfmc(addr) (*(volatile unsigned int *)(addr))
-#define tx4938_write_nfmc(b, addr) (*(volatile unsigned int *)(addr)) = (b)
-
-#define TX4938_PCIIO_0 0x10000000
-#define TX4938_PCIIO_1 0x01010000
-#define TX4938_PCIMEM_0 0x08000000
-#define TX4938_PCIMEM_1 0x11000000
-
-#define TX4938_PCIIO_SIZE_0 0x01000000
-#define TX4938_PCIIO_SIZE_1 0x00010000
-#define TX4938_PCIMEM_SIZE_0 0x08000000
-#define TX4938_PCIMEM_SIZE_1 0x00010000
-
-#define TX4938_REG_BASE	0xff1f0000 /* == TX4937_REG_BASE */
+#ifdef CONFIG_64BIT
+#define TX4938_REG_BASE	0xffffffffff1f0000UL /* == TX4937_REG_BASE */
+#else
+#define TX4938_REG_BASE	0xff1f0000UL /* == TX4937_REG_BASE */
+#endif
 #define TX4938_REG_SIZE	0x00010000 /* == TX4937_REG_SIZE */
 
 /* NDFMC, SRAMC, PCIC1, SPIC: TX4938 only */
@@ -49,149 +40,8 @@
 #define TX4938_ACLC_REG		(TX4938_REG_BASE + 0xf700)
 #define TX4938_SPI_REG		(TX4938_REG_BASE + 0xf800)
 
-#define _CONST64(c)	c##ull
-
-#include <asm/byteorder.h>
-
-#ifdef __BIG_ENDIAN
-#define endian_def_l2(e1, e2)	\
-	volatile unsigned long e1, e2
-#define endian_def_s2(e1, e2)	\
-	volatile unsigned short e1, e2
-#define endian_def_sb2(e1, e2, e3)	\
-	volatile unsigned short e1;volatile unsigned char e2, e3
-#define endian_def_b2s(e1, e2, e3)	\
-	volatile unsigned char e1, e2;volatile unsigned short e3
-#define endian_def_b4(e1, e2, e3, e4)	\
-	volatile unsigned char e1, e2, e3, e4
-#else
-#define endian_def_l2(e1, e2)	\
-	volatile unsigned long e2, e1
-#define endian_def_s2(e1, e2)	\
-	volatile unsigned short e2, e1
-#define endian_def_sb2(e1, e2, e3)	\
-	volatile unsigned char e3, e2;volatile unsigned short e1
-#define endian_def_b2s(e1, e2, e3)	\
-	volatile unsigned short e3;volatile unsigned char e2, e1
-#define endian_def_b4(e1, e2, e3, e4)	\
-	volatile unsigned char e4, e3, e2, e1
-#endif
-
-
-struct tx4938_sdramc_reg {
-	volatile unsigned long long cr[4];
-	volatile unsigned long long unused0[4];
-	volatile unsigned long long tr;
-	volatile unsigned long long unused1[2];
-	volatile unsigned long long cmd;
-	volatile unsigned long long sfcmd;
-};
-
-struct tx4938_ebusc_reg {
-	volatile unsigned long long cr[8];
-};
-
-struct tx4938_dma_reg {
-	struct tx4938_dma_ch_reg {
-		volatile unsigned long long cha;
-		volatile unsigned long long sar;
-		volatile unsigned long long dar;
-		endian_def_l2(unused0, cntr);
-		endian_def_l2(unused1, sair);
-		endian_def_l2(unused2, dair);
-		endian_def_l2(unused3, ccr);
-		endian_def_l2(unused4, csr);
-	} ch[4];
-	volatile unsigned long long dbr[8];
-	volatile unsigned long long tdhr;
-	volatile unsigned long long midr;
-	endian_def_l2(unused0, mcr);
-};
-
-struct tx4938_aclc_reg {
-	volatile unsigned long acctlen;
-	volatile unsigned long acctldis;
-	volatile unsigned long acregacc;
-	volatile unsigned long unused0;
-	volatile unsigned long acintsts;
-	volatile unsigned long acintmsts;
-	volatile unsigned long acinten;
-	volatile unsigned long acintdis;
-	volatile unsigned long acsemaph;
-	volatile unsigned long unused1[7];
-	volatile unsigned long acgpidat;
-	volatile unsigned long acgpodat;
-	volatile unsigned long acslten;
-	volatile unsigned long acsltdis;
-	volatile unsigned long acfifosts;
-	volatile unsigned long unused2[11];
-	volatile unsigned long acdmasts;
-	volatile unsigned long acdmasel;
-	volatile unsigned long unused3[6];
-	volatile unsigned long acaudodat;
-	volatile unsigned long acsurrdat;
-	volatile unsigned long accentdat;
-	volatile unsigned long aclfedat;
-	volatile unsigned long acaudiat;
-	volatile unsigned long unused4;
-	volatile unsigned long acmodoat;
-	volatile unsigned long acmodidat;
-	volatile unsigned long unused5[15];
-	volatile unsigned long acrevid;
-};
-
-
-struct tx4938_tmr_reg {
-	volatile unsigned long tcr;
-	volatile unsigned long tisr;
-	volatile unsigned long cpra;
-	volatile unsigned long cprb;
-	volatile unsigned long itmr;
-	volatile unsigned long unused0[3];
-	volatile unsigned long ccdr;
-	volatile unsigned long unused1[3];
-	volatile unsigned long pgmr;
-	volatile unsigned long unused2[3];
-	volatile unsigned long wtmr;
-	volatile unsigned long unused3[43];
-	volatile unsigned long trr;
-};
-
-struct tx4938_sio_reg {
-	volatile unsigned long lcr;
-	volatile unsigned long dicr;
-	volatile unsigned long disr;
-	volatile unsigned long cisr;
-	volatile unsigned long fcr;
-	volatile unsigned long flcr;
-	volatile unsigned long bgr;
-	volatile unsigned long tfifo;
-	volatile unsigned long rfifo;
-};
-
-struct tx4938_ndfmc_reg {
-	endian_def_l2(unused0, dtr);
-	endian_def_l2(unused1, mcr);
-	endian_def_l2(unused2, sr);
-	endian_def_l2(unused3, isr);
-	endian_def_l2(unused4, imr);
-	endian_def_l2(unused5, spr);
-	endian_def_l2(unused6, rstr);
-};
-
-struct tx4938_spi_reg {
-	volatile unsigned long mcr;
-	volatile unsigned long cr0;
-	volatile unsigned long cr1;
-	volatile unsigned long fs;
-	volatile unsigned long unused1;
-	volatile unsigned long sr;
-	volatile unsigned long dr;
-	volatile unsigned long unused2;
-};
-
 struct tx4938_sramc_reg {
-	volatile unsigned long long cr;
+	u64 cr;
 };
 
 struct tx4938_ccfg_reg {
@@ -209,34 +59,6 @@
 	u64 jmpadr;
 };
 
-#undef endian_def_l2
-#undef endian_def_s2
-#undef endian_def_sb2
-#undef endian_def_b2s
-#undef endian_def_b4
-
-/*
- * NDFMC
- */
-
-/* NDFMCR : NDFMC Mode Control */
-#define TX4938_NDFMCR_WE	0x80
-#define TX4938_NDFMCR_ECC_ALL	0x60
-#define TX4938_NDFMCR_ECC_RESET	0x60
-#define TX4938_NDFMCR_ECC_READ	0x40
-#define TX4938_NDFMCR_ECC_ON	0x20
-#define TX4938_NDFMCR_ECC_OFF	0x00
-#define TX4938_NDFMCR_CE	0x10
-#define TX4938_NDFMCR_BSPRT	0x04
-#define TX4938_NDFMCR_ALE	0x02
-#define TX4938_NDFMCR_CLE	0x01
-
-/* NDFMCR : NDFMC Status */
-#define TX4938_NDFSR_BUSY	0x80
-
-/* NDFMCR : NDFMC Reset */
-#define TX4938_NDFRSTR_RST	0x01
-
 /*
  * IRC
  */
@@ -268,13 +90,15 @@
 
 #define TX4938_IRC_INT	2	/* IP[2] in Status register */
 
+#define TX4938_NUM_PIO	16
+
 /*
  * CCFG
  */
 /* CCFG : Chip Configuration */
-#define TX4938_CCFG_WDRST	_CONST64(0x0000020000000000)
-#define TX4938_CCFG_WDREXEN	_CONST64(0x0000010000000000)
-#define TX4938_CCFG_BCFG_MASK	_CONST64(0x000000ff00000000)
+#define TX4938_CCFG_WDRST	0x0000020000000000ULL
+#define TX4938_CCFG_WDREXEN	0x0000010000000000ULL
+#define TX4938_CCFG_BCFG_MASK	0x000000ff00000000ULL
 #define TX4938_CCFG_TINTDIS	0x01000000
 #define TX4938_CCFG_PCI66	0x00800000
 #define TX4938_CCFG_PCIMODE	0x00400000
@@ -310,12 +134,12 @@
 #define TX4938_CCFG_ACEHOLD	0x00000001
 
 /* PCFG : Pin Configuration */
-#define TX4938_PCFG_ETH0_SEL	_CONST64(0x8000000000000000)
-#define TX4938_PCFG_ETH1_SEL	_CONST64(0x4000000000000000)
-#define TX4938_PCFG_ATA_SEL	_CONST64(0x2000000000000000)
-#define TX4938_PCFG_ISA_SEL	_CONST64(0x1000000000000000)
-#define TX4938_PCFG_SPI_SEL	_CONST64(0x0800000000000000)
-#define TX4938_PCFG_NDF_SEL	_CONST64(0x0400000000000000)
+#define TX4938_PCFG_ETH0_SEL	0x8000000000000000ULL
+#define TX4938_PCFG_ETH1_SEL	0x4000000000000000ULL
+#define TX4938_PCFG_ATA_SEL	0x2000000000000000ULL
+#define TX4938_PCFG_ISA_SEL	0x1000000000000000ULL
+#define TX4938_PCFG_SPI_SEL	0x0800000000000000ULL
+#define TX4938_PCFG_NDF_SEL	0x0400000000000000ULL
 #define TX4938_PCFG_SDCLKDLY_MASK	0x30000000
 #define TX4938_PCFG_SDCLKDLY(d)	((d)<<28)
 #define TX4938_PCFG_SYSCLKEN	0x08000000
@@ -336,8 +160,8 @@
 #define TX4938_PCFG_DMASEL3_SIO0	0x00000008
 
 /* CLKCTR : Clock Control */
-#define TX4938_CLKCTR_NDFCKD	_CONST64(0x0001000000000000)
-#define TX4938_CLKCTR_NDFRST	_CONST64(0x0000000100000000)
+#define TX4938_CLKCTR_NDFCKD	0x0001000000000000ULL
+#define TX4938_CLKCTR_NDFRST	0x0000000100000000ULL
 #define TX4938_CLKCTR_ETH1CKD	0x80000000
 #define TX4938_CLKCTR_ETH0CKD	0x40000000
 #define TX4938_CLKCTR_SPICKD	0x20000000
@@ -424,20 +248,16 @@
 #define TX4938_DMA_CSR_DESERR	0x00000002
 #define TX4938_DMA_CSR_SORERR	0x00000001
 
-#define tx4938_sdramcptr	((struct tx4938_sdramc_reg *)TX4938_SDRAMC_REG)
-#define tx4938_ebuscptr         ((struct tx4938_ebusc_reg *)TX4938_EBUSC_REG)
-#define tx4938_dmaptr(ch)	((struct tx4938_dma_reg *)TX4938_DMA_REG(ch))
-#define tx4938_ndfmcptr		((struct tx4938_ndfmc_reg *)TX4938_NDFMC_REG)
+#define tx4938_sdramcptr	tx4927_sdramcptr
+#define tx4938_ebuscptr		tx4927_ebuscptr
 #define tx4938_pcicptr		tx4927_pcicptr
 #define tx4938_pcic1ptr \
 		((struct tx4927_pcic_reg __iomem *)TX4938_PCIC1_REG)
 #define tx4938_ccfgptr \
 		((struct tx4938_ccfg_reg __iomem *)TX4938_CCFG_REG)
-#define tx4938_sioptr(ch)	((struct tx4938_sio_reg *)TX4938_SIO_REG(ch))
 #define tx4938_pioptr		((struct txx9_pio_reg __iomem *)TX4938_PIO_REG)
-#define tx4938_aclcptr		((struct tx4938_aclc_reg *)TX4938_ACLC_REG)
-#define tx4938_spiptr		((struct tx4938_spi_reg *)TX4938_SPI_REG)
-#define tx4938_sramcptr		((struct tx4938_sramc_reg *)TX4938_SRAMC_REG)
+#define tx4938_sramcptr \
+		((struct tx4938_sramc_reg __iomem *)TX4938_SRAMC_REG)
 
 
 #define TX4938_REV_PCODE()	\
@@ -447,14 +267,19 @@
 #define tx4938_ccfg_set(bits)	tx4927_ccfg_set(bits)
 #define tx4938_ccfg_change(change, new)	tx4927_ccfg_change(change, new)
 
-#define TX4938_SDRAMC_BA(ch)	((tx4938_sdramcptr->cr[ch] >> 49) << 21)
-#define TX4938_SDRAMC_SIZE(ch)	(((tx4938_sdramcptr->cr[ch] >> 33) + 1) << 21)
+#define TX4938_SDRAMC_CR(ch)	TX4927_SDRAMC_CR(ch)
+#define TX4938_SDRAMC_BA(ch)	TX4927_SDRAMC_BA(ch)
+#define TX4938_SDRAMC_SIZE(ch)	TX4927_SDRAMC_SIZE(ch)
 
-#define TX4938_EBUSC_CR(ch)	__raw_readq(&tx4938_ebuscptr->cr[(ch)])
-#define TX4938_EBUSC_BA(ch)	((tx4938_ebuscptr->cr[ch] >> 48) << 20)
-#define TX4938_EBUSC_SIZE(ch)	\
-	(0x00100000 << ((unsigned long)(tx4938_ebuscptr->cr[ch] >> 8) & 0xf))
+#define TX4938_EBUSC_CR(ch)	TX4927_EBUSC_CR(ch)
+#define TX4938_EBUSC_BA(ch)	TX4927_EBUSC_BA(ch)
+#define TX4938_EBUSC_SIZE(ch)	TX4927_EBUSC_SIZE(ch)
 
+#define tx4938_get_mem_size() tx4927_get_mem_size()
+void tx4938_wdr_init(void);
+void tx4938_setup(void);
+void tx4938_time_init(unsigned int tmrnr);
+void tx4938_setup_serial(void);
 int tx4938_report_pciclk(void);
 void tx4938_report_pci1clk(void);
 int tx4938_pciclk66_setup(void);
diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h
index 81a69d7..2655e2a 100644
--- a/include/asm-powerpc/kvm_host.h
+++ b/include/asm-powerpc/kvm_host.h
@@ -31,6 +31,8 @@
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
 
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
 /* We don't currently support large pages. */
 #define KVM_PAGES_PER_HPAGE (1<<31)
 
diff --git a/include/asm-s390/kvm_host.h b/include/asm-s390/kvm_host.h
index 18cbd8a..3234dd5 100644
--- a/include/asm-s390/kvm_host.h
+++ b/include/asm-s390/kvm_host.h
@@ -62,7 +62,7 @@
 #define CPUSTAT_J          0x00000002
 #define CPUSTAT_P          0x00000001
 
-struct sie_block {
+struct kvm_s390_sie_block {
 	atomic_t cpuflags;		/* 0x0000 */
 	__u32	prefix;			/* 0x0004 */
 	__u8	reserved8[32];		/* 0x0008 */
@@ -140,14 +140,14 @@
 	u32 diagnose_44;
 };
 
-struct io_info {
+struct kvm_s390_io_info {
 	__u16        subchannel_id;            /* 0x0b8 */
 	__u16        subchannel_nr;            /* 0x0ba */
 	__u32        io_int_parm;              /* 0x0bc */
 	__u32        io_int_word;              /* 0x0c0 */
 };
 
-struct ext_info {
+struct kvm_s390_ext_info {
 	__u32 ext_params;
 	__u64 ext_params2;
 };
@@ -160,22 +160,22 @@
 #define PGM_SPECIFICATION        0x06
 #define PGM_DATA                 0x07
 
-struct pgm_info {
+struct kvm_s390_pgm_info {
 	__u16 code;
 };
 
-struct prefix_info {
+struct kvm_s390_prefix_info {
 	__u32 address;
 };
 
-struct interrupt_info {
+struct kvm_s390_interrupt_info {
 	struct list_head list;
 	u64	type;
 	union {
-		struct io_info io;
-		struct ext_info ext;
-		struct pgm_info pgm;
-		struct prefix_info prefix;
+		struct kvm_s390_io_info io;
+		struct kvm_s390_ext_info ext;
+		struct kvm_s390_pgm_info pgm;
+		struct kvm_s390_prefix_info prefix;
 	};
 };
 
@@ -183,35 +183,35 @@
 #define ACTION_STORE_ON_STOP 1
 #define ACTION_STOP_ON_STOP  2
 
-struct local_interrupt {
+struct kvm_s390_local_interrupt {
 	spinlock_t lock;
 	struct list_head list;
 	atomic_t active;
-	struct float_interrupt *float_int;
+	struct kvm_s390_float_interrupt *float_int;
 	int timer_due; /* event indicator for waitqueue below */
 	wait_queue_head_t wq;
 	atomic_t *cpuflags;
 	unsigned int action_bits;
 };
 
-struct float_interrupt {
+struct kvm_s390_float_interrupt {
 	spinlock_t lock;
 	struct list_head list;
 	atomic_t active;
 	int next_rr_cpu;
 	unsigned long idle_mask [(64 + sizeof(long) - 1) / sizeof(long)];
-	struct local_interrupt *local_int[64];
+	struct kvm_s390_local_interrupt *local_int[64];
 };
 
 
 struct kvm_vcpu_arch {
-	struct sie_block *sie_block;
+	struct kvm_s390_sie_block *sie_block;
 	unsigned long	  guest_gprs[16];
 	s390_fp_regs      host_fpregs;
 	unsigned int      host_acrs[NUM_ACRS];
 	s390_fp_regs      guest_fpregs;
 	unsigned int      guest_acrs[NUM_ACRS];
-	struct local_interrupt local_int;
+	struct kvm_s390_local_interrupt local_int;
 	struct timer_list ckc_timer;
 	union  {
 		cpuid_t	  cpu_id;
@@ -228,8 +228,8 @@
 	unsigned long guest_memsize;
 	struct sca_block *sca;
 	debug_info_t *dbf;
-	struct float_interrupt float_int;
+	struct kvm_s390_float_interrupt float_int;
 };
 
-extern int sie64a(struct sie_block *, __u64 *);
+extern int sie64a(struct kvm_s390_sie_block *, __u64 *);
 #endif
diff --git a/include/asm-x86/kvm.h b/include/asm-x86/kvm.h
index 80eefef2..6f18408 100644
--- a/include/asm-x86/kvm.h
+++ b/include/asm-x86/kvm.h
@@ -228,5 +228,6 @@
 #define KVM_TRC_CLTS             (KVM_TRC_HANDLER + 0x12)
 #define KVM_TRC_LMSW             (KVM_TRC_HANDLER + 0x13)
 #define KVM_TRC_APIC_ACCESS      (KVM_TRC_HANDLER + 0x14)
+#define KVM_TRC_TDP_FAULT        (KVM_TRC_HANDLER + 0x15)
 
 #endif
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 844f2a8..f995783 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -27,6 +27,7 @@
 #define KVM_PRIVATE_MEM_SLOTS 4
 
 #define KVM_PIO_PAGE_OFFSET 1
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
 
 #define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
 #define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
@@ -79,6 +80,7 @@
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 40
+#define KVM_NR_VAR_MTRR 8
 
 extern spinlock_t kvm_lock;
 extern struct list_head vm_list;
@@ -109,12 +111,12 @@
 };
 
 enum {
-	VCPU_SREG_CS,
-	VCPU_SREG_DS,
 	VCPU_SREG_ES,
+	VCPU_SREG_CS,
+	VCPU_SREG_SS,
+	VCPU_SREG_DS,
 	VCPU_SREG_FS,
 	VCPU_SREG_GS,
-	VCPU_SREG_SS,
 	VCPU_SREG_TR,
 	VCPU_SREG_LDTR,
 };
@@ -243,6 +245,7 @@
 	gfn_t last_pt_write_gfn;
 	int   last_pt_write_count;
 	u64  *last_pte_updated;
+	gfn_t last_pte_gfn;
 
 	struct {
 		gfn_t gfn;	/* presumed gfn during guest pte update */
@@ -287,6 +290,10 @@
 	unsigned int hv_clock_tsc_khz;
 	unsigned int time_offset;
 	struct page *time_page;
+
+	bool nmi_pending;
+
+	u64 mtrr[0x100];
 };
 
 struct kvm_mem_alias {
@@ -344,6 +351,7 @@
 	u32 mmio_exits;
 	u32 signal_exits;
 	u32 irq_window_exits;
+	u32 nmi_window_exits;
 	u32 halt_exits;
 	u32 halt_wakeup;
 	u32 request_irq_exits;
@@ -379,7 +387,6 @@
 	void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
 	void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
 	void (*vcpu_put)(struct kvm_vcpu *vcpu);
-	void (*vcpu_decache)(struct kvm_vcpu *vcpu);
 
 	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
 			       struct kvm_debug_guest *dbg);
@@ -497,6 +504,10 @@
 int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
 		    unsigned long value);
 
+void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
+int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+				int type_bits, int seg);
+
 int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason);
 
 void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
@@ -515,6 +526,8 @@
 void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
 			   u32 error_code);
 
+void kvm_inject_nmi(struct kvm_vcpu *vcpu);
+
 void fx_init(struct kvm_vcpu *vcpu);
 
 int emulator_read_std(unsigned long addr,
@@ -554,55 +567,53 @@
 	return (struct kvm_mmu_page *)page_private(page);
 }
 
-static inline u16 read_fs(void)
+static inline u16 kvm_read_fs(void)
 {
 	u16 seg;
 	asm("mov %%fs, %0" : "=g"(seg));
 	return seg;
 }
 
-static inline u16 read_gs(void)
+static inline u16 kvm_read_gs(void)
 {
 	u16 seg;
 	asm("mov %%gs, %0" : "=g"(seg));
 	return seg;
 }
 
-static inline u16 read_ldt(void)
+static inline u16 kvm_read_ldt(void)
 {
 	u16 ldt;
 	asm("sldt %0" : "=g"(ldt));
 	return ldt;
 }
 
-static inline void load_fs(u16 sel)
+static inline void kvm_load_fs(u16 sel)
 {
 	asm("mov %0, %%fs" : : "rm"(sel));
 }
 
-static inline void load_gs(u16 sel)
+static inline void kvm_load_gs(u16 sel)
 {
 	asm("mov %0, %%gs" : : "rm"(sel));
 }
 
-#ifndef load_ldt
-static inline void load_ldt(u16 sel)
+static inline void kvm_load_ldt(u16 sel)
 {
 	asm("lldt %0" : : "rm"(sel));
 }
-#endif
 
-static inline void get_idt(struct descriptor_table *table)
+static inline void kvm_get_idt(struct descriptor_table *table)
 {
 	asm("sidt %0" : "=m"(*table));
 }
 
-static inline void get_gdt(struct descriptor_table *table)
+static inline void kvm_get_gdt(struct descriptor_table *table)
 {
 	asm("sgdt %0" : "=m"(*table));
 }
 
-static inline unsigned long read_tr_base(void)
+static inline unsigned long kvm_read_tr_base(void)
 {
 	u16 tr;
 	asm("str %0" : "=g"(tr));
@@ -619,17 +630,17 @@
 }
 #endif
 
-static inline void fx_save(struct i387_fxsave_struct *image)
+static inline void kvm_fx_save(struct i387_fxsave_struct *image)
 {
 	asm("fxsave (%0)":: "r" (image));
 }
 
-static inline void fx_restore(struct i387_fxsave_struct *image)
+static inline void kvm_fx_restore(struct i387_fxsave_struct *image)
 {
 	asm("fxrstor (%0)":: "r" (image));
 }
 
-static inline void fx_finit(void)
+static inline void kvm_fx_finit(void)
 {
 	asm("finit");
 }
@@ -691,4 +702,28 @@
 	trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
 						vcpu, 0, 0, 0, 0, 0, 0)
 
+#ifdef CONFIG_64BIT
+#define KVM_EX_ENTRY ".quad"
+#else
+#define KVM_EX_ENTRY ".long"
+#endif
+
+/*
+ * Hardware virtualization extension instructions may fault if a
+ * reboot turns off virtualization while processes are running.
+ * Trap the fault and ignore the instruction if that happens.
+ */
+asmlinkage void kvm_handle_fault_on_reboot(void);
+
+#define __kvm_handle_fault_on_reboot(insn) \
+	"666: " insn "\n\t" \
+	".pushsection .text.fixup, \"ax\" \n" \
+	"667: \n\t" \
+	"push $666b \n\t" \
+	"jmp kvm_handle_fault_on_reboot \n\t" \
+	".popsection \n\t" \
+	".pushsection __ex_table, \"a\" \n\t" \
+	KVM_EX_ENTRY " 666b, 667b \n\t" \
+	".popsection"
+
 #endif
diff --git a/include/asm-x86/kvm_x86_emulate.h b/include/asm-x86/kvm_x86_emulate.h
index b877bbd..4e8c1e4 100644
--- a/include/asm-x86/kvm_x86_emulate.h
+++ b/include/asm-x86/kvm_x86_emulate.h
@@ -124,7 +124,8 @@
 	u8 rex_prefix;
 	struct operand src;
 	struct operand dst;
-	unsigned long *override_base;
+	bool has_seg_override;
+	u8 seg_override;
 	unsigned int d;
 	unsigned long regs[NR_VCPU_REGS];
 	unsigned long eip;
@@ -134,6 +135,7 @@
 	u8 modrm_reg;
 	u8 modrm_rm;
 	u8 use_modrm_ea;
+	bool rip_relative;
 	unsigned long modrm_ea;
 	void *modrm_ptr;
 	unsigned long modrm_val;
@@ -150,12 +152,7 @@
 	/* Emulated execution mode, represented by an X86EMUL_MODE value. */
 	int mode;
 
-	unsigned long cs_base;
-	unsigned long ds_base;
-	unsigned long es_base;
-	unsigned long ss_base;
-	unsigned long gs_base;
-	unsigned long fs_base;
+	u32 cs_base;
 
 	/* decode cache */
 
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 0488f93..d62c19f 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -148,7 +148,8 @@
  * items.  If the item is a group, it may support mkdir(2).
  * Groups supply one of make_group() and make_item().  If the
  * group supports make_group(), one can create group children.  If it
- * supports make_item(), one can create config_item children.  If it has
+ * supports make_item(), one can create config_item children.  make_group()
+ * and make_item() return ERR_PTR() on errors.  If it has
  * default_groups on group->default_groups, it has automatically created
  * group children.  default_groups may coexist alongsize make_group() or
  * make_item(), but if the group wishes to have only default_groups
@@ -165,8 +166,8 @@
 };
 
 struct configfs_group_operations {
-	int (*make_item)(struct config_group *group, const char *name, struct config_item **new_item);
-	int (*make_group)(struct config_group *group, const char *name, struct config_group **new_group);
+	struct config_item *(*make_item)(struct config_group *group, const char *name);
+	struct config_group *(*make_group)(struct config_group *group, const char *name);
 	int (*commit_item)(struct config_item *item);
 	void (*disconnect_notify)(struct config_group *group, struct config_item *item);
 	void (*drop_item)(struct config_group *group, struct config_item *item);
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index 504cb2c..2d3d1e0 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -550,11 +550,11 @@
 
 struct cyclades_port {
 	int                     magic;
+	struct tty_port		port;
 	struct cyclades_card	*card;
 	int			line;
 	int			flags; 		/* defined in tty.h */
 	int                     type;		/* UART type */
-	struct tty_struct 	*tty;
 	int			read_status_mask;
 	int			ignore_status_mask;
 	int			timeout;
@@ -567,13 +567,8 @@
 	int			chip_rev;
 	int			custom_divisor;
 	u8			x_char; /* to be pushed out ASAP */
-	int			close_delay;
-	unsigned short		closing_wait;
-	int			count;	/* # of fd on device */
 	int                     breakon;
 	int                     breakoff;
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
@@ -583,16 +578,14 @@
 	struct cyclades_monitor	mon;
 	struct cyclades_idle_stats	idle_stats;
 	struct cyclades_icount	icount;
-	wait_queue_head_t       open_wait;
-	wait_queue_head_t       close_wait;
 	struct completion       shutdown_wait;
 	wait_queue_head_t       delta_msr_wait;
 	int throttle;
 };
 
 #define	CLOSING_WAIT_DELAY	30*HZ
-#define CY_CLOSING_WAIT_NONE	65535
-#define CY_CLOSING_WAIT_INF	0
+#define CY_CLOSING_WAIT_NONE	ASYNC_CLOSING_WAIT_NONE
+#define CY_CLOSING_WAIT_INF	ASYNC_CLOSING_WAIT_INF
 
 
 #define CyMAX_CHIPS_PER_CARD	8
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index 1108336..4cc9139 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -14,6 +14,7 @@
 
 #ifdef __KERNEL__
 #include <linux/mutex.h>
+#include <linux/tty.h>
 
 struct real_driver {
   void                    (*disable_tx_interrupts) (void *);
@@ -33,17 +34,12 @@
 
 struct gs_port {
   int                     magic;
+  struct tty_port	  port;
   unsigned char           *xmit_buf; 
   int                     xmit_head;
   int                     xmit_tail;
   int                     xmit_cnt;
   struct mutex            port_write_mutex;
-  int                     flags;
-  wait_queue_head_t       open_wait;
-  wait_queue_head_t       close_wait;
-  int                     count;
-  int                     blocked_open;
-  struct tty_struct       *tty;
   unsigned long           event;
   unsigned short          closing_wait;
   int                     close_delay;
diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h
index 2177ee5..940aeb5 100644
--- a/include/linux/hayesesp.h
+++ b/include/linux/hayesesp.h
@@ -76,11 +76,10 @@
 
 struct esp_struct {
 	int			magic;
+	struct tty_port		port;
 	spinlock_t		lock;
-	int			port;
+	int			io_port;
 	int			irq;
-	int			flags; 		/* defined in tty.h */
-	struct tty_struct 	*tty;
 	int			read_status_mask;
 	int			ignore_status_mask;
 	int			timeout;
@@ -93,14 +92,10 @@
 	int			MCR; 	/* Modem control register */
 	unsigned long		last_active;
 	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
 	wait_queue_head_t	delta_msr_wait;
 	wait_queue_head_t	break_wait;
 	struct async_icount	icount;	/* kernel counters for the 4 input interrupts */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index ef13b7c6..4862398 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -33,15 +33,11 @@
 
 #define I2C_DRIVERID_MSP3400	 1
 #define I2C_DRIVERID_TUNER	 2
-#define I2C_DRIVERID_TDA8425	 4	/* stereo sound processor	*/
 #define I2C_DRIVERID_TEA6420	 5	/* audio matrix switch		*/
 #define I2C_DRIVERID_TEA6415C	 6	/* video matrix switch		*/
 #define I2C_DRIVERID_TDA9840	 7	/* stereo sound processor	*/
 #define I2C_DRIVERID_SAA7111A	 8	/* video input processor	*/
 #define I2C_DRIVERID_SAA7185B	13	/* video encoder		*/
-#define I2C_DRIVERID_TEA6300	18	/* audio mixer			*/
-#define I2C_DRIVERID_TDA9850	20	/* audio mixer			*/
-#define I2C_DRIVERID_TDA9855	21	/* audio mixer			*/
 #define I2C_DRIVERID_SAA7110	22	/* video decoder		*/
 #define I2C_DRIVERID_MGATVO	23	/* Matrox TVOut			*/
 #define I2C_DRIVERID_SAA5249	24	/* SAA5249 and compatibles	*/
@@ -50,9 +46,7 @@
 #define I2C_DRIVERID_TDA7432	27	/* Stereo sound processor	*/
 #define I2C_DRIVERID_TVMIXER    28      /* Mixer driver for tv cards    */
 #define I2C_DRIVERID_TVAUDIO    29      /* Generic TV sound driver      */
-#define I2C_DRIVERID_TDA9873    31      /* TV sound decoder chip        */
 #define I2C_DRIVERID_TDA9875    32      /* TV sound decoder chip        */
-#define I2C_DRIVERID_PIC16C54_PV9 33    /* Audio mux/ir receiver        */
 #define I2C_DRIVERID_BT819	40     /* video decoder			*/
 #define I2C_DRIVERID_BT856	41     /* video encoder			*/
 #define I2C_DRIVERID_VPX3220	42     /* video decoder+vbi/vtxt	*/
@@ -63,7 +57,6 @@
 #define I2C_DRIVERID_INDYCAM	58	/* SGI IndyCam			*/
 #define I2C_DRIVERID_OVCAMCHIP	61	/* OmniVision CMOS image sens.	*/
 #define I2C_DRIVERID_MAX6900	63	/* MAX6900 real-time clock	*/
-#define I2C_DRIVERID_TDA9874	66	/* TV sound decoder		*/
 #define I2C_DRIVERID_SAA6752HS	67	/* MPEG2 encoder		*/
 #define I2C_DRIVERID_TVEEPROM	68	/* TV EEPROM			*/
 #define I2C_DRIVERID_WM8775	69	/* wm8775 audio processor	*/
@@ -158,7 +151,6 @@
 #define I2C_HW_SMBUS_W9968CF	0x04000d
 #define I2C_HW_SMBUS_OV511	0x04000e /* OV511(+) USB 1.1 webcam ICs */
 #define I2C_HW_SMBUS_OV518	0x04000f /* OV518(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_OVFX2	0x040011 /* Cypress/OmniVision FX2 webcam */
 #define I2C_HW_SMBUS_CAFE	0x040012 /* Marvell 88ALP01 "CAFE" cam  */
 #define I2C_HW_SMBUS_ALI1563	0x040013
 
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
index 5a84fe9..0d18407 100644
--- a/include/linux/istallion.h
+++ b/include/linux/istallion.h
@@ -51,25 +51,21 @@
  */
 struct stliport {
 	unsigned long		magic;
+	struct tty_port		port;
 	unsigned int		portnr;
 	unsigned int		panelnr;
 	unsigned int		brdnr;
 	unsigned long		state;
 	unsigned int		devnr;
-	int			flags;
 	int			baud_base;
 	int			custom_divisor;
 	int			close_delay;
 	int			closing_wait;
-	int			refcount;
 	int			openwaitcnt;
 	int			rc;
 	int			argsize;
 	void			*argp;
 	unsigned int		rxmarkmsk;
-	struct tty_struct	*tty;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
 	wait_queue_head_t	raw_wait;
 	struct asysigs		asig;
 	unsigned long		addr;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index a281afe..0ea064c 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -173,6 +173,30 @@
 	};
 };
 
+/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
+
+struct kvm_coalesced_mmio_zone {
+	__u64 addr;
+	__u32 size;
+	__u32 pad;
+};
+
+struct kvm_coalesced_mmio {
+	__u64 phys_addr;
+	__u32 len;
+	__u32 pad;
+	__u8  data[8];
+};
+
+struct kvm_coalesced_mmio_ring {
+	__u32 first, last;
+	struct kvm_coalesced_mmio coalesced_mmio[0];
+};
+
+#define KVM_COALESCED_MMIO_MAX \
+	((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
+	 sizeof(struct kvm_coalesced_mmio))
+
 /* for KVM_TRANSLATE */
 struct kvm_translation {
 	/* in */
@@ -294,14 +318,14 @@
 	__u32 vcpu_id;
 	union {
 		struct {
-			__u32 cycle_lo, cycle_hi;
+			__u64 cycle_u64;
 			__u32 extra_u32[KVM_TRC_EXTRA_MAX];
 		} cycle;
 		struct {
 			__u32 extra_u32[KVM_TRC_EXTRA_MAX];
 		} nocycle;
 	} u;
-};
+} __attribute__((packed));
 
 #define KVMIO 0xAE
 
@@ -346,6 +370,7 @@
 #define KVM_CAP_NOP_IO_DELAY 12
 #define KVM_CAP_PV_MMU 13
 #define KVM_CAP_MP_STATE 14
+#define KVM_CAP_COALESCED_MMIO 15
 
 /*
  * ioctls for VM fds
@@ -371,6 +396,10 @@
 #define KVM_CREATE_PIT		  _IO(KVMIO,  0x64)
 #define KVM_GET_PIT		  _IOWR(KVMIO, 0x65, struct kvm_pit_state)
 #define KVM_SET_PIT		  _IOR(KVMIO,  0x66, struct kvm_pit_state)
+#define KVM_REGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
+#define KVM_UNREGISTER_COALESCED_MMIO \
+			_IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
 
 /*
  * ioctls for vcpu fds
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index de9d1df..07d68a8 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -52,7 +52,8 @@
 
 void kvm_io_bus_init(struct kvm_io_bus *bus);
 void kvm_io_bus_destroy(struct kvm_io_bus *bus);
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
+					  gpa_t addr, int len, int is_write);
 void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 			     struct kvm_io_device *dev);
 
@@ -116,6 +117,10 @@
 	struct kvm_vm_stat stat;
 	struct kvm_arch arch;
 	atomic_t users_count;
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	struct kvm_coalesced_mmio_dev *coalesced_mmio_dev;
+	struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+#endif
 };
 
 /* The guest did something we don't support. */
@@ -135,9 +140,6 @@
 void vcpu_load(struct kvm_vcpu *vcpu);
 void vcpu_put(struct kvm_vcpu *vcpu);
 
-void decache_vcpus_on_cpu(int cpu);
-
-
 int kvm_init(void *opaque, unsigned int vcpu_size,
 		  struct module *module);
 void kvm_exit(void);
@@ -166,6 +168,7 @@
 				struct kvm_userspace_memory_region *mem,
 				struct kvm_memory_slot old,
 				int user_alloc);
+void kvm_arch_flush_shadow(struct kvm *kvm);
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
 unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index 4ab2162..322cd6d 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  *
  * Copyright 2001 Compaq Computer Corporation.
- * Copyright 2007 OpendHand.
+ * Copyright 2007-2008 OpenedHand Ltd.
  */
 
 #ifndef __ASIC3_H__
@@ -16,43 +16,22 @@
 
 #include <linux/types.h>
 
-struct asic3 {
-	void __iomem *mapping;
-	unsigned int bus_shift;
-	unsigned int irq_nr;
-	unsigned int irq_base;
-	spinlock_t lock;
-	u16 irq_bothedge[4];
-	struct device *dev;
-};
-
 struct asic3_platform_data {
-	struct {
-		u32 dir;
-		u32 init;
-		u32 sleep_mask;
-		u32 sleep_out;
-		u32 batt_fault_out;
-		u32 sleep_conf;
-		u32 alt_function;
-	} gpio_a, gpio_b, gpio_c, gpio_d;
-
-	unsigned int bus_shift;
+	u16 *gpio_config;
+	unsigned int gpio_config_num;
 
 	unsigned int irq_base;
 
-	struct platform_device **children;
-	unsigned int n_children;
+	unsigned int gpio_base;
 };
 
-int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio);
-void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val);
-
 #define ASIC3_NUM_GPIO_BANKS	4
 #define ASIC3_GPIOS_PER_BANK	16
 #define ASIC3_NUM_GPIOS		64
 #define ASIC3_NR_IRQS		ASIC3_NUM_GPIOS + 6
 
+#define ASIC3_TO_GPIO(gpio) (NR_BUILTIN_GPIO + (gpio))
+
 #define ASIC3_GPIO_BANK_A	0
 #define ASIC3_GPIO_BANK_B	1
 #define ASIC3_GPIO_BANK_C	2
@@ -64,32 +43,89 @@
 /* All offsets below are specified with this address bus shift */
 #define ASIC3_DEFAULT_ADDR_SHIFT 2
 
-#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_Base + ASIC3_##base##_##reg)
+#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_BASE + ASIC3_##base##_##reg)
 #define ASIC3_GPIO_OFFSET(base, reg) \
-	(ASIC3_GPIO_##base##_Base + ASIC3_GPIO_##reg)
+	(ASIC3_GPIO_##base##_BASE + ASIC3_GPIO_##reg)
 
-#define ASIC3_GPIO_A_Base      0x0000
-#define ASIC3_GPIO_B_Base      0x0100
-#define ASIC3_GPIO_C_Base      0x0200
-#define ASIC3_GPIO_D_Base      0x0300
+#define ASIC3_GPIO_A_BASE      0x0000
+#define ASIC3_GPIO_B_BASE      0x0100
+#define ASIC3_GPIO_C_BASE      0x0200
+#define ASIC3_GPIO_D_BASE      0x0300
 
-#define ASIC3_GPIO_Mask          0x00    /* R/W 0:don't mask */
-#define ASIC3_GPIO_Direction     0x04    /* R/W 0:input */
-#define ASIC3_GPIO_Out           0x08    /* R/W 0:output low */
-#define ASIC3_GPIO_TriggerType   0x0c    /* R/W 0:level */
-#define ASIC3_GPIO_EdgeTrigger   0x10    /* R/W 0:falling */
-#define ASIC3_GPIO_LevelTrigger  0x14    /* R/W 0:low level detect */
-#define ASIC3_GPIO_SleepMask     0x18    /* R/W 0:don't mask in sleep mode */
-#define ASIC3_GPIO_SleepOut      0x1c    /* R/W level 0:low in sleep mode */
-#define ASIC3_GPIO_BattFaultOut  0x20    /* R/W level 0:low in batt_fault */
-#define ASIC3_GPIO_IntStatus     0x24    /* R/W 0:none, 1:detect */
-#define ASIC3_GPIO_AltFunction   0x28	 /* R/W 1:LED register control */
-#define ASIC3_GPIO_SleepConf     0x2c    /*
+#define ASIC3_GPIO_TO_BANK(gpio) ((gpio) >> 4)
+#define ASIC3_GPIO_TO_BIT(gpio)  ((gpio) - \
+				  (ASIC3_GPIOS_PER_BANK * ((gpio) >> 4)))
+#define ASIC3_GPIO_TO_MASK(gpio) (1 << ASIC3_GPIO_TO_BIT(gpio))
+#define ASIC3_GPIO_TO_BASE(gpio) (ASIC3_GPIO_A_BASE + (((gpio) >> 4) * 0x0100))
+#define ASIC3_BANK_TO_BASE(bank) (ASIC3_GPIO_A_BASE + ((bank) * 0x100))
+
+#define ASIC3_GPIO_MASK          0x00    /* R/W 0:don't mask */
+#define ASIC3_GPIO_DIRECTION     0x04    /* R/W 0:input */
+#define ASIC3_GPIO_OUT           0x08    /* R/W 0:output low */
+#define ASIC3_GPIO_TRIGGER_TYPE  0x0c    /* R/W 0:level */
+#define ASIC3_GPIO_EDGE_TRIGGER  0x10    /* R/W 0:falling */
+#define ASIC3_GPIO_LEVEL_TRIGGER 0x14    /* R/W 0:low level detect */
+#define ASIC3_GPIO_SLEEP_MASK    0x18    /* R/W 0:don't mask in sleep mode */
+#define ASIC3_GPIO_SLEEP_OUT     0x1c    /* R/W level 0:low in sleep mode */
+#define ASIC3_GPIO_BAT_FAULT_OUT 0x20    /* R/W level 0:low in batt_fault */
+#define ASIC3_GPIO_INT_STATUS    0x24    /* R/W 0:none, 1:detect */
+#define ASIC3_GPIO_ALT_FUNCTION  0x28	 /* R/W 1:LED register control */
+#define ASIC3_GPIO_SLEEP_CONF    0x2c    /*
 					  * R/W bit 1: autosleep
 					  * 0: disable gposlpout in normal mode,
 					  * enable gposlpout in sleep mode.
 					  */
-#define ASIC3_GPIO_Status        0x30    /* R   Pin status */
+#define ASIC3_GPIO_STATUS        0x30    /* R   Pin status */
+
+/*
+ * ASIC3 GPIO config
+ *
+ * Bits 0..6   gpio number
+ * Bits 7..13  Alternate function
+ * Bit  14     Direction
+ * Bit  15     Initial value
+ *
+ */
+#define ASIC3_CONFIG_GPIO_PIN(config) ((config) & 0x7f)
+#define ASIC3_CONFIG_GPIO_ALT(config)  (((config) & (0x7f << 7)) >> 7)
+#define ASIC3_CONFIG_GPIO_DIR(config)  ((config & (1 << 14)) >> 14)
+#define ASIC3_CONFIG_GPIO_INIT(config) ((config & (1 << 15)) >> 15)
+#define ASIC3_CONFIG_GPIO(gpio, alt, dir, init) (((gpio) & 0x7f) \
+	| (((alt) & 0x7f) << 7) | (((dir) & 0x1) << 14) \
+	| (((init) & 0x1) << 15))
+#define ASIC3_CONFIG_GPIO_DEFAULT(gpio, dir, init) \
+	ASIC3_CONFIG_GPIO((gpio), 0, (dir), (init))
+#define ASIC3_CONFIG_GPIO_DEFAULT_OUT(gpio, init) \
+	ASIC3_CONFIG_GPIO((gpio), 0, 1, (init))
+
+/*
+ * Alternate functions
+ */
+#define ASIC3_GPIOA11_PWM0		ASIC3_CONFIG_GPIO(11, 1, 1, 0)
+#define ASIC3_GPIOA12_PWM1		ASIC3_CONFIG_GPIO(12, 1, 1, 0)
+#define ASIC3_GPIOA15_CONTROL_CX	ASIC3_CONFIG_GPIO(15, 1, 1, 0)
+#define ASIC3_GPIOC0_LED0		ASIC3_CONFIG_GPIO(32, 1, 1, 0)
+#define ASIC3_GPIOC1_LED1		ASIC3_CONFIG_GPIO(33, 1, 1, 0)
+#define ASIC3_GPIOC2_LED2		ASIC3_CONFIG_GPIO(34, 1, 1, 0)
+#define ASIC3_GPIOC3_SPI_RXD		ASIC3_CONFIG_GPIO(35, 1, 0, 0)
+#define ASIC3_GPIOC4_CF_nCD		ASIC3_CONFIG_GPIO(36, 1, 0, 0)
+#define ASIC3_GPIOC4_SPI_TXD		ASIC3_CONFIG_GPIO(36, 1, 1, 0)
+#define ASIC3_GPIOC5_SPI_CLK		ASIC3_CONFIG_GPIO(37, 1, 1, 0)
+#define ASIC3_GPIOC5_nCIOW		ASIC3_CONFIG_GPIO(37, 1, 1, 0)
+#define ASIC3_GPIOC6_nCIOR		ASIC3_CONFIG_GPIO(38, 1, 1, 0)
+#define ASIC3_GPIOC7_nPCE_1		ASIC3_CONFIG_GPIO(39, 1, 0, 0)
+#define ASIC3_GPIOC8_nPCE_2		ASIC3_CONFIG_GPIO(40, 1, 0, 0)
+#define ASIC3_GPIOC9_nPOE		ASIC3_CONFIG_GPIO(41, 1, 0, 0)
+#define ASIC3_GPIOC10_nPWE		ASIC3_CONFIG_GPIO(42, 1, 0, 0)
+#define ASIC3_GPIOC11_PSKTSEL		ASIC3_CONFIG_GPIO(43, 1, 0, 0)
+#define ASIC3_GPIOC12_nPREG		ASIC3_CONFIG_GPIO(44, 1, 0, 0)
+#define ASIC3_GPIOC13_nPWAIT		ASIC3_CONFIG_GPIO(45, 1, 1, 0)
+#define ASIC3_GPIOC14_nPIOIS16		ASIC3_CONFIG_GPIO(46, 1, 1, 0)
+#define ASIC3_GPIOC15_nPIOR		ASIC3_CONFIG_GPIO(47, 1, 0, 0)
+#define ASIC3_GPIOD11_nCIOIS16		ASIC3_CONFIG_GPIO(59, 1, 0, 0)
+#define ASIC3_GPIOD12_nCWAIT		ASIC3_CONFIG_GPIO(60, 1, 0, 0)
+#define ASIC3_GPIOD15_nPIOW		ASIC3_CONFIG_GPIO(63, 1, 0, 0)
+
 
 #define ASIC3_SPI_Base		      0x0400
 #define ASIC3_SPI_Control               0x0000
@@ -128,7 +164,7 @@
 #define LED_AUTOSTOP	(1 << 5) /* LED ON/OFF auto stop 0:disable, 1:enable */
 #define LED_ALWAYS	(1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
 
-#define ASIC3_CLOCK_Base		0x0A00
+#define ASIC3_CLOCK_BASE	   0x0A00
 #define ASIC3_CLOCK_CDEX           0x00
 #define ASIC3_CLOCK_SEL            0x04
 
@@ -159,12 +195,12 @@
 #define CLOCK_SEL_CX            (1 << 2)
 
 
-#define ASIC3_INTR_Base		0x0B00
+#define ASIC3_INTR_BASE		0x0B00
 
-#define ASIC3_INTR_IntMask       0x00  /* Interrupt mask control */
-#define ASIC3_INTR_PIntStat      0x04  /* Peripheral interrupt status */
-#define ASIC3_INTR_IntCPS        0x08  /* Interrupt timer clock pre-scale */
-#define ASIC3_INTR_IntTBS        0x0c  /* Interrupt timer set */
+#define ASIC3_INTR_INT_MASK       0x00  /* Interrupt mask control */
+#define ASIC3_INTR_P_INT_STAT     0x04  /* Peripheral interrupt status */
+#define ASIC3_INTR_INT_CPS        0x08  /* Interrupt timer clock pre-scale */
+#define ASIC3_INTR_INT_TBS        0x0c  /* Interrupt timer set */
 
 #define ASIC3_INTMASK_GINTMASK    (1 << 0)  /* Global INTs mask 1:enable */
 #define ASIC3_INTMASK_GINTEL      (1 << 1)  /* 1: rising edge, 0: hi level */
@@ -227,44 +263,12 @@
 #define ASIC3_EXTCF_CF_SLEEP             (1 << 15) /* CF sleep mode control */
 
 /*********************************************
- *  The Onewire interface registers
- *
- *  OWM_CMD
- *  OWM_DAT
- *  OWM_INTR
- *  OWM_INTEN
- *  OWM_CLKDIV
+ *  The Onewire interface (DS1WM) is handled
+ *  by the ds1wm driver.
  *
  *********************************************/
 
-#define ASIC3_OWM_Base		0xC00
-
-#define ASIC3_OWM_CMD         0x00
-#define ASIC3_OWM_DAT         0x04
-#define ASIC3_OWM_INTR        0x08
-#define ASIC3_OWM_INTEN       0x0C
-#define ASIC3_OWM_CLKDIV      0x10
-
-#define ASIC3_OWM_CMD_ONEWR         (1 << 0)
-#define ASIC3_OWM_CMD_SRA           (1 << 1)
-#define ASIC3_OWM_CMD_DQO           (1 << 2)
-#define ASIC3_OWM_CMD_DQI           (1 << 3)
-
-#define ASIC3_OWM_INTR_PD          (1 << 0)
-#define ASIC3_OWM_INTR_PDR         (1 << 1)
-#define ASIC3_OWM_INTR_TBE         (1 << 2)
-#define ASIC3_OWM_INTR_TEMP        (1 << 3)
-#define ASIC3_OWM_INTR_RBF         (1 << 4)
-
-#define ASIC3_OWM_INTEN_EPD        (1 << 0)
-#define ASIC3_OWM_INTEN_IAS        (1 << 1)
-#define ASIC3_OWM_INTEN_ETBE       (1 << 2)
-#define ASIC3_OWM_INTEN_ETMT       (1 << 3)
-#define ASIC3_OWM_INTEN_ERBF       (1 << 4)
-
-#define ASIC3_OWM_CLKDIV_PRE       (3 << 0) /* two bits wide at bit 0 */
-#define ASIC3_OWM_CLKDIV_DIV       (7 << 2) /* 3 bits wide at bit 2 */
-
+#define ASIC3_OWM_BASE		0xC00
 
 /*****************************************************************************
  *  The SD configuration registers are at a completely different location
@@ -492,6 +496,7 @@
 #define ASIC3_SDIO_CTRL_LEDCtrl              0x7C
 #define ASIC3_SDIO_CTRL_SoftwareReset        0x1C0
 
-#define ASIC3_MAP_SIZE	     		     0x2000
+#define ASIC3_MAP_SIZE_32BIT	0x2000
+#define ASIC3_MAP_SIZE_16BIT	0x1000
 
 #endif /* __ASIC3_H__ */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index d8f31de..f3a1c0e 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -190,6 +190,7 @@
 	void		(*break_ctl)(struct uart_port *, int ctl);
 	int		(*startup)(struct uart_port *);
 	void		(*shutdown)(struct uart_port *);
+	void		(*flush_buffer)(struct uart_port *);
 	void		(*set_termios)(struct uart_port *, struct ktermios *new,
 				       struct ktermios *old);
 	void		(*set_ldisc)(struct uart_port *);
@@ -343,13 +344,15 @@
  * stuff here.
  */
 struct uart_info {
-	struct tty_struct	*tty;
+	struct tty_port		port;
 	struct circ_buf		xmit;
 	uif_t			flags;
 
 /*
  * Definitions for info->flags.  These are _private_ to serial_core, and
  * are specific to this structure.  They may be queried by low level drivers.
+ *
+ * FIXME: use the ASY_ definitions
  */
 #define UIF_CHECK_CD		((__force uif_t) (1 << 25))
 #define UIF_CTS_FLOW		((__force uif_t) (1 << 26))
@@ -357,11 +360,7 @@
 #define UIF_INITIALIZED		((__force uif_t) (1 << 31))
 #define UIF_SUSPENDED		((__force uif_t) (1 << 30))
 
-	int			blocked_open;
-
 	struct tasklet_struct	tlet;
-
-	wait_queue_head_t	open_wait;
 	wait_queue_head_t	delta_msr_wait;
 };
 
@@ -438,8 +437,8 @@
 #define uart_circ_chars_free(circ)	\
 	(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
 
-#define uart_tx_stopped(port)		\
-	((port)->info->tty->stopped || (port)->info->tty->hw_stopped)
+#define uart_tx_stopped(portp)		\
+	((portp)->info->port.tty->stopped || (portp)->info->port.tty->hw_stopped)
 
 /*
  * The following are helper functions for the low level drivers.
@@ -450,7 +449,7 @@
 #ifdef SUPPORT_SYSRQ
 	if (port->sysrq) {
 		if (ch && time_before(jiffies, port->sysrq)) {
-			handle_sysrq(ch, port->info ? port->info->tty : NULL);
+			handle_sysrq(ch, port->info ? port->info->port.tty : NULL);
 			port->sysrq = 0;
 			return 1;
 		}
@@ -479,7 +478,7 @@
 	}
 #endif
 	if (port->flags & UPF_SAK)
-		do_SAK(info->tty);
+		do_SAK(info->port.tty);
 	return 0;
 }
 
@@ -502,9 +501,9 @@
 
 	if (info->flags & UIF_CHECK_CD) {
 		if (status)
-			wake_up_interruptible(&info->open_wait);
-		else if (info->tty)
-			tty_hangup(info->tty);
+			wake_up_interruptible(&info->port.open_wait);
+		else if (info->port.tty)
+			tty_hangup(info->port.tty);
 	}
 }
 
@@ -517,7 +516,7 @@
 uart_handle_cts_change(struct uart_port *port, unsigned int status)
 {
 	struct uart_info *info = port->info;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = info->port.tty;
 
 	port->icount.cts++;
 
@@ -543,7 +542,7 @@
 uart_insert_char(struct uart_port *port, unsigned int status,
 		 unsigned int overrun, unsigned int ch, unsigned int flag)
 {
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = port->info->port.tty;
 
 	if ((status & port->ignore_status_mask & ~overrun) == 0)
 		tty_insert_flip_char(tty, ch, flag);
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
index 0424d75..336af33c 100644
--- a/include/linux/stallion.h
+++ b/include/linux/stallion.h
@@ -69,6 +69,7 @@
  */
 struct stlport {
 	unsigned long		magic;
+	struct tty_port		port;
 	unsigned int		portnr;
 	unsigned int		panelnr;
 	unsigned int		brdnr;
@@ -76,12 +77,10 @@
 	int			uartaddr;
 	unsigned int		pagenr;
 	unsigned long		istate;
-	int			flags;
 	int			baud_base;
 	int			custom_divisor;
 	int			close_delay;
 	int			closing_wait;
-	int			refcount;
 	int			openwaitcnt;
 	int			brklen;
 	unsigned int		sigs;
@@ -92,9 +91,6 @@
 	unsigned long		clk;
 	unsigned long		hwid;
 	void			*uartp;
-	struct tty_struct	*tty;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
 	comstats_t		stats;
 	struct stlrq		tx;
 };
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 324a3b2..4e58330 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -71,7 +71,8 @@
 	struct tty_buffer *head;	/* Queue head */
 	struct tty_buffer *tail;	/* Active buffer */
 	struct tty_buffer *free;	/* Free queue head */
-	int memory_used;		/* Buffer space used excluding free queue */
+	int memory_used;		/* Buffer space used excluding
+								free queue */
 };
 /*
  * When a break, frame error, or parity error happens, these codes are
@@ -101,71 +102,96 @@
 #define LNEXT_CHAR(tty)	((tty)->termios->c_cc[VLNEXT])
 #define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
 
-#define _I_FLAG(tty,f)	((tty)->termios->c_iflag & (f))
-#define _O_FLAG(tty,f)	((tty)->termios->c_oflag & (f))
-#define _C_FLAG(tty,f)	((tty)->termios->c_cflag & (f))
-#define _L_FLAG(tty,f)	((tty)->termios->c_lflag & (f))
+#define _I_FLAG(tty, f)	((tty)->termios->c_iflag & (f))
+#define _O_FLAG(tty, f)	((tty)->termios->c_oflag & (f))
+#define _C_FLAG(tty, f)	((tty)->termios->c_cflag & (f))
+#define _L_FLAG(tty, f)	((tty)->termios->c_lflag & (f))
 
-#define I_IGNBRK(tty)	_I_FLAG((tty),IGNBRK)
-#define I_BRKINT(tty)	_I_FLAG((tty),BRKINT)
-#define I_IGNPAR(tty)	_I_FLAG((tty),IGNPAR)
-#define I_PARMRK(tty)	_I_FLAG((tty),PARMRK)
-#define I_INPCK(tty)	_I_FLAG((tty),INPCK)
-#define I_ISTRIP(tty)	_I_FLAG((tty),ISTRIP)
-#define I_INLCR(tty)	_I_FLAG((tty),INLCR)
-#define I_IGNCR(tty)	_I_FLAG((tty),IGNCR)
-#define I_ICRNL(tty)	_I_FLAG((tty),ICRNL)
-#define I_IUCLC(tty)	_I_FLAG((tty),IUCLC)
-#define I_IXON(tty)	_I_FLAG((tty),IXON)
-#define I_IXANY(tty)	_I_FLAG((tty),IXANY)
-#define I_IXOFF(tty)	_I_FLAG((tty),IXOFF)
-#define I_IMAXBEL(tty)	_I_FLAG((tty),IMAXBEL)
-#define I_IUTF8(tty)	_I_FLAG((tty),IUTF8)
+#define I_IGNBRK(tty)	_I_FLAG((tty), IGNBRK)
+#define I_BRKINT(tty)	_I_FLAG((tty), BRKINT)
+#define I_IGNPAR(tty)	_I_FLAG((tty), IGNPAR)
+#define I_PARMRK(tty)	_I_FLAG((tty), PARMRK)
+#define I_INPCK(tty)	_I_FLAG((tty), INPCK)
+#define I_ISTRIP(tty)	_I_FLAG((tty), ISTRIP)
+#define I_INLCR(tty)	_I_FLAG((tty), INLCR)
+#define I_IGNCR(tty)	_I_FLAG((tty), IGNCR)
+#define I_ICRNL(tty)	_I_FLAG((tty), ICRNL)
+#define I_IUCLC(tty)	_I_FLAG((tty), IUCLC)
+#define I_IXON(tty)	_I_FLAG((tty), IXON)
+#define I_IXANY(tty)	_I_FLAG((tty), IXANY)
+#define I_IXOFF(tty)	_I_FLAG((tty), IXOFF)
+#define I_IMAXBEL(tty)	_I_FLAG((tty), IMAXBEL)
+#define I_IUTF8(tty)	_I_FLAG((tty), IUTF8)
 
-#define O_OPOST(tty)	_O_FLAG((tty),OPOST)
-#define O_OLCUC(tty)	_O_FLAG((tty),OLCUC)
-#define O_ONLCR(tty)	_O_FLAG((tty),ONLCR)
-#define O_OCRNL(tty)	_O_FLAG((tty),OCRNL)
-#define O_ONOCR(tty)	_O_FLAG((tty),ONOCR)
-#define O_ONLRET(tty)	_O_FLAG((tty),ONLRET)
-#define O_OFILL(tty)	_O_FLAG((tty),OFILL)
-#define O_OFDEL(tty)	_O_FLAG((tty),OFDEL)
-#define O_NLDLY(tty)	_O_FLAG((tty),NLDLY)
-#define O_CRDLY(tty)	_O_FLAG((tty),CRDLY)
-#define O_TABDLY(tty)	_O_FLAG((tty),TABDLY)
-#define O_BSDLY(tty)	_O_FLAG((tty),BSDLY)
-#define O_VTDLY(tty)	_O_FLAG((tty),VTDLY)
-#define O_FFDLY(tty)	_O_FLAG((tty),FFDLY)
+#define O_OPOST(tty)	_O_FLAG((tty), OPOST)
+#define O_OLCUC(tty)	_O_FLAG((tty), OLCUC)
+#define O_ONLCR(tty)	_O_FLAG((tty), ONLCR)
+#define O_OCRNL(tty)	_O_FLAG((tty), OCRNL)
+#define O_ONOCR(tty)	_O_FLAG((tty), ONOCR)
+#define O_ONLRET(tty)	_O_FLAG((tty), ONLRET)
+#define O_OFILL(tty)	_O_FLAG((tty), OFILL)
+#define O_OFDEL(tty)	_O_FLAG((tty), OFDEL)
+#define O_NLDLY(tty)	_O_FLAG((tty), NLDLY)
+#define O_CRDLY(tty)	_O_FLAG((tty), CRDLY)
+#define O_TABDLY(tty)	_O_FLAG((tty), TABDLY)
+#define O_BSDLY(tty)	_O_FLAG((tty), BSDLY)
+#define O_VTDLY(tty)	_O_FLAG((tty), VTDLY)
+#define O_FFDLY(tty)	_O_FLAG((tty), FFDLY)
 
-#define C_BAUD(tty)	_C_FLAG((tty),CBAUD)
-#define C_CSIZE(tty)	_C_FLAG((tty),CSIZE)
-#define C_CSTOPB(tty)	_C_FLAG((tty),CSTOPB)
-#define C_CREAD(tty)	_C_FLAG((tty),CREAD)
-#define C_PARENB(tty)	_C_FLAG((tty),PARENB)
-#define C_PARODD(tty)	_C_FLAG((tty),PARODD)
-#define C_HUPCL(tty)	_C_FLAG((tty),HUPCL)
-#define C_CLOCAL(tty)	_C_FLAG((tty),CLOCAL)
-#define C_CIBAUD(tty)	_C_FLAG((tty),CIBAUD)
-#define C_CRTSCTS(tty)	_C_FLAG((tty),CRTSCTS)
+#define C_BAUD(tty)	_C_FLAG((tty), CBAUD)
+#define C_CSIZE(tty)	_C_FLAG((tty), CSIZE)
+#define C_CSTOPB(tty)	_C_FLAG((tty), CSTOPB)
+#define C_CREAD(tty)	_C_FLAG((tty), CREAD)
+#define C_PARENB(tty)	_C_FLAG((tty), PARENB)
+#define C_PARODD(tty)	_C_FLAG((tty), PARODD)
+#define C_HUPCL(tty)	_C_FLAG((tty), HUPCL)
+#define C_CLOCAL(tty)	_C_FLAG((tty), CLOCAL)
+#define C_CIBAUD(tty)	_C_FLAG((tty), CIBAUD)
+#define C_CRTSCTS(tty)	_C_FLAG((tty), CRTSCTS)
 
-#define L_ISIG(tty)	_L_FLAG((tty),ISIG)
-#define L_ICANON(tty)	_L_FLAG((tty),ICANON)
-#define L_XCASE(tty)	_L_FLAG((tty),XCASE)
-#define L_ECHO(tty)	_L_FLAG((tty),ECHO)
-#define L_ECHOE(tty)	_L_FLAG((tty),ECHOE)
-#define L_ECHOK(tty)	_L_FLAG((tty),ECHOK)
-#define L_ECHONL(tty)	_L_FLAG((tty),ECHONL)
-#define L_NOFLSH(tty)	_L_FLAG((tty),NOFLSH)
-#define L_TOSTOP(tty)	_L_FLAG((tty),TOSTOP)
-#define L_ECHOCTL(tty)	_L_FLAG((tty),ECHOCTL)
-#define L_ECHOPRT(tty)	_L_FLAG((tty),ECHOPRT)
-#define L_ECHOKE(tty)	_L_FLAG((tty),ECHOKE)
-#define L_FLUSHO(tty)	_L_FLAG((tty),FLUSHO)
-#define L_PENDIN(tty)	_L_FLAG((tty),PENDIN)
-#define L_IEXTEN(tty)	_L_FLAG((tty),IEXTEN)
+#define L_ISIG(tty)	_L_FLAG((tty), ISIG)
+#define L_ICANON(tty)	_L_FLAG((tty), ICANON)
+#define L_XCASE(tty)	_L_FLAG((tty), XCASE)
+#define L_ECHO(tty)	_L_FLAG((tty), ECHO)
+#define L_ECHOE(tty)	_L_FLAG((tty), ECHOE)
+#define L_ECHOK(tty)	_L_FLAG((tty), ECHOK)
+#define L_ECHONL(tty)	_L_FLAG((tty), ECHONL)
+#define L_NOFLSH(tty)	_L_FLAG((tty), NOFLSH)
+#define L_TOSTOP(tty)	_L_FLAG((tty), TOSTOP)
+#define L_ECHOCTL(tty)	_L_FLAG((tty), ECHOCTL)
+#define L_ECHOPRT(tty)	_L_FLAG((tty), ECHOPRT)
+#define L_ECHOKE(tty)	_L_FLAG((tty), ECHOKE)
+#define L_FLUSHO(tty)	_L_FLAG((tty), FLUSHO)
+#define L_PENDIN(tty)	_L_FLAG((tty), PENDIN)
+#define L_IEXTEN(tty)	_L_FLAG((tty), IEXTEN)
 
 struct device;
 struct signal_struct;
+
+/*
+ * Port level information. Each device keeps its own port level information
+ * so provide a common structure for those ports wanting to use common support
+ * routines.
+ *
+ * The tty port has a different lifetime to the tty so must be kept apart.
+ * In addition be careful as tty -> port mappings are valid for the life
+ * of the tty object but in many cases port -> tty mappings are valid only
+ * until a hangup so don't use the wrong path.
+ */
+
+struct tty_port {
+	struct tty_struct	*tty;		/* Back pointer */
+	int			blocked_open;	/* Waiting to open */
+	int			count;		/* Usage count */
+	wait_queue_head_t	open_wait;	/* Open waiters */
+	wait_queue_head_t	close_wait;	/* Close waiters */
+	unsigned long		flags;		/* TTY flags ASY_*/
+	struct mutex		mutex;		/* Locking */
+	unsigned char		*xmit_buf;	/* Optional buffer */
+	int			close_delay;	/* Close port delay */
+	int			closing_wait;	/* Delay for output */
+};
+
 /*
  * Where all of the state associated with a tty is kept while the tty
  * is open.  Since the termios state should be kept even if the tty
@@ -185,6 +211,7 @@
 	struct tty_driver *driver;
 	const struct tty_operations *ops;
 	int index;
+	/* The ldisc objects are protected by tty_ldisc_lock at the moment */
 	struct tty_ldisc ldisc;
 	struct mutex termios_mutex;
 	spinlock_t ctrl_lock;
@@ -213,7 +240,7 @@
 	struct list_head tty_files;
 
 #define N_TTY_BUF_SIZE 4096
-	
+
 	/*
 	 * The following is data for the N_TTY line discipline.  For
 	 * historical reasons, this is included in the tty structure.
@@ -241,6 +268,7 @@
 	spinlock_t read_lock;
 	/* If the tty has a pending do_SAK, queue it here - akpm */
 	struct work_struct SAK_work;
+	struct tty_port *port;
 };
 
 /* tty magic number */
@@ -248,14 +276,14 @@
 
 /*
  * These bits are used in the flags field of the tty structure.
- * 
+ *
  * So that interrupts won't be able to mess up the queues,
  * copy_to_cooked must be atomic with respect to itself, as must
  * tty->write.  Thus, you must use the inline functions set_bit() and
  * clear_bit() to make things atomic.
  */
 #define TTY_THROTTLED 		0	/* Call unthrottle() at threshold min */
-#define TTY_IO_ERROR 		1	/* Canse an I/O error (may be no ldisc too) */
+#define TTY_IO_ERROR 		1	/* Cause an I/O error (may be no ldisc too) */
 #define TTY_OTHER_CLOSED 	2	/* Other side (if any) has closed */
 #define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
 #define TTY_DEBUG 		4	/* Debugging */
@@ -285,11 +313,11 @@
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
 			      const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
-extern void tty_wait_until_sent(struct tty_struct * tty, long timeout);
-extern int tty_check_change(struct tty_struct * tty);
-extern void stop_tty(struct tty_struct * tty);
-extern void start_tty(struct tty_struct * tty);
-extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
+extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
+extern int tty_check_change(struct tty_struct *tty);
+extern void stop_tty(struct tty_struct *tty);
+extern void start_tty(struct tty_struct *tty);
+extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
@@ -310,10 +338,10 @@
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
-extern void tty_hangup(struct tty_struct * tty);
-extern void tty_vhangup(struct tty_struct * tty);
+extern void tty_hangup(struct tty_struct *tty);
+extern void tty_vhangup(struct tty_struct *tty);
 extern void tty_unhangup(struct file *filp);
-extern int tty_hung_up_p(struct file * filp);
+extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
 extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
@@ -322,17 +350,17 @@
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
-extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud);
-extern void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud);
+extern void tty_termios_encode_baud_rate(struct ktermios *termios,
+						speed_t ibaud, speed_t obaud);
+extern void tty_encode_baud_rate(struct tty_struct *tty,
+						speed_t ibaud, speed_t obaud);
 extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
 extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
 
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
 extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
-
-extern struct tty_ldisc *tty_ldisc_get(int);
-extern void tty_ldisc_put(int);
+extern const struct file_operations tty_ldiscs_proc_fops;
 
 extern void tty_wakeup(struct tty_struct *tty);
 extern void tty_ldisc_flush(struct tty_struct *tty);
@@ -351,10 +379,14 @@
 extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 #define tty_is_writelocked(tty)  (mutex_is_locked(&tty->atomic_write_lock))
 
+extern void tty_port_init(struct tty_port *port);
+extern int tty_port_alloc_xmit_buf(struct tty_port *port);
+extern void tty_port_free_xmit_buf(struct tty_port *port);
+
 
 
 /* n_tty.c */
-extern struct tty_ldisc tty_ldisc_N_TTY;
+extern struct tty_ldisc_ops tty_ldisc_N_TTY;
 
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
@@ -363,7 +395,8 @@
 extern void tty_audit_exit(void);
 extern void tty_audit_fork(struct signal_struct *sig);
 extern void tty_audit_push(struct tty_struct *tty);
-extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid);
+extern void tty_audit_push_task(struct task_struct *tsk,
+					uid_t loginuid, u32 sessionid);
 #else
 static inline void tty_audit_add_data(struct tty_struct *tty,
 				      unsigned char *data, size_t size)
@@ -378,19 +411,20 @@
 static inline void tty_audit_push(struct tty_struct *tty)
 {
 }
-static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+static inline void tty_audit_push_task(struct task_struct *tsk,
+					uid_t loginuid, u32 sessionid)
 {
 }
 #endif
 
 /* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
+extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg);
 
 /* serial.c */
 
 extern void serial_console_init(void);
- 
+
 /* pcxx.c */
 
 extern int pcxe_open(struct tty_struct *tty, struct file *filp);
@@ -401,7 +435,7 @@
 
 /* vt.c */
 
-extern int vt_ioctl(struct tty_struct *tty, struct file * file,
+extern int vt_ioctl(struct tty_struct *tty, struct file *file,
 		    unsigned int cmd, unsigned long arg);
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 6226504..40f38d8 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -104,7 +104,7 @@
 #include <linux/fs.h>
 #include <linux/wait.h>
 
-struct tty_ldisc {
+struct tty_ldisc_ops {
 	int	magic;
 	char	*name;
 	int	num;
@@ -142,6 +142,11 @@
 	int refcount;
 };
 
+struct tty_ldisc {
+	struct tty_ldisc_ops *ops;
+	int refcount;
+};
+
 #define TTY_LDISC_MAGIC	0x5403
 
 #define LDISC_FLAG_DEFINED	0x00000001
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 4a535ea..2e66a95 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -246,6 +246,7 @@
 #define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
 #define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
 #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY	0x00000200  /* Can do video output overlay */
+#define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
 
 #define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
 #define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
@@ -309,6 +310,7 @@
 
 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G','B','R','G') /*  8  GBGB.. RGRG.. */
 #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B','Y','R','2') /* 16  BGBG.. GRGR.. */
 
 /* compressed formats */
@@ -323,6 +325,9 @@
 #define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
 #define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
 #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
+#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S','5','0','1') /* YUYV per line */
+#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S','5','6','1') /* compressed GBRG bayer */
+#define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P','2','0','7') /* compressed BGGR bayer */
 
 /*
  *	F O R M A T   E N U M E R A T I O N
@@ -1156,6 +1161,14 @@
 	__u32		      reserved[8];
 };
 
+struct v4l2_hw_freq_seek {
+	__u32		      tuner;
+	enum v4l2_tuner_type  type;
+	__u32		      seek_upward;
+	__u32		      wrap_around;
+	__u32		      reserved[8];
+};
+
 /*
  *	A U D I O
  */
@@ -1441,6 +1454,7 @@
 
 #define VIDIOC_G_CHIP_IDENT     _IOWR ('V', 81, struct v4l2_chip_ident)
 #endif
+#define VIDIOC_S_HW_FREQ_SEEK	_IOW  ('V', 82, struct v4l2_hw_freq_seek)
 
 #ifdef __OLD_VIDIOC_
 /* for compatibility, will go away some day */
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
index 5f4608e..9ec4d58 100644
--- a/include/media/cx2341x.h
+++ b/include/media/cx2341x.h
@@ -27,6 +27,7 @@
 
 enum cx2341x_cap {
 	CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
+	CX2341X_CAP_HAS_TS 	   = 1 << 1,
 };
 
 struct cx2341x_mpeg_params {
@@ -88,13 +89,13 @@
 int cx2341x_update(void *priv, cx2341x_mbox_func func,
 		const struct cx2341x_mpeg_params *old,
 		const struct cx2341x_mpeg_params *new);
-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
 		struct v4l2_queryctrl *qctrl);
-const char **cx2341x_ctrl_get_menu(u32 id);
+const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id);
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
 		struct v4l2_ext_controls *ctrls, unsigned int cmd);
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix);
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix);
 
 /* Firmware names */
 #define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index a455f7c..00fa57e 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -19,7 +19,4 @@
 	char                   phys[32];
 	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
-
-int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 #endif
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
index adc1254..0f19779 100644
--- a/include/media/pwc-ioctl.h
+++ b/include/media/pwc-ioctl.h
@@ -55,8 +55,7 @@
 #include <linux/types.h>
 #include <linux/version.h>
 
-
- /* Enumeration of image sizes */
+/* Enumeration of image sizes */
 #define PSZ_SQCIF	0x00
 #define PSZ_QSIF	0x01
 #define PSZ_QCIF	0x02
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 88b2b5a..2f68f4c 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -53,7 +53,7 @@
 /* saa7146 page table */
 struct saa7146_pgtable {
 	unsigned int	size;
-	u32		*cpu;
+	__le32		*cpu;
 	dma_addr_t	dma;
 	/* used for offsets for u,v planes for planar capture modes */
 	unsigned long	offset;
@@ -101,7 +101,7 @@
 struct saa7146_dma
 {
 	dma_addr_t	dma_handle;
-	u32		*cpu_addr;
+	__le32		*cpu_addr;
 };
 
 struct saa7146_dev
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
new file mode 100644
index 0000000..234a471
--- /dev/null
+++ b/include/media/sh_mobile_ceu.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_SH_MOBILE_CEU_H__
+#define __ASM_SH_MOBILE_CEU_H__
+
+#include <media/soc_camera.h>
+
+struct sh_mobile_ceu_info {
+	unsigned long flags; /* SOCAM_... */
+	void (*enable_camera)(void);
+	void (*disable_camera)(void);
+};
+
+#endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 6a8c8be..1de98f1 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -13,7 +13,7 @@
 #define SOC_CAMERA_H
 
 #include <linux/videodev2.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-core.h>
 
 struct soc_camera_device {
 	struct list_head list;
@@ -48,15 +48,12 @@
 struct soc_camera_file {
 	struct soc_camera_device *icd;
 	struct videobuf_queue vb_vidq;
-	spinlock_t *lock;
 };
 
 struct soc_camera_host {
 	struct list_head list;
 	struct device dev;
 	unsigned char nr;				/* Host number */
-	size_t msize;
-	struct videobuf_queue_ops *vbq_ops;
 	void *priv;
 	char *drv_name;
 	struct soc_camera_host_ops *ops;
@@ -69,13 +66,13 @@
 	int (*set_fmt_cap)(struct soc_camera_device *, __u32,
 			   struct v4l2_rect *);
 	int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+	void (*init_videobuf)(struct videobuf_queue *,
+			      struct soc_camera_device *);
 	int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
 	int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
 	int (*try_bus_param)(struct soc_camera_device *, __u32);
 	int (*set_bus_param)(struct soc_camera_device *, __u32);
 	unsigned int (*poll)(struct file *, poll_table *);
-	spinlock_t* (*spinlock_alloc)(struct soc_camera_file *);
-	void (*spinlock_free)(spinlock_t *);
 };
 
 struct soc_camera_link {
@@ -156,11 +153,12 @@
 #define SOCAM_DATAWIDTH_8		(1 << 6)
 #define SOCAM_DATAWIDTH_9		(1 << 7)
 #define SOCAM_DATAWIDTH_10		(1 << 8)
-#define SOCAM_PCLK_SAMPLE_RISING	(1 << 9)
-#define SOCAM_PCLK_SAMPLE_FALLING	(1 << 10)
+#define SOCAM_DATAWIDTH_16		(1 << 9)
+#define SOCAM_PCLK_SAMPLE_RISING	(1 << 10)
+#define SOCAM_PCLK_SAMPLE_FALLING	(1 << 11)
 
 #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
-			      SOCAM_DATAWIDTH_10)
+			      SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_16)
 
 static inline unsigned long soc_camera_bus_param_compatible(
 			unsigned long camera_flags, unsigned long bus_flags)
diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h
new file mode 100644
index 0000000..851f182
--- /dev/null
+++ b/include/media/soc_camera_platform.h
@@ -0,0 +1,15 @@
+#ifndef __SOC_CAMERA_H__
+#define __SOC_CAMERA_H__
+
+#include <linux/videodev2.h>
+
+struct soc_camera_platform_info {
+	int iface;
+	char *format_name;
+	unsigned long format_depth;
+	struct v4l2_pix_format format;
+	unsigned long bus_param;
+	int (*set_capture)(struct soc_camera_platform_info *info, int enable);
+};
+
+#endif /* __SOC_CAMERA_H__ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 859f7a6..33f379b 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -59,8 +59,8 @@
 int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
 
 /* names for fancy debug output */
-extern char *v4l2_field_names[];
-extern char *v4l2_type_names[];
+extern const char *v4l2_field_names[];
+extern const char *v4l2_type_names[];
 
 /*  Compatibility layer interface  --  v4l1-compat module */
 typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
@@ -96,6 +96,8 @@
 	int type;       /* v4l1 */
 	int type2;      /* v4l2 */
 	int minor;
+	/* attribute to diferentiate multiple indexs on one physical device */
+	int index;
 
 	int debug;	/* Activates debug level*/
 
@@ -118,74 +120,76 @@
 				    enum v4l2_priority p);
 
 	/* VIDIOC_ENUM_FMT handlers */
-	int (*vidioc_enum_fmt_cap)         (struct file *file, void *fh,
+	int (*vidioc_enum_fmt_vid_cap)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_overlay)     (struct file *file, void *fh,
+	int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_vbi)         (struct file *file, void *fh,
+	int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh,
+#if 1
+	/* deprecated, will be removed in 2.6.28 */
+	int (*vidioc_enum_fmt_vbi_cap)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
-					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_output_overlay) (struct file *file, void *fh,
-					    struct v4l2_fmtdesc *f);
-	int (*vidioc_enum_fmt_vbi_output)  (struct file *file, void *fh,
-					    struct v4l2_fmtdesc *f);
+#endif
 	int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
 
 	/* VIDIOC_G_FMT handlers */
-	int (*vidioc_g_fmt_cap)        (struct file *file, void *fh,
+	int (*vidioc_g_fmt_vid_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_overlay)    (struct file *file, void *fh,
+	int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_vbi)        (struct file *file, void *fh,
+	int (*vidioc_g_fmt_vid_out)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh,
+	int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh,
+	int (*vidioc_g_fmt_vbi_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
+	int (*vidioc_g_fmt_vbi_out)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_g_fmt_output_overlay) (struct file *file, void *fh,
+	int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					struct v4l2_format *f);
 	int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
 	/* VIDIOC_S_FMT handlers */
-	int (*vidioc_s_fmt_cap)        (struct file *file, void *fh,
+	int (*vidioc_s_fmt_vid_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-
-	int (*vidioc_s_fmt_overlay)    (struct file *file, void *fh,
+	int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_s_fmt_vbi)        (struct file *file, void *fh,
+	int (*vidioc_s_fmt_vid_out)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh,
+	int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh,
+	int (*vidioc_s_fmt_vbi_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
+	int (*vidioc_s_fmt_vbi_out)    (struct file *file, void *fh,
 					struct v4l2_format *f);
-	int (*vidioc_s_fmt_output_overlay) (struct file *file, void *fh,
+	int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					struct v4l2_format *f);
 	int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
 	/* VIDIOC_TRY_FMT handlers */
-	int (*vidioc_try_fmt_cap)        (struct file *file, void *fh,
+	int (*vidioc_try_fmt_vid_cap)    (struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_overlay)    (struct file *file, void *fh,
+	int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_vbi)        (struct file *file, void *fh,
+	int (*vidioc_try_fmt_vid_out)    (struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh,
+	int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh,
+	int (*vidioc_try_fmt_vbi_cap)    (struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
+	int (*vidioc_try_fmt_vbi_out)    (struct file *file, void *fh,
 					  struct v4l2_format *f);
-	int (*vidioc_try_fmt_output_overlay)(struct file *file, void *fh,
+	int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh,
 					  struct v4l2_format *f);
 	int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
 					  struct v4l2_format *f);
@@ -212,8 +216,9 @@
 	int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
 
 		/* Standard handling
-			G_STD and ENUMSTD are handled by videodev.c
+			ENUMSTD is handled by videodev.c
 		 */
+	int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm);
 	int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
 	int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
 
@@ -224,7 +229,7 @@
 	int (*vidioc_s_input)   (struct file *file, void *fh, unsigned int i);
 
 		/* Output handling */
-	int (*vidioc_enumoutput) (struct file *file, void *fh,
+	int (*vidioc_enum_output) (struct file *file, void *fh,
 				  struct v4l2_output *a);
 	int (*vidioc_g_output)   (struct file *file, void *fh, unsigned int *i);
 	int (*vidioc_s_output)   (struct file *file, void *fh, unsigned int i);
@@ -306,6 +311,8 @@
 	/* Log status ioctl */
 	int (*vidioc_log_status)       (struct file *file, void *fh);
 
+	int (*vidioc_s_hw_freq_seek)   (struct file *file, void *fh,
+					struct v4l2_hw_freq_seek *a);
 
 	/* Debugging ioctls */
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -342,6 +349,8 @@
 
 /* Version 2 functions */
 extern int video_register_device(struct video_device *vfd, int type, int nr);
+int video_register_device_index(struct video_device *vfd, int type, int nr,
+					int index);
 void video_unregister_device(struct video_device *);
 extern int video_ioctl2(struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg);
@@ -366,7 +375,7 @@
 {
 	int ret = device_create_file(&vfd->class_dev, attr);
 	if (ret < 0)
-		printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret);
+		printk(KERN_WARNING "%s error: %d\n", __func__, ret);
 	return ret;
 }
 static inline void
diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h
index 8785622..975ffbf 100644
--- a/include/media/v4l2-i2c-drv-legacy.h
+++ b/include/media/v4l2-i2c-drv-legacy.h
@@ -68,7 +68,6 @@
 	if (err)
 		return err;
 	kfree(client);
-
 	return 0;
 }
 
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
new file mode 100644
index 0000000..5493866
--- /dev/null
+++ b/include/media/videobuf-dma-contig.h
@@ -0,0 +1,32 @@
+/*
+ * helper functions for physically contiguous capture buffers
+ *
+ * The functions support hardware lacking scatter gather support
+ * (i.e. the buffers must be linear in physical memory)
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * 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
+ */
+#ifndef _VIDEOBUF_DMA_CONTIG_H
+#define _VIDEOBUF_DMA_CONTIG_H
+
+#include <linux/dma-mapping.h>
+#include <media/videobuf-core.h>
+
+void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
+				    struct videobuf_queue_ops *ops,
+				    struct device *dev,
+				    spinlock_t *irqlock,
+				    enum v4l2_buf_type type,
+				    enum v4l2_field field,
+				    unsigned int msize,
+				    void *priv);
+
+dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
+void videobuf_dma_contig_free(struct videobuf_queue *q,
+			      struct videobuf_buffer *buf);
+
+#endif /* _VIDEOBUF_DMA_CONTIG_H */
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index be8da26..90edd22 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -1,7 +1,7 @@
 /*
  * helper functions for SG DMA video4linux capture buffers
  *
- * The functions expect the hardware being able to scatter gatter
+ * The functions expect the hardware being able to scatter gather
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
  * to touch the video data.
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index aed3946..e87222c 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -1,7 +1,7 @@
 /*
  * helper functions for vmalloc capture buffers
  *
- * The functions expect the hardware being able to scatter gatter
+ * The functions expect the hardware being able to scatter gather
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
  * to touch the video data.
diff --git a/init/main.c b/init/main.c
index edeace0..756eca4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -630,9 +630,10 @@
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start && !initrd_below_start_ok &&
-			initrd_start < min_low_pfn << PAGE_SHIFT) {
+	    page_to_pfn(virt_to_page(initrd_start)) < min_low_pfn) {
 		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
-		    "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
+		    "disabling it.\n",
+		    page_to_pfn(virt_to_page(initrd_start)), min_low_pfn);
 		initrd_start = 0;
 	}
 #endif
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 5d16357..d3340dd 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -643,14 +643,7 @@
 		return;
 
 	BT_DBG("dev %p tty %p", dev, tty);
-
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-
-	wake_up_interruptible(&tty->write_wait);
-#ifdef SERIAL_HAVE_POLL_WAIT
-	wake_up_interruptible(&tty->poll_wait);
-#endif
+	tty_wakeup(tty);
 }
 
 static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
@@ -1059,9 +1052,7 @@
 		return;
 
 	skb_queue_purge(&dev->dlc->tx_queue);
-
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-		tty->ldisc.write_wakeup(tty);
+	tty_wakeup(tty);
 }
 
 static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 76c3057..e4e2cae 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -650,12 +650,7 @@
 	}
 
 	/* Check if user (still) wants to be waken up */
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-	{
-		(tty->ldisc.write_wakeup)(tty);
-	}
-	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
 }
 
 /*
@@ -1141,6 +1136,7 @@
 				      struct sk_buff *skb)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+	struct tty_ldisc *ld;
 
 	IRDA_DEBUG(2, "%s()\n", __func__ );
 
@@ -1173,7 +1169,11 @@
 	 * involve the flip buffers, since we are not running in an interrupt
 	 * handler
 	 */
-	self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
+
+	ld = tty_ldisc_ref(self->tty);
+	if (ld)
+		ld->ops->receive_buf(self->tty, skb->data, NULL, skb->len);
+	tty_ldisc_deref(ld);
 
 	/* No need to kfree_skb - see ircomm_ttp_data_indication() */
 
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
new file mode 100644
index 0000000..5ae620d
--- /dev/null
+++ b/virt/kvm/coalesced_mmio.c
@@ -0,0 +1,156 @@
+/*
+ * KVM coalesced MMIO
+ *
+ * Copyright (c) 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ */
+
+#include "iodev.h"
+
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include "coalesced_mmio.h"
+
+static int coalesced_mmio_in_range(struct kvm_io_device *this,
+				   gpa_t addr, int len, int is_write)
+{
+	struct kvm_coalesced_mmio_dev *dev =
+				(struct kvm_coalesced_mmio_dev*)this->private;
+	struct kvm_coalesced_mmio_zone *zone;
+	int next;
+	int i;
+
+	if (!is_write)
+		return 0;
+
+	/* kvm->lock is taken by the caller and must be not released before
+         * dev.read/write
+         */
+
+	/* Are we able to batch it ? */
+
+	/* last is the first free entry
+	 * check if we don't meet the first used entry
+	 * there is always one unused entry in the buffer
+	 */
+
+	next = (dev->kvm->coalesced_mmio_ring->last + 1) %
+							KVM_COALESCED_MMIO_MAX;
+	if (next == dev->kvm->coalesced_mmio_ring->first) {
+		/* full */
+		return 0;
+	}
+
+	/* is it in a batchable area ? */
+
+	for (i = 0; i < dev->nb_zones; i++) {
+		zone = &dev->zone[i];
+
+		/* (addr,len) is fully included in
+		 * (zone->addr, zone->size)
+		 */
+
+		if (zone->addr <= addr &&
+		    addr + len <= zone->addr + zone->size)
+			return 1;
+	}
+	return 0;
+}
+
+static void coalesced_mmio_write(struct kvm_io_device *this,
+				 gpa_t addr, int len, const void *val)
+{
+	struct kvm_coalesced_mmio_dev *dev =
+				(struct kvm_coalesced_mmio_dev*)this->private;
+	struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
+
+	/* kvm->lock must be taken by caller before call to in_range()*/
+
+	/* copy data in first free entry of the ring */
+
+	ring->coalesced_mmio[ring->last].phys_addr = addr;
+	ring->coalesced_mmio[ring->last].len = len;
+	memcpy(ring->coalesced_mmio[ring->last].data, val, len);
+	smp_wmb();
+	ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX;
+}
+
+static void coalesced_mmio_destructor(struct kvm_io_device *this)
+{
+	kfree(this);
+}
+
+int kvm_coalesced_mmio_init(struct kvm *kvm)
+{
+	struct kvm_coalesced_mmio_dev *dev;
+
+	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	dev->dev.write  = coalesced_mmio_write;
+	dev->dev.in_range  = coalesced_mmio_in_range;
+	dev->dev.destructor  = coalesced_mmio_destructor;
+	dev->dev.private  = dev;
+	dev->kvm = kvm;
+	kvm->coalesced_mmio_dev = dev;
+	kvm_io_bus_register_dev(&kvm->mmio_bus, &dev->dev);
+
+	return 0;
+}
+
+int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
+				         struct kvm_coalesced_mmio_zone *zone)
+{
+	struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	mutex_lock(&kvm->lock);
+	if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) {
+		mutex_unlock(&kvm->lock);
+		return -ENOBUFS;
+	}
+
+	dev->zone[dev->nb_zones] = *zone;
+	dev->nb_zones++;
+
+	mutex_unlock(&kvm->lock);
+	return 0;
+}
+
+int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
+					   struct kvm_coalesced_mmio_zone *zone)
+{
+	int i;
+	struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev;
+	struct kvm_coalesced_mmio_zone *z;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	mutex_lock(&kvm->lock);
+
+	i = dev->nb_zones;
+	while(i) {
+		z = &dev->zone[i - 1];
+
+		/* unregister all zones
+		 * included in (zone->addr, zone->size)
+		 */
+
+		if (zone->addr <= z->addr &&
+		    z->addr + z->size <= zone->addr + zone->size) {
+			dev->nb_zones--;
+			*z = dev->zone[dev->nb_zones];
+		}
+		i--;
+	}
+
+	mutex_unlock(&kvm->lock);
+
+	return 0;
+}
diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h
new file mode 100644
index 0000000..5ac0ec6
--- /dev/null
+++ b/virt/kvm/coalesced_mmio.h
@@ -0,0 +1,23 @@
+/*
+ * KVM coalesced MMIO
+ *
+ * Copyright (c) 2008 Bull S.A.S.
+ *
+ *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ */
+
+#define KVM_COALESCED_MMIO_ZONE_MAX 100
+
+struct kvm_coalesced_mmio_dev {
+	struct kvm_io_device dev;
+	struct kvm *kvm;
+	int nb_zones;
+	struct kvm_coalesced_mmio_zone zone[KVM_COALESCED_MMIO_ZONE_MAX];
+};
+
+int kvm_coalesced_mmio_init(struct kvm *kvm);
+int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
+                                       struct kvm_coalesced_mmio_zone *zone);
+int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
+                                         struct kvm_coalesced_mmio_zone *zone);
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 4458908..c0d2287 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -146,6 +146,11 @@
 	return kvm_apic_set_irq(vcpu, vector, trig_mode);
 }
 
+static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
+{
+	kvm_inject_nmi(vcpu);
+}
+
 static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
 				       u8 dest_mode)
 {
@@ -239,8 +244,19 @@
 			}
 		}
 		break;
-
-		/* TODO: NMI */
+	case IOAPIC_NMI:
+		for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+			if (!(deliver_bitmask & (1 << vcpu_id)))
+				continue;
+			deliver_bitmask &= ~(1 << vcpu_id);
+			vcpu = ioapic->kvm->vcpus[vcpu_id];
+			if (vcpu)
+				ioapic_inj_nmi(vcpu);
+			else
+				ioapic_debug("NMI to vcpu %d failed\n",
+						vcpu->vcpu_id);
+		}
+		break;
 	default:
 		printk(KERN_WARNING "Unsupported delivery mode %d\n",
 		       delivery_mode);
@@ -291,7 +307,8 @@
 			__kvm_ioapic_update_eoi(ioapic, i);
 }
 
-static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
+static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
+			   int len, int is_write)
 {
 	struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
 
diff --git a/virt/kvm/iodev.h b/virt/kvm/iodev.h
index c14e642..55e8846 100644
--- a/virt/kvm/iodev.h
+++ b/virt/kvm/iodev.h
@@ -27,7 +27,8 @@
 		      gpa_t addr,
 		      int len,
 		      const void *val);
-	int (*in_range)(struct kvm_io_device *this, gpa_t addr);
+	int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len,
+			int is_write);
 	void (*destructor)(struct kvm_io_device *this);
 
 	void             *private;
@@ -49,9 +50,10 @@
 	dev->write(dev, addr, len, val);
 }
 
-static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
+static inline int kvm_iodevice_inrange(struct kvm_io_device *dev,
+				       gpa_t addr, int len, int is_write)
 {
-	return dev->in_range(dev, addr);
+	return dev->in_range(dev, addr, len, is_write);
 }
 
 static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d4eae6a..904d7b7 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -47,6 +47,10 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+#include "coalesced_mmio.h"
+#endif
+
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
@@ -65,6 +69,8 @@
 static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
 			   unsigned long arg);
 
+bool kvm_rebooting;
+
 static inline int valid_vcpu(int n)
 {
 	return likely(n >= 0 && n < KVM_MAX_VCPUS);
@@ -99,10 +105,11 @@
 
 void kvm_flush_remote_tlbs(struct kvm *kvm)
 {
-	int i, cpu;
+	int i, cpu, me;
 	cpumask_t cpus;
 	struct kvm_vcpu *vcpu;
 
+	me = get_cpu();
 	cpus_clear(cpus);
 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
 		vcpu = kvm->vcpus[i];
@@ -111,21 +118,24 @@
 		if (test_and_set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
 			continue;
 		cpu = vcpu->cpu;
-		if (cpu != -1 && cpu != raw_smp_processor_id())
+		if (cpu != -1 && cpu != me)
 			cpu_set(cpu, cpus);
 	}
 	if (cpus_empty(cpus))
-		return;
+		goto out;
 	++kvm->stat.remote_tlb_flush;
 	smp_call_function_mask(cpus, ack_flush, NULL, 1);
+out:
+	put_cpu();
 }
 
 void kvm_reload_remote_mmus(struct kvm *kvm)
 {
-	int i, cpu;
+	int i, cpu, me;
 	cpumask_t cpus;
 	struct kvm_vcpu *vcpu;
 
+	me = get_cpu();
 	cpus_clear(cpus);
 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
 		vcpu = kvm->vcpus[i];
@@ -134,12 +144,14 @@
 		if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
 			continue;
 		cpu = vcpu->cpu;
-		if (cpu != -1 && cpu != raw_smp_processor_id())
+		if (cpu != -1 && cpu != me)
 			cpu_set(cpu, cpus);
 	}
 	if (cpus_empty(cpus))
-		return;
+		goto out;
 	smp_call_function_mask(cpus, ack_flush, NULL, 1);
+out:
+	put_cpu();
 }
 
 
@@ -183,10 +195,23 @@
 static struct kvm *kvm_create_vm(void)
 {
 	struct kvm *kvm = kvm_arch_create_vm();
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	struct page *page;
+#endif
 
 	if (IS_ERR(kvm))
 		goto out;
 
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page) {
+		kfree(kvm);
+		return ERR_PTR(-ENOMEM);
+	}
+	kvm->coalesced_mmio_ring =
+			(struct kvm_coalesced_mmio_ring *)page_address(page);
+#endif
+
 	kvm->mm = current->mm;
 	atomic_inc(&kvm->mm->mm_count);
 	spin_lock_init(&kvm->mmu_lock);
@@ -198,6 +223,9 @@
 	spin_lock(&kvm_lock);
 	list_add(&kvm->vm_list, &vm_list);
 	spin_unlock(&kvm_lock);
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	kvm_coalesced_mmio_init(kvm);
+#endif
 out:
 	return kvm;
 }
@@ -240,6 +268,10 @@
 	spin_unlock(&kvm_lock);
 	kvm_io_bus_destroy(&kvm->pio_bus);
 	kvm_io_bus_destroy(&kvm->mmio_bus);
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	if (kvm->coalesced_mmio_ring != NULL)
+		free_page((unsigned long)kvm->coalesced_mmio_ring);
+#endif
 	kvm_arch_destroy_vm(kvm);
 	mmdrop(mm);
 }
@@ -333,6 +365,7 @@
 	r = -ENOMEM;
 
 	/* Allocate if a slot is being created */
+#ifndef CONFIG_S390
 	if (npages && !new.rmap) {
 		new.rmap = vmalloc(npages * sizeof(struct page *));
 
@@ -373,10 +406,14 @@
 			goto out_free;
 		memset(new.dirty_bitmap, 0, dirty_bytes);
 	}
+#endif /* not defined CONFIG_S390 */
 
 	if (mem->slot >= kvm->nmemslots)
 		kvm->nmemslots = mem->slot + 1;
 
+	if (!npages)
+		kvm_arch_flush_shadow(kvm);
+
 	*memslot = new;
 
 	r = kvm_arch_set_memory_region(kvm, mem, old, user_alloc);
@@ -532,6 +569,7 @@
 	struct page *page[1];
 	unsigned long addr;
 	int npages;
+	pfn_t pfn;
 
 	might_sleep();
 
@@ -544,19 +582,38 @@
 	npages = get_user_pages(current, current->mm, addr, 1, 1, 1, page,
 				NULL);
 
-	if (npages != 1) {
-		get_page(bad_page);
-		return page_to_pfn(bad_page);
-	}
+	if (unlikely(npages != 1)) {
+		struct vm_area_struct *vma;
 
-	return page_to_pfn(page[0]);
+		vma = find_vma(current->mm, addr);
+		if (vma == NULL || addr < vma->vm_start ||
+		    !(vma->vm_flags & VM_PFNMAP)) {
+			get_page(bad_page);
+			return page_to_pfn(bad_page);
+		}
+
+		pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+		BUG_ON(pfn_valid(pfn));
+	} else
+		pfn = page_to_pfn(page[0]);
+
+	return pfn;
 }
 
 EXPORT_SYMBOL_GPL(gfn_to_pfn);
 
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
 {
-	return pfn_to_page(gfn_to_pfn(kvm, gfn));
+	pfn_t pfn;
+
+	pfn = gfn_to_pfn(kvm, gfn);
+	if (pfn_valid(pfn))
+		return pfn_to_page(pfn);
+
+	WARN_ON(!pfn_valid(pfn));
+
+	get_page(bad_page);
+	return bad_page;
 }
 
 EXPORT_SYMBOL_GPL(gfn_to_page);
@@ -569,7 +626,8 @@
 
 void kvm_release_pfn_clean(pfn_t pfn)
 {
-	put_page(pfn_to_page(pfn));
+	if (pfn_valid(pfn))
+		put_page(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_release_pfn_clean);
 
@@ -594,21 +652,25 @@
 
 void kvm_set_pfn_dirty(pfn_t pfn)
 {
-	struct page *page = pfn_to_page(pfn);
-	if (!PageReserved(page))
-		SetPageDirty(page);
+	if (pfn_valid(pfn)) {
+		struct page *page = pfn_to_page(pfn);
+		if (!PageReserved(page))
+			SetPageDirty(page);
+	}
 }
 EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty);
 
 void kvm_set_pfn_accessed(pfn_t pfn)
 {
-	mark_page_accessed(pfn_to_page(pfn));
+	if (pfn_valid(pfn))
+		mark_page_accessed(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed);
 
 void kvm_get_pfn(pfn_t pfn)
 {
-	get_page(pfn_to_page(pfn));
+	if (pfn_valid(pfn))
+		get_page(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_get_pfn);
 
@@ -799,6 +861,10 @@
 	else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET)
 		page = virt_to_page(vcpu->arch.pio_data);
 #endif
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	else if (vmf->pgoff == KVM_COALESCED_MMIO_PAGE_OFFSET)
+		page = virt_to_page(vcpu->kvm->coalesced_mmio_ring);
+#endif
 	else
 		return VM_FAULT_SIGBUS;
 	get_page(page);
@@ -1121,6 +1187,32 @@
 			goto out;
 		break;
 	}
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+	case KVM_REGISTER_COALESCED_MMIO: {
+		struct kvm_coalesced_mmio_zone zone;
+		r = -EFAULT;
+		if (copy_from_user(&zone, argp, sizeof zone))
+			goto out;
+		r = -ENXIO;
+		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone);
+		if (r)
+			goto out;
+		r = 0;
+		break;
+	}
+	case KVM_UNREGISTER_COALESCED_MMIO: {
+		struct kvm_coalesced_mmio_zone zone;
+		r = -EFAULT;
+		if (copy_from_user(&zone, argp, sizeof zone))
+			goto out;
+		r = -ENXIO;
+		r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone);
+		if (r)
+			goto out;
+		r = 0;
+		break;
+	}
+#endif
 	default:
 		r = kvm_arch_vm_ioctl(filp, ioctl, arg);
 	}
@@ -1179,7 +1271,6 @@
 static long kvm_dev_ioctl(struct file *filp,
 			  unsigned int ioctl, unsigned long arg)
 {
-	void __user *argp = (void __user *)arg;
 	long r = -EINVAL;
 
 	switch (ioctl) {
@@ -1196,7 +1287,7 @@
 		r = kvm_dev_ioctl_create_vm();
 		break;
 	case KVM_CHECK_EXTENSION:
-		r = kvm_dev_ioctl_check_extension((long)argp);
+		r = kvm_dev_ioctl_check_extension(arg);
 		break;
 	case KVM_GET_VCPU_MMAP_SIZE:
 		r = -EINVAL;
@@ -1206,6 +1297,9 @@
 #ifdef CONFIG_X86
 		r += PAGE_SIZE;    /* pio data page */
 #endif
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+		r += PAGE_SIZE;    /* coalesced mmio ring page */
+#endif
 		break;
 	case KVM_TRACE_ENABLE:
 	case KVM_TRACE_PAUSE:
@@ -1247,7 +1341,6 @@
 	if (!cpu_isset(cpu, cpus_hardware_enabled))
 		return;
 	cpu_clear(cpu, cpus_hardware_enabled);
-	decache_vcpus_on_cpu(cpu);
 	kvm_arch_hardware_disable(NULL);
 }
 
@@ -1277,6 +1370,18 @@
 	return NOTIFY_OK;
 }
 
+
+asmlinkage void kvm_handle_fault_on_reboot(void)
+{
+	if (kvm_rebooting)
+		/* spin while reset goes on */
+		while (true)
+			;
+	/* Fault while not rebooting.  We want the trace. */
+	BUG();
+}
+EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot);
+
 static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
 		      void *v)
 {
@@ -1286,6 +1391,7 @@
 		 * in vmx root mode.
 		 */
 		printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+		kvm_rebooting = true;
 		on_each_cpu(hardware_disable, NULL, 1);
 	}
 	return NOTIFY_OK;
@@ -1312,14 +1418,15 @@
 	}
 }
 
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
+					  gpa_t addr, int len, int is_write)
 {
 	int i;
 
 	for (i = 0; i < bus->dev_count; i++) {
 		struct kvm_io_device *pos = bus->devs[i];
 
-		if (pos->in_range(pos, addr))
+		if (pos->in_range(pos, addr, len, is_write))
 			return pos;
 	}
 
diff --git a/virt/kvm/kvm_trace.c b/virt/kvm/kvm_trace.c
index 0e49547..58141f3 100644
--- a/virt/kvm/kvm_trace.c
+++ b/virt/kvm/kvm_trace.c
@@ -72,11 +72,7 @@
 	rec.cycle_in 	= p->cycle_in;
 
 	if (rec.cycle_in) {
-		u64 cycle = 0;
-
-		cycle = get_cycles();
-		rec.u.cycle.cycle_lo = (u32)cycle;
-		rec.u.cycle.cycle_hi = (u32)(cycle >> 32);
+		rec.u.cycle.cycle_u64 = get_cycles();
 
 		for (i = 0; i < rec.extra_u32; i++)
 			rec.u.cycle.extra_u32[i] = va_arg(*args, u32);
@@ -114,8 +110,18 @@
 {
 	struct kvm_trace *kt;
 
-	if (!relay_buf_full(buf))
+	if (!relay_buf_full(buf)) {
+		if (!prev_subbuf) {
+			/*
+			 * executed only once when the channel is opened
+			 * save metadata as first record
+			 */
+			subbuf_start_reserve(buf, sizeof(u32));
+			*(u32 *)subbuf = 0x12345678;
+		}
+
 		return 1;
+	}
 
 	kt = buf->chan->private_data;
 	atomic_inc(&kt->lost_records);