Browse Source

Merge branch 'master' into for-linus

Chris Metcalf 15 years ago
parent
commit
cc44826a26
100 changed files with 4464 additions and 1303 deletions
  1. 1 1
      Documentation/DocBook/v4l/v4l2.xml
  2. 4 2
      Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
  3. 152 0
      Documentation/edac.txt
  4. 3 2
      Documentation/video4linux/CARDLIST.saa7134
  5. 1 0
      Documentation/video4linux/gspca.txt
  6. 2 2
      MAINTAINERS
  7. 4 4
      arch/frv/mm/fault.c
  8. 4 10
      arch/m32r/mm/fault.c
  9. 4 5
      arch/mn10300/mm/fault.c
  10. 15 1
      arch/sh/Kconfig
  11. 3 0
      arch/sh/boards/Kconfig
  12. 1 1
      arch/sh/boards/mach-ap325rxa/setup.c
  13. 91 10
      arch/sh/boards/mach-ecovec24/setup.c
  14. 1 1
      arch/sh/boards/mach-migor/setup.c
  15. 4 4
      arch/sh/boards/mach-se/7724/setup.c
  16. 9 4
      arch/sh/boot/romimage/Makefile
  17. 39 3
      arch/sh/boot/romimage/head.S
  18. 72 0
      arch/sh/boot/romimage/mmcif-sh7724.c
  19. 2 0
      arch/sh/boot/romimage/vmlinux.scr
  20. 8 0
      arch/sh/include/asm/io.h
  21. 5 4
      arch/sh/include/asm/machvec.h
  22. 1 0
      arch/sh/include/cpu-sh4/cpu/sh7724.h
  23. 10 0
      arch/sh/include/mach-common/mach/romimage.h
  24. 27 0
      arch/sh/include/mach-ecovec24/mach/romimage.h
  25. 10 0
      arch/sh/include/mach-kfr2r09/mach/romimage.h
  26. 2 1
      arch/sh/kernel/Makefile
  27. 17 2
      arch/sh/kernel/dwarf.c
  28. 0 22
      arch/sh/kernel/io.c
  29. 20 0
      arch/sh/kernel/io_generic.c
  30. 4 0
      arch/sh/kernel/io_trapped.c
  31. 11 6
      arch/sh/kernel/machvec.c
  32. 2 0
      arch/sh/kernel/return_address.c
  33. 1 1
      arch/um/kernel/skas/uaccess.c
  34. 2 0
      arch/x86/include/asm/pci_x86.h
  35. 10 0
      arch/x86/kernel/cpu/mcheck/mce.c
  36. 25 17
      arch/x86/pci/legacy.c
  37. 4 10
      arch/xtensa/mm/fault.c
  38. 14 6
      block/blk-core.c
  39. 79 22
      block/cfq-iosched.c
  40. 5 3
      block/elevator.c
  41. 52 1
      drivers/block/brd.c
  42. 1 1
      drivers/block/cciss_scsi.c
  43. 3 11
      drivers/block/drbd/drbd_int.h
  44. 26 42
      drivers/block/drbd/drbd_main.c
  45. 23 22
      drivers/block/drbd/drbd_receiver.c
  46. 14 40
      drivers/block/drbd/drbd_req.c
  47. 1 0
      drivers/block/drbd/drbd_req.h
  48. 2 22
      drivers/block/drbd/drbd_worker.c
  49. 1 0
      drivers/char/Kconfig
  50. 5 4
      drivers/char/n_gsm.c
  51. 1 1
      drivers/char/vt.c
  52. 3 1
      drivers/char/vt_ioctl.c
  53. 13 9
      drivers/clocksource/sh_cmt.c
  54. 11 9
      drivers/clocksource/sh_tmu.c
  55. 13 0
      drivers/edac/Kconfig
  56. 2 0
      drivers/edac/Makefile
  57. 22 1
      drivers/edac/edac_core.h
  58. 149 26
      drivers/edac/edac_mc_sysfs.c
  59. 61 0
      drivers/edac/edac_mce.c
  60. 2078 0
      drivers/edac/i7core_edac.c
  61. 1 3
      drivers/infiniband/hw/qib/qib_fs.c
  62. 2 1
      drivers/input/serio/Kconfig
  63. 0 1
      drivers/input/tablet/wacom_sys.c
  64. 59 14
      drivers/input/tablet/wacom_wac.c
  65. 1 0
      drivers/input/tablet/wacom_wac.h
  66. 1 1
      drivers/input/touchscreen/Kconfig
  67. 1 1
      drivers/input/touchscreen/ads7846.c
  68. 1 1
      drivers/input/touchscreen/s3c2410_ts.c
  69. 4 8
      drivers/input/touchscreen/tps6507x-ts.c
  70. 2 0
      drivers/media/IR/Kconfig
  71. 41 34
      drivers/media/IR/imon.c
  72. 10 7
      drivers/media/IR/ir-keytable.c
  73. 4 3
      drivers/media/IR/ir-sysfs.c
  74. 2 1
      drivers/media/IR/keymaps/Makefile
  75. 0 90
      drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
  76. 147 0
      drivers/media/IR/keymaps/rc-avermedia-m135a.c
  77. 95 0
      drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
  78. 1 1
      drivers/media/dvb/dm1105/dm1105.c
  79. 11 1
      drivers/media/dvb/dvb-core/dvb_net.c
  80. 3 1
      drivers/media/dvb/dvb-usb/Kconfig
  81. 3 1
      drivers/media/dvb/dvb-usb/cxusb.c
  82. 1 0
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  83. 89 6
      drivers/media/dvb/dvb-usb/ttusb2.c
  84. 1 1
      drivers/media/dvb/firewire/firedtv-1394.c
  85. 0 26
      drivers/media/dvb/frontends/au8522_decoder.c
  86. 1 4
      drivers/media/dvb/frontends/ds3000.c
  87. 4 1
      drivers/media/dvb/frontends/stv6110x.c
  88. 15 0
      drivers/media/dvb/ngene/ngene-cards.c
  89. 55 25
      drivers/media/dvb/ngene/ngene-core.c
  90. 3 12
      drivers/media/dvb/ngene/ngene-dvb.c
  91. 0 1
      drivers/media/dvb/ngene/ngene-i2c.c
  92. 3 0
      drivers/media/dvb/ngene/ngene.h
  93. 3 2
      drivers/media/dvb/ttpci/Kconfig
  94. 1 0
      drivers/media/dvb/ttpci/budget-ci.c
  95. 2 2
      drivers/media/video/Kconfig
  96. 2 1
      drivers/media/video/ak881x.c
  97. 414 345
      drivers/media/video/bw-qcam.c
  98. 0 69
      drivers/media/video/bw-qcam.h
  99. 330 304
      drivers/media/video/c-qcam.c
  100. 1 1
      drivers/media/video/cx18/cx18-alsa-main.c

+ 1 - 1
Documentation/DocBook/v4l/v4l2.xml

@@ -58,7 +58,7 @@ MPEG stream embedded, sliced VBI data format in this specification.
 </contrib>
 	<affiliation>
 	  <address>
-	    <email>awalls@radix.net</email>
+	    <email>awalls@md.metrocast.net</email>
 	  </address>
 	</affiliation>
       </author>

+ 4 - 2
Documentation/DocBook/v4l/vidioc-query-dv-preset.xml

@@ -53,8 +53,10 @@ input</refpurpose>
 automatically, similar to sensing the video standard. To do so, applications
 call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
 &v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
-returned in the preset field of &v4l2-dv-preset;. When detection is not
-possible or fails, the value V4L2_DV_INVALID is returned.</para>
+returned in the preset field of &v4l2-dv-preset;. If the preset could not be
+detected because there was no signal, or the signal was unreliable, or the
+signal did not map to a supported preset, then the value V4L2_DV_INVALID is
+returned.</para>
   </refsect1>
 
   <refsect1>

+ 152 - 0
Documentation/edac.txt

@@ -6,6 +6,8 @@ Written by Doug Thompson <dougthompson@xmission.com>
 7 Dec 2005
 17 Jul 2007	Updated
 
+(c) Mauro Carvalho Chehab <mchehab@redhat.com>
+05 Aug 2009	Nehalem interface
 
 EDAC is maintained and written by:
 
@@ -717,3 +719,153 @@ unique drivers for their hardware systems.
 The 'test_device_edac' sample driver is located at the
 bluesmoke.sourceforge.net project site for EDAC.
 
+=======================================================================
+NEHALEM USAGE OF EDAC APIs
+
+This chapter documents some EXPERIMENTAL mappings for EDAC API to handle
+Nehalem EDAC driver. They will likely be changed on future versions
+of the driver.
+
+Due to the way Nehalem exports Memory Controller data, some adjustments
+were done at i7core_edac driver. This chapter will cover those differences
+
+1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect
+   (QPI). At the driver, the term "socket" means one QPI. This is
+   associated with a physical CPU socket.
+
+   Each MC have 3 physical read channels, 3 physical write channels and
+   3 logic channels. The driver currenty sees it as just 3 channels.
+   Each channel can have up to 3 DIMMs.
+
+   The minimum known unity is DIMMs. There are no information about csrows.
+   As EDAC API maps the minimum unity is csrows, the driver sequencially
+   maps channel/dimm into different csrows.
+
+   For example, suposing the following layout:
+	Ch0 phy rd0, wr0 (0x063f4031): 2 ranks, UDIMMs
+	  dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+	  dimm 1 1024 Mb offset: 4, bank: 8, rank: 1, row: 0x4000, col: 0x400
+        Ch1 phy rd1, wr1 (0x063f4031): 2 ranks, UDIMMs
+	  dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+	Ch2 phy rd3, wr3 (0x063f4031): 2 ranks, UDIMMs
+	  dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+   The driver will map it as:
+	csrow0: channel 0, dimm0
+	csrow1: channel 0, dimm1
+	csrow2: channel 1, dimm0
+	csrow3: channel 2, dimm0
+
+exports one
+   DIMM per csrow.
+
+   Each QPI is exported as a different memory controller.
+
+2) Nehalem MC has the hability to generate errors. The driver implements this
+   functionality via some error injection nodes:
+
+   For injecting a memory error, there are some sysfs nodes, under
+   /sys/devices/system/edac/mc/mc?/:
+
+   inject_addrmatch/*:
+      Controls the error injection mask register. It is possible to specify
+      several characteristics of the address to match an error code:
+         dimm = the affected dimm. Numbers are relative to a channel;
+         rank = the memory rank;
+         channel = the channel that will generate an error;
+         bank = the affected bank;
+         page = the page address;
+         column (or col) = the address column.
+      each of the above values can be set to "any" to match any valid value.
+
+      At driver init, all values are set to any.
+
+      For example, to generate an error at rank 1 of dimm 2, for any channel,
+      any bank, any page, any column:
+		echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+		echo 1 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+	To return to the default behaviour of matching any, you can do:
+		echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+		echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+   inject_eccmask:
+       specifies what bits will have troubles,
+
+   inject_section:
+       specifies what ECC cache section will get the error:
+		3 for both
+		2 for the highest
+		1 for the lowest
+
+   inject_type:
+       specifies the type of error, being a combination of the following bits:
+		bit 0 - repeat
+		bit 1 - ecc
+		bit 2 - parity
+
+       inject_enable starts the error generation when something different
+       than 0 is written.
+
+   All inject vars can be read. root permission is needed for write.
+
+   Datasheet states that the error will only be generated after a write on an
+   address that matches inject_addrmatch. It seems, however, that reading will
+   also produce an error.
+
+   For example, the following code will generate an error for any write access
+   at socket 0, on any DIMM/address on channel 2:
+
+   echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/channel
+   echo 2 >/sys/devices/system/edac/mc/mc0/inject_type
+   echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask
+   echo 3 >/sys/devices/system/edac/mc/mc0/inject_section
+   echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable
+   dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null
+
+   For socket 1, it is needed to replace "mc0" by "mc1" at the above
+   commands.
+
+   The generated error message will look like:
+
+   EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error))
+
+3) Nehalem specific Corrected Error memory counters
+
+   Nehalem have some registers to count memory errors. The driver uses those
+   registers to report Corrected Errors on devices with Registered Dimms.
+
+   However, those counters don't work with Unregistered Dimms. As the chipset
+   offers some counters that also work with UDIMMS (but with a worse level of
+   granularity than the default ones), the driver exposes those registers for
+   UDIMM memories.
+
+   They can be read by looking at the contents of all_channel_counts/
+
+   $ for i in /sys/devices/system/edac/mc/mc0/all_channel_counts/*; do echo $i; cat $i; done
+	/sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0
+	0
+	/sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1
+	0
+	/sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2
+	0
+
+   What happens here is that errors on different csrows, but at the same
+   dimm number will increment the same counter.
+   So, in this memory mapping:
+	csrow0: channel 0, dimm0
+	csrow1: channel 0, dimm1
+	csrow2: channel 1, dimm0
+	csrow3: channel 2, dimm0
+   The hardware will increment udimm0 for an error at the first dimm at either
+	csrow0, csrow2  or csrow3;
+   The hardware will increment udimm1 for an error at the second dimm at either
+	csrow0, csrow2  or csrow3;
+   The hardware will increment udimm2 for an error at the third dimm at either
+	csrow0, csrow2  or csrow3;
+
+4) Standard error counters
+
+   The standard error counters are generated when an mcelog error is received
+   by the driver. Since, with udimm, this is counted by software, it is
+   possible that some errors could be lost. With rdimm's, they displays the
+   contents of the registers

+ 3 - 2
Documentation/video4linux/CARDLIST.saa7134

@@ -176,5 +176,6 @@
 175 -> Leadtek Winfast DTV1000S                 [107d:6655]
 176 -> Beholder BeholdTV 505 RDS                [0000:5051]
 177 -> Hawell HW-404M7
-179 -> Beholder BeholdTV H7			[5ace:7190]
-180 -> Beholder BeholdTV A7			[5ace:7090]
+178 -> Beholder BeholdTV H7                     [5ace:7190]
+179 -> Beholder BeholdTV A7                     [5ace:7090]
+180 -> Avermedia M733A                          [1461:4155,1461:4255]

+ 1 - 0
Documentation/video4linux/gspca.txt

@@ -290,6 +290,7 @@ 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:60ce	USB-PC-Camera-168 (TALK-5067)
 sonixj		0c45:60ec	SN9C105+MO4000
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fc	LG-LIC300

+ 2 - 2
MAINTAINERS

@@ -1731,7 +1731,7 @@ S:	Maintained
 F:	sound/pci/cs5535audio/
 
 CX18 VIDEO4LINUX DRIVER
-M:	Andy Walls <awalls@radix.net>
+M:	Andy Walls <awalls@md.metrocast.net>
 L:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -3165,7 +3165,7 @@ F:	Documentation/hwmon/it87
 F:	drivers/hwmon/it87.c
 
 IVTV VIDEO4LINUX DRIVER
-M:	Andy Walls <awalls@radix.net>
+M:	Andy Walls <awalls@md.metrocast.net>
 L:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git

+ 4 - 4
arch/frv/mm/fault.c

@@ -257,10 +257,10 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
  */
  out_of_memory:
 	up_read(&mm->mmap_sem);
-	printk("VM: killing process %s\n", current->comm);
-	if (user_mode(__frame))
-		do_group_exit(SIGKILL);
-	goto no_context;
+	if (!user_mode(__frame))
+		goto no_context;
+	pagefault_out_of_memory();
+	return;
 
  do_sigbus:
 	up_read(&mm->mmap_sem);

+ 4 - 10
arch/m32r/mm/fault.c

@@ -188,7 +188,6 @@ good_area:
 	if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC))
 	  goto bad_area;
 
-survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -271,15 +270,10 @@ no_context:
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
-	if (is_global_init(tsk)) {
-		yield();
-		down_read(&mm->mmap_sem);
-		goto survive;
-	}
-	printk("VM: killing process %s\n", tsk->comm);
-	if (error_code & ACE_USERMODE)
-		do_group_exit(SIGKILL);
-	goto no_context;
+	if (!(error_code & ACE_USERMODE))
+		goto no_context;
+	pagefault_out_of_memory();
+	return;
 
 do_sigbus:
 	up_read(&mm->mmap_sem);

+ 4 - 5
arch/mn10300/mm/fault.c

@@ -338,11 +338,10 @@ no_context:
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
-	monitor_signal(regs);
-	printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
-	if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
-		do_exit(SIGKILL);
-	goto no_context;
+	if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR)
+		goto no_context;
+	pagefault_out_of_memory();
+	return;
 
 do_sigbus:
 	up_read(&mm->mmap_sem);

+ 15 - 1
arch/sh/Kconfig

@@ -9,7 +9,7 @@ config SUPERH
 	def_bool y
 	select EMBEDDED
 	select HAVE_CLK
-	select HAVE_IDE
+	select HAVE_IDE if HAS_IOPORT
 	select HAVE_LMB
 	select HAVE_OPROFILE
 	select HAVE_GENERIC_DMA_COHERENT
@@ -174,6 +174,9 @@ config ARCH_HAS_DEFAULT_IDLE
 config ARCH_HAS_CPU_IDLE_WAIT
 	def_bool y
 
+config NO_IOPORT
+	bool
+
 config IO_TRAPPED
 	bool
 
@@ -776,6 +779,17 @@ config ENTRY_OFFSET
 	default "0x00010000" if PAGE_SIZE_64KB
 	default "0x00000000"
 
+config ROMIMAGE_MMCIF
+	bool "Include MMCIF loader in romImage (EXPERIMENTAL)"
+	depends on CPU_SUBTYPE_SH7724 && EXPERIMENTAL
+	help
+	  Say Y here to include experimental MMCIF loading code in
+	  romImage. With this enabled it is possible to write the romImage
+	  kernel image to an MMC card and boot the kernel straight from
+	  the reset vector. At reset the processor Mask ROM will load the
+	  first part of the romImage which in turn loads the rest the kernel
+	  image to RAM using the MMCIF hardware block.
+
 choice
 	prompt "Kernel command line"
 	optional

+ 3 - 0
arch/sh/boards/Kconfig

@@ -154,6 +154,7 @@ config SH_SDK7786
 	bool "SDK7786"
 	depends on CPU_SUBTYPE_SH7786
 	select SYS_SUPPORTS_PCI
+	select NO_IOPORT if !PCI
 	help
 	  Select SDK7786 if configuring for a Renesas Technology Europe
 	  SH7786-65nm board.
@@ -190,6 +191,7 @@ config SH_URQUELL
 	depends on CPU_SUBTYPE_SH7786
 	select ARCH_REQUIRE_GPIOLIB
 	select SYS_SUPPORTS_PCI
+	select NO_IOPORT if !PCI
 
 config SH_MIGOR
 	bool "Migo-R"
@@ -286,6 +288,7 @@ config SH_LBOX_RE2
 config SH_X3PROTO
 	bool "SH-X3 Prototype board"
 	depends on CPU_SUBTYPE_SHX3
+	select NO_IOPORT if !PCI
 
 config SH_MAGIC_PANEL_R2
 	bool "Magic Panel R2"

+ 1 - 1
arch/sh/boards/mach-ap325rxa/setup.c

@@ -328,7 +328,7 @@ static struct soc_camera_platform_info camera_info = {
 	.set_capture = camera_set_capture,
 };
 
-struct soc_camera_link camera_link = {
+static struct soc_camera_link camera_link = {
 	.bus_id		= 0,
 	.add_device	= ap325rxa_camera_add,
 	.del_device	= ap325rxa_camera_del,

+ 91 - 10
arch/sh/boards/mach-ecovec24/setup.c

@@ -12,6 +12,8 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -26,7 +28,6 @@
 #include <linux/mmc/host.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
 #include <video/sh_mobile_lcdc.h>
 #include <sound/sh_fsi.h>
 #include <media/sh_mobile_ceu.h>
@@ -139,7 +140,7 @@ static struct resource sh_eth_resources[] = {
 	},
 };
 
-struct sh_eth_plat_data sh_eth_plat = {
+static struct sh_eth_plat_data sh_eth_plat = {
 	.phy = 0x1f, /* SMSC LAN8700 */
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 	.ether_link_active_low = 1
@@ -159,7 +160,7 @@ static struct platform_device sh_eth_device = {
 };
 
 /* USB0 host */
-void usb0_port_power(int port, int power)
+static void usb0_port_power(int port, int power)
 {
 	gpio_set_value(GPIO_PTB4, power);
 }
@@ -195,7 +196,7 @@ static struct platform_device usb0_host_device = {
 };
 
 /* USB1 host/function */
-void usb1_port_power(int port, int power)
+static void usb1_port_power(int port, int power)
 {
 	gpio_set_value(GPIO_PTB5, power);
 }
@@ -421,7 +422,7 @@ static int ts_init(void)
 	return 0;
 }
 
-struct tsc2007_platform_data tsc2007_info = {
+static struct tsc2007_platform_data tsc2007_info = {
 	.model			= 2007,
 	.x_plate_ohms		= 180,
 	.get_pendown_state	= ts_get_pendown_state,
@@ -436,7 +437,7 @@ static struct i2c_board_info ts_i2c_clients = {
 };
 
 #ifdef CONFIG_MFD_SH_MOBILE_SDHI
-/* SHDI0 */
+/* SDHI0 */
 static void sdhi0_set_pwr(struct platform_device *pdev, int state)
 {
 	gpio_set_value(GPIO_PTB6, state);
@@ -474,7 +475,8 @@ static struct platform_device sdhi0_device = {
 	},
 };
 
-/* SHDI1 */
+#if !defined(CONFIG_MMC_SH_MMCIF)
+/* SDHI1 */
 static void sdhi1_set_pwr(struct platform_device *pdev, int state)
 {
 	gpio_set_value(GPIO_PTB7, state);
@@ -511,6 +513,7 @@ static struct platform_device sdhi1_device = {
 		.hwblk_id = HWBLK_SDHI1,
 	},
 };
+#endif /* CONFIG_MMC_SH_MMCIF */
 
 #else
 
@@ -720,7 +723,7 @@ static struct clk fsimckb_clk = {
 	.rate		= 0, /* unknown */
 };
 
-struct sh_fsi_platform_info fsi_info = {
+static struct sh_fsi_platform_info fsi_info = {
 	.portb_flags = SH_FSI_BRS_INV |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_IN_SLAVE_MODE |
@@ -777,7 +780,7 @@ static struct platform_device irda_device = {
 #include <media/ak881x.h>
 #include <media/sh_vou.h>
 
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
 	.flags = AK881X_IF_MODE_SLAVE,
 };
 
@@ -786,7 +789,7 @@ static struct i2c_board_info ak8813 = {
 	.platform_data = &ak881x_pdata,
 };
 
-struct sh_vou_pdata sh_vou_pdata = {
+static struct sh_vou_pdata sh_vou_pdata = {
 	.bus_fmt	= SH_VOU_BUS_8BIT,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,
@@ -819,6 +822,58 @@ static struct platform_device vou_device = {
 	},
 };
 
+#if defined(CONFIG_MMC_SH_MMCIF)
+/* SH_MMCIF */
+static void mmcif_set_pwr(struct platform_device *pdev, int state)
+{
+	gpio_set_value(GPIO_PTB7, state);
+}
+
+static void mmcif_down_pwr(struct platform_device *pdev)
+{
+	gpio_set_value(GPIO_PTB7, 0);
+}
+
+static struct resource sh_mmcif_resources[] = {
+	[0] = {
+		.name	= "SH_MMCIF",
+		.start	= 0xA4CA0000,
+		.end	= 0xA4CA00FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		/* MMC2I */
+		.start	= 29,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		/* MMC3I */
+		.start	= 30,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_plat = {
+	.set_pwr	= mmcif_set_pwr,
+	.down_pwr	= mmcif_down_pwr,
+	.sup_pclk	= 0, /* SH7724: Max Pclk/2 */
+	.caps		= MMC_CAP_4_BIT_DATA |
+			  MMC_CAP_8_BIT_DATA |
+			  MMC_CAP_NEEDS_POLL,
+	.ocr		= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct platform_device sh_mmcif_device = {
+	.name		= "sh_mmcif",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= &sh_mmcif_plat,
+	},
+	.num_resources	= ARRAY_SIZE(sh_mmcif_resources),
+	.resource	= sh_mmcif_resources,
+};
+#endif
+
 static struct platform_device *ecovec_devices[] __initdata = {
 	&heartbeat_device,
 	&nor_flash_device,
@@ -831,7 +886,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
 	&keysc_device,
 #ifdef CONFIG_MFD_SH_MOBILE_SDHI
 	&sdhi0_device,
+#if !defined(CONFIG_MMC_SH_MMCIF)
 	&sdhi1_device,
+#endif
 #else
 	&msiof0_device,
 #endif
@@ -841,6 +898,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
 	&fsi_device,
 	&irda_device,
 	&vou_device,
+#if defined(CONFIG_MMC_SH_MMCIF)
+	&sh_mmcif_device,
+#endif
 };
 
 #ifdef CONFIG_I2C
@@ -1134,6 +1194,7 @@ static int __init arch_setup(void)
 	gpio_request(GPIO_PTB6, NULL);
 	gpio_direction_output(GPIO_PTB6, 0);
 
+#if !defined(CONFIG_MMC_SH_MMCIF)
 	/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
 	gpio_request(GPIO_FN_SDHI1CD,  NULL);
 	gpio_request(GPIO_FN_SDHI1WP,  NULL);
@@ -1148,6 +1209,7 @@ static int __init arch_setup(void)
 
 	/* I/O buffer drive ability is high for SDHI1 */
 	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+#endif /* CONFIG_MMC_SH_MMCIF */
 #else
 	/* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */
 	gpio_request(GPIO_FN_MSIOF0_TXD, NULL);
@@ -1223,6 +1285,25 @@ static int __init arch_setup(void)
 	gpio_request(GPIO_PTU5, NULL);
 	gpio_direction_output(GPIO_PTU5, 0);
 
+#if defined(CONFIG_MMC_SH_MMCIF)
+	/* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
+	gpio_request(GPIO_FN_MMC_D7, NULL);
+	gpio_request(GPIO_FN_MMC_D6, NULL);
+	gpio_request(GPIO_FN_MMC_D5, NULL);
+	gpio_request(GPIO_FN_MMC_D4, NULL);
+	gpio_request(GPIO_FN_MMC_D3, NULL);
+	gpio_request(GPIO_FN_MMC_D2, NULL);
+	gpio_request(GPIO_FN_MMC_D1, NULL);
+	gpio_request(GPIO_FN_MMC_D0, NULL);
+	gpio_request(GPIO_FN_MMC_CLK, NULL);
+	gpio_request(GPIO_FN_MMC_CMD, NULL);
+	gpio_request(GPIO_PTB7, NULL);
+	gpio_direction_output(GPIO_PTB7, 0);
+
+	/* I/O buffer drive ability is high for MMCIF */
+	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+#endif
+
 	/* enable I2C device */
 	i2c_register_board_info(0, i2c0_devices,
 				ARRAY_SIZE(i2c0_devices));

+ 1 - 1
arch/sh/boards/mach-migor/setup.c

@@ -181,7 +181,7 @@ static int migor_nand_flash_ready(struct mtd_info *mtd)
 	return gpio_get_value(GPIO_PTA1); /* NAND_RBn */
 }
 
-struct platform_nand_data migor_nand_flash_data = {
+static struct platform_nand_data migor_nand_flash_data = {
 	.chip = {
 		.nr_chips = 1,
 		.partitions = migor_nand_flash_partitions,

+ 4 - 4
arch/sh/boards/mach-se/7724/setup.c

@@ -283,7 +283,7 @@ static struct clk fsimcka_clk = {
 };
 
 /* change J20, J21, J22 pin to 1-2 connection to use slave mode */
-struct sh_fsi_platform_info fsi_info = {
+static struct sh_fsi_platform_info fsi_info = {
 	.porta_flags = SH_FSI_BRS_INV |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_IN_SLAVE_MODE |
@@ -371,7 +371,7 @@ static struct resource sh_eth_resources[] = {
 	},
 };
 
-struct sh_eth_plat_data sh_eth_plat = {
+static struct sh_eth_plat_data sh_eth_plat = {
 	.phy = 0x1f, /* SMSC LAN8187 */
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 };
@@ -535,7 +535,7 @@ static struct platform_device irda_device = {
 #include <media/ak881x.h>
 #include <media/sh_vou.h>
 
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
 	.flags = AK881X_IF_MODE_SLAVE,
 };
 
@@ -545,7 +545,7 @@ static struct i2c_board_info ak8813 = {
 	.platform_data = &ak881x_pdata,
 };
 
-struct sh_vou_pdata sh_vou_pdata = {
+static struct sh_vou_pdata sh_vou_pdata = {
 	.bus_fmt	= SH_VOU_BUS_8BIT,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,

+ 9 - 4
arch/sh/boot/romimage/Makefile

@@ -1,16 +1,21 @@
 #
 # linux/arch/sh/boot/romimage/Makefile
 #
-# create an image suitable for burning to flash from zImage
+# create an romImage file suitable for burning to flash/mmc from zImage
 #
 
 targets		:= vmlinux head.o zeropage.bin piggy.o
+load-y		:= 0
 
-OBJECTS = $(obj)/head.o
-LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart \
+mmcif-load-$(CONFIG_CPU_SUBTYPE_SH7724)	:= 0xe5200000 # ILRAM
+mmcif-obj-$(CONFIG_CPU_SUBTYPE_SH7724)	:= $(obj)/mmcif-sh7724.o
+load-$(CONFIG_ROMIMAGE_MMCIF)		:= $(mmcif-load-y)
+obj-$(CONFIG_ROMIMAGE_MMCIF)		:= $(mmcif-obj-y)
+
+LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(load-y) -e romstart \
 		   -T $(obj)/../../kernel/vmlinux.lds
 
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+$(obj)/vmlinux: $(obj)/head.o $(obj-y) $(obj)/piggy.o FORCE
 	$(call if_changed,ld)
 	@:
 

+ 39 - 3
arch/sh/boot/romimage/head.S

@@ -12,8 +12,40 @@ romstart:
 	/* include board specific setup code */
 #include <mach/romimage.h>
 
+#ifdef CONFIG_ROMIMAGE_MMCIF
+	/* load the romImage to above the empty zero page */
+	mov.l	empty_zero_page_dst, r4
+	mov.l	empty_zero_page_dst_adj, r5
+	add	r5, r4
+	mov.l	bytes_to_load, r5
+	mov.l	loader_function, r7
+	jsr	@r7
+	 mov	r4, r15
+
+	mov.l	empty_zero_page_dst, r4
+	mov.l	empty_zero_page_dst_adj, r5
+	add	r5, r4
+	mov.l	loaded_code_offs, r5
+	add	r5, r4
+	jmp	@r4
+	 nop
+
+	.balign 4
+empty_zero_page_dst_adj:
+	.long	PAGE_SIZE
+bytes_to_load:
+	.long	end_data - romstart
+loader_function:
+	.long	mmcif_loader
+loaded_code_offs:
+	.long	loaded_code - romstart
+loaded_code:
+#endif /* CONFIG_ROMIMAGE_MMCIF */
+
 	/* copy the empty_zero_page contents to where vmlinux expects it */
-	mova	empty_zero_page_src, r0
+	mova	extra_data_pos, r0
+	mov.l	extra_data_size, r1
+	add	r1, r0
 	mov.l	empty_zero_page_dst, r1
 	mov	#(PAGE_SHIFT - 4), r4
 	mov	#1, r3
@@ -37,7 +69,9 @@ romstart:
 	mov	#PAGE_SHIFT, r4
 	mov	#1, r1
 	shld	r4, r1
-	mova	empty_zero_page_src, r0
+	mova	extra_data_pos, r0
+	add	r1, r0
+	mov.l	extra_data_size, r1
 	add	r1, r0
 	jmp	@r0
 	 nop
@@ -45,4 +79,6 @@ romstart:
 	.align 2
 empty_zero_page_dst:
 	.long	_text
-empty_zero_page_src:
+extra_data_pos:
+extra_data_size:
+	.long	zero_page_pos - extra_data_pos

+ 72 - 0
arch/sh/boot/romimage/mmcif-sh7724.c

@@ -0,0 +1,72 @@
+/*
+ * sh7724 MMCIF loader
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * 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/mmc/sh_mmcif.h>
+#include <mach/romimage.h>
+
+#define MMCIF_BASE      (void __iomem *)0xa4ca0000
+
+#define MSTPCR2		0xa4150038
+#define PTWCR		0xa4050146
+#define PTXCR		0xa4050148
+#define PSELA		0xa405014e
+#define PSELE		0xa4050156
+#define HIZCRC		0xa405015c
+#define DRVCRA		0xa405018a
+
+enum { MMCIF_PROGRESS_ENTER, MMCIF_PROGRESS_INIT,
+       MMCIF_PROGRESS_LOAD, MMCIF_PROGRESS_DONE };
+
+/* SH7724 specific MMCIF loader
+ *
+ * loads the romImage from an MMC card starting from block 512
+ * use the following line to write the romImage to an MMC card
+ * # dd if=arch/sh/boot/romImage of=/dev/sdx bs=512 seek=512
+ */
+asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
+{
+	mmcif_update_progress(MMCIF_PROGRESS_ENTER);
+
+	/* enable clock to the MMCIF hardware block */
+	__raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2);
+
+	/* setup pins D7-D0 */
+	__raw_writew(0x0000, PTWCR);
+
+	/* setup pins MMC_CLK, MMC_CMD */
+	__raw_writew(__raw_readw(PTXCR) & ~0x000f, PTXCR);
+
+	/* select D3-D0 pin function */
+	__raw_writew(__raw_readw(PSELA) & ~0x2000, PSELA);
+
+	/* select D7-D4 pin function */
+	__raw_writew(__raw_readw(PSELE) & ~0x3000, PSELE);
+
+	/* disable Hi-Z for the MMC pins */
+	__raw_writew(__raw_readw(HIZCRC) & ~0x0620, HIZCRC);
+
+	/* high drive capability for MMC pins */
+	__raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA);
+
+	mmcif_update_progress(MMCIF_PROGRESS_INIT);
+
+	/* setup MMCIF hardware */
+	sh_mmcif_boot_init(MMCIF_BASE);
+
+	mmcif_update_progress(MMCIF_PROGRESS_LOAD);
+
+	/* load kernel via MMCIF interface */
+	sh_mmcif_boot_slurp(MMCIF_BASE, buf, no_bytes);
+
+	/* disable clock to the MMCIF hardware block */
+	__raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2);
+
+	mmcif_update_progress(MMCIF_PROGRESS_DONE);
+}

+ 2 - 0
arch/sh/boot/romimage/vmlinux.scr

@@ -1,6 +1,8 @@
 SECTIONS
 {
   .text : {
+	zero_page_pos = .;
 	*(.data)
+	end_data = .;
 	}
 }

+ 8 - 0
arch/sh/include/asm/io.h

@@ -39,6 +39,8 @@
 #include <asm/io_generic.h>
 #include <asm/io_trapped.h>
 
+#ifdef CONFIG_HAS_IOPORT
+
 #define inb(p)			sh_mv.mv_inb((p))
 #define inw(p)			sh_mv.mv_inw((p))
 #define inl(p)			sh_mv.mv_inl((p))
@@ -60,6 +62,8 @@
 #define outsw(p,b,c)		sh_mv.mv_outsw((p), (b), (c))
 #define outsl(p,b,c)		sh_mv.mv_outsl((p), (b), (c))
 
+#endif
+
 #define __raw_writeb(v,a)	(__chk_io_ptr(a), *(volatile u8  __force *)(a) = (v))
 #define __raw_writew(v,a)	(__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v))
 #define __raw_writel(v,a)	(__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v))
@@ -240,6 +244,8 @@ __BUILD_MEMORY_STRING(q, u64)
 
 #define IO_SPACE_LIMIT 0xffffffff
 
+#ifdef CONFIG_HAS_IOPORT
+
 /*
  * This function provides a method for the generic case where a
  * board-specific ioport_map simply needs to return the port + some
@@ -255,6 +261,8 @@ static inline void __set_io_port_base(unsigned long pbase)
 
 #define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n))
 
+#endif
+
 /* We really want to try and get these to memcpy etc */
 void memcpy_fromio(void *, const volatile void __iomem *, unsigned long);
 void memcpy_toio(volatile void __iomem *, const void *, unsigned long);

+ 5 - 4
arch/sh/include/asm/machvec.h

@@ -19,6 +19,10 @@ struct sh_machine_vector {
 	const char *mv_name;
 	int mv_nr_irqs;
 
+	int (*mv_irq_demux)(int irq);
+	void (*mv_init_irq)(void);
+
+#ifdef CONFIG_HAS_IOPORT
 	u8 (*mv_inb)(unsigned long);
 	u16 (*mv_inw)(unsigned long);
 	u32 (*mv_inl)(unsigned long);
@@ -40,12 +44,9 @@ struct sh_machine_vector {
 	void (*mv_outsw)(unsigned long, const void *src, unsigned long count);
 	void (*mv_outsl)(unsigned long, const void *src, unsigned long count);
 
-	int (*mv_irq_demux)(int irq);
-
-	void (*mv_init_irq)(void);
-
 	void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
 	void (*mv_ioport_unmap)(void __iomem *);
+#endif
 
 	int (*mv_clk_init)(void);
 	int (*mv_mode_pins)(void);

+ 1 - 0
arch/sh/include/cpu-sh4/cpu/sh7724.h

@@ -9,6 +9,7 @@
  * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
  * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
  * MD8: Test Mode
+ * BOOT: FBR - Boot Mode (L: MMCIF, H: Area0)
  */
 
 /* Pin Function Controller:

+ 10 - 0
arch/sh/include/mach-common/mach/romimage.h

@@ -1 +1,11 @@
+#ifdef __ASSEMBLY__
+
 /* do nothing here by default */
+
+#else /* __ASSEMBLY__ */
+
+extern inline void mmcif_update_progress(int nr)
+{
+}
+
+#endif /* __ASSEMBLY__ */

+ 27 - 0
arch/sh/include/mach-ecovec24/mach/romimage.h

@@ -1,3 +1,5 @@
+#ifdef __ASSEMBLY__
+
 /* EcoVec board specific boot code:
  * converts the "partner-jet-script.txt" script into assembly
  * the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,28 @@
 	.align 2
 1 :	.long 0xa8000000
 2 :
+
+#else /* __ASSEMBLY__ */
+
+/* Ecovec board specific information:
+ *
+ * Set the following to enable MMCIF boot from the MMC card in CN12:
+ *
+ * DS1.5 = OFF (SH BOOT pin set to L)
+ * DS2.6 = OFF (Select MMCIF on CN12 instead of SDHI1)
+ * DS2.7 = ON  (Select MMCIF on CN12 instead of SDHI1)
+ *
+ */
+#define HIZCRA		0xa4050158
+#define PGDR		0xa405012c
+
+extern inline void mmcif_update_progress(int nr)
+{
+	/* disable Hi-Z for LED pins */
+	__raw_writew(__raw_readw(HIZCRA) & ~(1 << 1), HIZCRA);
+
+	/* update progress on LED4, LED5, LED6 and LED7 */
+	__raw_writeb(1 << (nr - 1), PGDR);
+}
+
+#endif /* __ASSEMBLY__ */

+ 10 - 0
arch/sh/include/mach-kfr2r09/mach/romimage.h

@@ -1,3 +1,5 @@
+#ifdef __ASSEMBLY__
+
 /* kfr2r09 board specific boot code:
  * converts the "partner-jet-script.txt" script into assembly
  * the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,11 @@
 	.align 2
 1:	.long 0xa8000000
 2:
+
+#else /* __ASSEMBLY__ */
+
+extern inline void mmcif_update_progress(int nr)
+{
+}
+
+#endif /* __ASSEMBLY__ */

+ 2 - 1
arch/sh/kernel/Makefile

@@ -12,7 +12,7 @@ endif
 CFLAGS_REMOVE_return_address.o = -pg
 
 obj-y	:= clkdev.o debugtraps.o dma-nommu.o dumpstack.o 		\
-	   idle.o io.o io_generic.o irq.o				\
+	   idle.o io.o irq.o						\
 	   irq_$(BITS).o machvec.o nmi_debug.o process.o		\
 	   process_$(BITS).o ptrace_$(BITS).o				\
 	   reboot.o return_address.o					\
@@ -39,6 +39,7 @@ obj-$(CONFIG_DUMP_CODE)		+= disassemble.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o
 obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.o
+obj-$(CONFIG_HAS_IOPORT)	+= io_generic.o
 
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)	+= localtimer.o

+ 17 - 2
arch/sh/kernel/dwarf.c

@@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock);
 
 static struct dwarf_cie *cached_cie;
 
+static unsigned int dwarf_unwinder_ready;
+
 /**
  *	dwarf_frame_alloc_reg - allocate memory for a DWARF register
  *	@frame: the DWARF frame whose list of registers we insert on
@@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
 	struct dwarf_reg *reg;
 	unsigned long addr;
 
+	/*
+	 * If we've been called in to before initialization has
+	 * completed, bail out immediately.
+	 */
+	if (!dwarf_unwinder_ready)
+		return NULL;
+
 	/*
 	 * If we're starting at the top of the stack we need get the
 	 * contents of a physical register to get the CFA in order to
@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod)
  */
 static int __init dwarf_unwinder_init(void)
 {
-	int err;
+	int err = -ENOMEM;
 
 	dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
 			sizeof(struct dwarf_frame), 0,
@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void)
 					  mempool_alloc_slab,
 					  mempool_free_slab,
 					  dwarf_frame_cachep);
+	if (!dwarf_frame_pool)
+		goto out;
 
 	dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
 					 mempool_alloc_slab,
 					 mempool_free_slab,
 					 dwarf_reg_cachep);
+	if (!dwarf_reg_pool)
+		goto out;
 
 	err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
 	if (err)
@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void)
 	if (err)
 		goto out;
 
+	dwarf_unwinder_ready = 1;
+
 	return 0;
 
 out:
 	printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
 	dwarf_unwinder_cleanup();
-	return -EINVAL;
+	return err;
 }
 early_initcall(dwarf_unwinder_init);

+ 0 - 22
arch/sh/kernel/io.c

@@ -112,25 +112,3 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
         }
 }
 EXPORT_SYMBOL(memset_io);
-
-#ifndef CONFIG_GENERIC_IOMAP
-
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
-	void __iomem *ret;
-
-	ret = __ioport_map_trapped(port, nr);
-	if (ret)
-		return ret;
-
-	return __ioport_map(port, nr);
-}
-EXPORT_SYMBOL(ioport_map);
-
-void ioport_unmap(void __iomem *addr)
-{
-	sh_mv.mv_ioport_unmap(addr);
-}
-EXPORT_SYMBOL(ioport_unmap);
-
-#endif /* CONFIG_GENERIC_IOMAP */

+ 20 - 0
arch/sh/kernel/io_generic.c

@@ -158,3 +158,23 @@ void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
 void generic_ioport_unmap(void __iomem *addr)
 {
 }
+
+#ifndef CONFIG_GENERIC_IOMAP
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+	void __iomem *ret;
+
+	ret = __ioport_map_trapped(port, nr);
+	if (ret)
+		return ret;
+
+	return __ioport_map(port, nr);
+}
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+	sh_mv.mv_ioport_unmap(addr);
+}
+EXPORT_SYMBOL(ioport_unmap);
+#endif /* CONFIG_GENERIC_IOMAP */

+ 4 - 0
arch/sh/kernel/io_trapped.c

@@ -91,10 +91,14 @@ int register_trapped_io(struct trapped_io *tiop)
 	tiop->magic = IO_TRAPPED_MAGIC;
 	INIT_LIST_HEAD(&tiop->list);
 	spin_lock_irq(&trapped_lock);
+#ifdef CONFIG_HAS_IOPORT
 	if (flags & IORESOURCE_IO)
 		list_add(&tiop->list, &trapped_io);
+#endif
+#ifdef CONFIG_HAS_IOMEM
 	if (flags & IORESOURCE_MEM)
 		list_add(&tiop->list, &trapped_mem);
+#endif
 	spin_unlock_irq(&trapped_lock);
 
 	return 0;

+ 11 - 6
arch/sh/kernel/machvec.c

@@ -118,6 +118,14 @@ void __init sh_mv_setup(void)
 		sh_mv.mv_##elem = generic_##elem; \
 } while (0)
 
+#ifdef CONFIG_HAS_IOPORT
+
+#ifdef P2SEG
+	__set_io_port_base(P2SEG);
+#else
+	__set_io_port_base(0);
+#endif
+
 	mv_set(inb);	mv_set(inw);	mv_set(inl);
 	mv_set(outb);	mv_set(outw);	mv_set(outl);
 
@@ -129,16 +137,13 @@ void __init sh_mv_setup(void)
 
 	mv_set(ioport_map);
 	mv_set(ioport_unmap);
+
+#endif
+
 	mv_set(irq_demux);
 	mv_set(mode_pins);
 	mv_set(mem_init);
 
 	if (!sh_mv.mv_nr_irqs)
 		sh_mv.mv_nr_irqs = NR_IRQS;
-
-#ifdef P2SEG
-	__set_io_port_base(P2SEG);
-#else
-	__set_io_port_base(0);
-#endif
 }

+ 2 - 0
arch/sh/kernel/return_address.c

@@ -24,6 +24,8 @@ void *return_address(unsigned int depth)
 		struct dwarf_frame *tmp;
 
 		tmp = dwarf_unwind_stack(ra, frame);
+		if (!tmp)
+			return NULL;
 
 		if (frame)
 			dwarf_free_frame(frame);

+ 1 - 1
arch/um/kernel/skas/uaccess.c

@@ -81,7 +81,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,
 
 	current->thread.fault_catcher = NULL;
 
-	kunmap_atomic(page, KM_UML_USERCOPY);
+	kunmap_atomic((void *)addr, KM_UML_USERCOPY);
 
 	return n;
 }

+ 2 - 0
arch/x86/include/asm/pci_x86.h

@@ -53,6 +53,8 @@ extern int pcibios_last_bus;
 extern struct pci_bus *pci_root_bus;
 extern struct pci_ops pci_root_ops;
 
+void pcibios_scan_specific_bus(int busn);
+
 /* pci-irq.c */
 
 struct irq_info {

+ 10 - 0
arch/x86/kernel/cpu/mcheck/mce.c

@@ -36,6 +36,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/debugfs.h>
+#include <linux/edac_mce.h>
 
 #include <asm/processor.h>
 #include <asm/hw_irq.h>
@@ -168,6 +169,15 @@ void mce_log(struct mce *mce)
 	for (;;) {
 		entry = rcu_dereference_check_mce(mcelog.next);
 		for (;;) {
+			/*
+			 * If edac_mce is enabled, it will check the error type
+			 * and will process it, if it is a known error.
+			 * Otherwise, the error will be sent through mcelog
+			 * interface
+			 */
+			if (edac_mce_parse(mce))
+				return;
+
 			/*
 			 * When the buffer fills up discard new entries.
 			 * Assume that the earlier errors are the more

+ 25 - 17
arch/x86/pci/legacy.c

@@ -11,28 +11,14 @@
  */
 static void __devinit pcibios_fixup_peer_bridges(void)
 {
-	int n, devfn;
-	long node;
+	int n;
 
 	if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
 		return;
 	DBG("PCI: Peer bridge fixup\n");
 
-	for (n=0; n <= pcibios_last_bus; n++) {
-		u32 l;
-		if (pci_find_bus(0, n))
-			continue;
-		node = get_mp_bus_to_node(n);
-		for (devfn = 0; devfn < 256; devfn += 8) {
-			if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
-			    l != 0x0000 && l != 0xffff) {
-				DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
-				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
-				pci_scan_bus_on_node(n, &pci_root_ops, node);
-				break;
-			}
-		}
-	}
+	for (n=0; n <= pcibios_last_bus; n++)
+		pcibios_scan_specific_bus(n);
 }
 
 int __init pci_legacy_init(void)
@@ -50,6 +36,28 @@ int __init pci_legacy_init(void)
 	return 0;
 }
 
+void pcibios_scan_specific_bus(int busn)
+{
+	int devfn;
+	long node;
+	u32 l;
+
+	if (pci_find_bus(0, busn))
+		return;
+
+	node = get_mp_bus_to_node(busn);
+	for (devfn = 0; devfn < 256; devfn += 8) {
+		if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
+		    l != 0x0000 && l != 0xffff) {
+			DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
+			printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
+			pci_scan_bus_on_node(busn, &pci_root_ops, node);
+			return;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
+
 int __init pci_subsys_init(void)
 {
 	/*

+ 4 - 10
arch/xtensa/mm/fault.c

@@ -105,7 +105,6 @@ good_area:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-survive:
 	fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		if (fault & VM_FAULT_OOM)
@@ -146,15 +145,10 @@ bad_area:
 	 */
 out_of_memory:
 	up_read(&mm->mmap_sem);
-	if (is_global_init(current)) {
-		yield();
-		down_read(&mm->mmap_sem);
-		goto survive;
-	}
-	printk("VM: killing process %s\n", current->comm);
-	if (user_mode(regs))
-		do_group_exit(SIGKILL);
-	bad_page_fault(regs, address, SIGKILL);
+	if (!user_mode(regs))
+		bad_page_fault(regs, address, SIGKILL);
+	else
+		pagefault_out_of_memory();
 	return;
 
 do_sigbus:

+ 14 - 6
block/blk-core.c

@@ -467,6 +467,9 @@ static int blk_init_free_list(struct request_queue *q)
 {
 	struct request_list *rl = &q->rq;
 
+	if (unlikely(rl->rq_pool))
+		return 0;
+
 	rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
 	rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
 	rl->elvpriv = 0;
@@ -570,9 +573,17 @@ EXPORT_SYMBOL(blk_init_queue);
 struct request_queue *
 blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 {
-	struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+	struct request_queue *uninit_q, *q;
+
+	uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+	if (!uninit_q)
+		return NULL;
+
+	q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
+	if (!q)
+		blk_cleanup_queue(uninit_q);
 
-	return blk_init_allocated_queue_node(q, rfn, lock, node_id);
+	return q;
 }
 EXPORT_SYMBOL(blk_init_queue_node);
 
@@ -592,10 +603,8 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
 		return NULL;
 
 	q->node = node_id;
-	if (blk_init_free_list(q)) {
-		kmem_cache_free(blk_requestq_cachep, q);
+	if (blk_init_free_list(q))
 		return NULL;
-	}
 
 	q->request_fn		= rfn;
 	q->prep_rq_fn		= NULL;
@@ -618,7 +627,6 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
 		return q;
 	}
 
-	blk_put_queue(q);
 	return NULL;
 }
 EXPORT_SYMBOL(blk_init_allocated_queue_node);

+ 79 - 22
block/cfq-iosched.c

@@ -64,6 +64,9 @@ static DEFINE_PER_CPU(unsigned long, cfq_ioc_count);
 static struct completion *ioc_gone;
 static DEFINE_SPINLOCK(ioc_gone_lock);
 
+static DEFINE_SPINLOCK(cic_index_lock);
+static DEFINE_IDA(cic_index_ida);
+
 #define CFQ_PRIO_LISTS		IOPRIO_BE_NR
 #define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
 #define cfq_class_rt(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
@@ -271,6 +274,7 @@ struct cfq_data {
 	unsigned int cfq_latency;
 	unsigned int cfq_group_isolation;
 
+	unsigned int cic_index;
 	struct list_head cic_list;
 
 	/*
@@ -430,6 +434,24 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic,
 	cic->cfqq[is_sync] = cfqq;
 }
 
+#define CIC_DEAD_KEY	1ul
+#define CIC_DEAD_INDEX_SHIFT	1
+
+static inline void *cfqd_dead_key(struct cfq_data *cfqd)
+{
+	return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY);
+}
+
+static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic)
+{
+	struct cfq_data *cfqd = cic->key;
+
+	if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY))
+		return NULL;
+
+	return cfqd;
+}
+
 /*
  * We regard a request as SYNC, if it's either a read or has the SYNC bit
  * set (in which case it could also be direct WRITE).
@@ -2510,11 +2532,12 @@ static void cfq_cic_free(struct cfq_io_context *cic)
 static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic)
 {
 	unsigned long flags;
+	unsigned long dead_key = (unsigned long) cic->key;
 
-	BUG_ON(!cic->dead_key);
+	BUG_ON(!(dead_key & CIC_DEAD_KEY));
 
 	spin_lock_irqsave(&ioc->lock, flags);
-	radix_tree_delete(&ioc->radix_root, cic->dead_key);
+	radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT);
 	hlist_del_rcu(&cic->cic_list);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 
@@ -2537,15 +2560,10 @@ static void cfq_free_io_context(struct io_context *ioc)
 	__call_for_each_cic(ioc, cic_free_func);
 }
 
-static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static void cfq_put_cooperator(struct cfq_queue *cfqq)
 {
 	struct cfq_queue *__cfqq, *next;
 
-	if (unlikely(cfqq == cfqd->active_queue)) {
-		__cfq_slice_expired(cfqd, cfqq, 0);
-		cfq_schedule_dispatch(cfqd);
-	}
-
 	/*
 	 * If this queue was scheduled to merge with another queue, be
 	 * sure to drop the reference taken on that queue (and others in
@@ -2561,6 +2579,16 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 		cfq_put_queue(__cfqq);
 		__cfqq = next;
 	}
+}
+
+static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	if (unlikely(cfqq == cfqd->active_queue)) {
+		__cfq_slice_expired(cfqd, cfqq, 0);
+		cfq_schedule_dispatch(cfqd);
+	}
+
+	cfq_put_cooperator(cfqq);
 
 	cfq_put_queue(cfqq);
 }
@@ -2573,11 +2601,10 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
 	list_del_init(&cic->queue_list);
 
 	/*
-	 * Make sure key == NULL is seen for dead queues
+	 * Make sure dead mark is seen for dead queues
 	 */
 	smp_wmb();
-	cic->dead_key = (unsigned long) cic->key;
-	cic->key = NULL;
+	cic->key = cfqd_dead_key(cfqd);
 
 	if (ioc->ioc_data == cic)
 		rcu_assign_pointer(ioc->ioc_data, NULL);
@@ -2596,7 +2623,7 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
 static void cfq_exit_single_io_context(struct io_context *ioc,
 				       struct cfq_io_context *cic)
 {
-	struct cfq_data *cfqd = cic->key;
+	struct cfq_data *cfqd = cic_to_cfqd(cic);
 
 	if (cfqd) {
 		struct request_queue *q = cfqd->queue;
@@ -2609,7 +2636,7 @@ static void cfq_exit_single_io_context(struct io_context *ioc,
 		 * race between exiting task and queue
 		 */
 		smp_read_barrier_depends();
-		if (cic->key)
+		if (cic->key == cfqd)
 			__cfq_exit_single_io_context(cfqd, cic);
 
 		spin_unlock_irqrestore(q->queue_lock, flags);
@@ -2689,7 +2716,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
 
 static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
 {
-	struct cfq_data *cfqd = cic->key;
+	struct cfq_data *cfqd = cic_to_cfqd(cic);
 	struct cfq_queue *cfqq;
 	unsigned long flags;
 
@@ -2746,7 +2773,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
 {
 	struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1);
-	struct cfq_data *cfqd = cic->key;
+	struct cfq_data *cfqd = cic_to_cfqd(cic);
 	unsigned long flags;
 	struct request_queue *q;
 
@@ -2883,12 +2910,13 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
 	unsigned long flags;
 
 	WARN_ON(!list_empty(&cic->queue_list));
+	BUG_ON(cic->key != cfqd_dead_key(cfqd));
 
 	spin_lock_irqsave(&ioc->lock, flags);
 
 	BUG_ON(ioc->ioc_data == cic);
 
-	radix_tree_delete(&ioc->radix_root, (unsigned long) cfqd);
+	radix_tree_delete(&ioc->radix_root, cfqd->cic_index);
 	hlist_del_rcu(&cic->cic_list);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 
@@ -2900,7 +2928,6 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
 {
 	struct cfq_io_context *cic;
 	unsigned long flags;
-	void *k;
 
 	if (unlikely(!ioc))
 		return NULL;
@@ -2917,13 +2944,11 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
 	}
 
 	do {
-		cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd);
+		cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index);
 		rcu_read_unlock();
 		if (!cic)
 			break;
-		/* ->key must be copied to avoid race with cfq_exit_queue() */
-		k = cic->key;
-		if (unlikely(!k)) {
+		if (unlikely(cic->key != cfqd)) {
 			cfq_drop_dead_cic(cfqd, ioc, cic);
 			rcu_read_lock();
 			continue;
@@ -2956,7 +2981,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
 
 		spin_lock_irqsave(&ioc->lock, flags);
 		ret = radix_tree_insert(&ioc->radix_root,
-						(unsigned long) cfqd, cic);
+						cfqd->cic_index, cic);
 		if (!ret)
 			hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list);
 		spin_unlock_irqrestore(&ioc->lock, flags);
@@ -3516,6 +3541,9 @@ split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq)
 	}
 
 	cic_set_cfqq(cic, NULL, 1);
+
+	cfq_put_cooperator(cfqq);
+
 	cfq_put_queue(cfqq);
 	return NULL;
 }
@@ -3708,10 +3736,32 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
 	cfq_shutdown_timer_wq(cfqd);
 
+	spin_lock(&cic_index_lock);
+	ida_remove(&cic_index_ida, cfqd->cic_index);
+	spin_unlock(&cic_index_lock);
+
 	/* Wait for cfqg->blkg->key accessors to exit their grace periods. */
 	call_rcu(&cfqd->rcu, cfq_cfqd_free);
 }
 
+static int cfq_alloc_cic_index(void)
+{
+	int index, error;
+
+	do {
+		if (!ida_pre_get(&cic_index_ida, GFP_KERNEL))
+			return -ENOMEM;
+
+		spin_lock(&cic_index_lock);
+		error = ida_get_new(&cic_index_ida, &index);
+		spin_unlock(&cic_index_lock);
+		if (error && error != -EAGAIN)
+			return error;
+	} while (error);
+
+	return index;
+}
+
 static void *cfq_init_queue(struct request_queue *q)
 {
 	struct cfq_data *cfqd;
@@ -3719,10 +3769,16 @@ static void *cfq_init_queue(struct request_queue *q)
 	struct cfq_group *cfqg;
 	struct cfq_rb_root *st;
 
+	i = cfq_alloc_cic_index();
+	if (i < 0)
+		return NULL;
+
 	cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
 	if (!cfqd)
 		return NULL;
 
+	cfqd->cic_index = i;
+
 	/* Init root service tree */
 	cfqd->grp_service_tree = CFQ_RB_ROOT;
 
@@ -3984,6 +4040,7 @@ static void __exit cfq_exit(void)
 	 */
 	if (elv_ioc_count_read(cfq_ioc_count))
 		wait_for_completion(&all_gone);
+	ida_destroy(&cic_index_ida);
 	cfq_slab_kill();
 }
 

+ 5 - 3
block/elevator.c

@@ -242,9 +242,11 @@ int elevator_init(struct request_queue *q, char *name)
 {
 	struct elevator_type *e = NULL;
 	struct elevator_queue *eq;
-	int ret = 0;
 	void *data;
 
+	if (unlikely(q->elevator))
+		return 0;
+
 	INIT_LIST_HEAD(&q->queue_head);
 	q->last_merge = NULL;
 	q->end_sector = 0;
@@ -284,7 +286,7 @@ int elevator_init(struct request_queue *q, char *name)
 	}
 
 	elevator_attach(q, eq, data);
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(elevator_init);
 
@@ -1097,7 +1099,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
 	struct elevator_type *__e;
 	int len = 0;
 
-	if (!q->elevator)
+	if (!q->elevator || !blk_queue_stackable(q))
 		return sprintf(name, "none\n");
 
 	elv = e->elevator_type;

+ 52 - 1
drivers/block/brd.c

@@ -133,6 +133,28 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
 	return page;
 }
 
+static void brd_free_page(struct brd_device *brd, sector_t sector)
+{
+	struct page *page;
+	pgoff_t idx;
+
+	spin_lock(&brd->brd_lock);
+	idx = sector >> PAGE_SECTORS_SHIFT;
+	page = radix_tree_delete(&brd->brd_pages, idx);
+	spin_unlock(&brd->brd_lock);
+	if (page)
+		__free_page(page);
+}
+
+static void brd_zero_page(struct brd_device *brd, sector_t sector)
+{
+	struct page *page;
+
+	page = brd_lookup_page(brd, sector);
+	if (page)
+		clear_highpage(page);
+}
+
 /*
  * Free all backing store pages and radix tree. This must only be called when
  * there are no other users of the device.
@@ -189,6 +211,24 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n)
 	return 0;
 }
 
+static void discard_from_brd(struct brd_device *brd,
+			sector_t sector, size_t n)
+{
+	while (n >= PAGE_SIZE) {
+		/*
+		 * Don't want to actually discard pages here because
+		 * re-allocating the pages can result in writeback
+		 * deadlocks under heavy load.
+		 */
+		if (0)
+			brd_free_page(brd, sector);
+		else
+			brd_zero_page(brd, sector);
+		sector += PAGE_SIZE >> SECTOR_SHIFT;
+		n -= PAGE_SIZE;
+	}
+}
+
 /*
  * Copy n bytes from src to the brd starting at sector. Does not sleep.
  */
@@ -300,6 +340,12 @@ static int brd_make_request(struct request_queue *q, struct bio *bio)
 						get_capacity(bdev->bd_disk))
 		goto out;
 
+	if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) {
+		err = 0;
+		discard_from_brd(brd, sector, bio->bi_size);
+		goto out;
+	}
+
 	rw = bio_rw(bio);
 	if (rw == READA)
 		rw = READ;
@@ -320,7 +366,7 @@ out:
 }
 
 #ifdef CONFIG_BLK_DEV_XIP
-static int brd_direct_access (struct block_device *bdev, sector_t sector,
+static int brd_direct_access(struct block_device *bdev, sector_t sector,
 			void **kaddr, unsigned long *pfn)
 {
 	struct brd_device *brd = bdev->bd_disk->private_data;
@@ -437,6 +483,11 @@ static struct brd_device *brd_alloc(int i)
 	blk_queue_max_hw_sectors(brd->brd_queue, 1024);
 	blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
 
+	brd->brd_queue->limits.discard_granularity = PAGE_SIZE;
+	brd->brd_queue->limits.max_discard_sectors = UINT_MAX;
+	brd->brd_queue->limits.discard_zeroes_data = 1;
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);
+
 	disk = brd->brd_disk = alloc_disk(1 << part_shift);
 	if (!disk)
 		goto out_free_queue;

+ 1 - 1
drivers/block/cciss_scsi.c

@@ -188,11 +188,11 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
 
 	sa = h->scsi_ctlr;
 	stk = &sa->cmd_stack; 
+	stk->top++;
 	if (stk->top >= CMD_STACK_SIZE) {
 		printk("cciss: scsi_cmd_free called too many times.\n");
 		BUG();
 	}
-	stk->top++;
 	stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
 }
 

+ 3 - 11
drivers/block/drbd/drbd_int.h

@@ -943,8 +943,7 @@ struct drbd_conf {
 	struct drbd_work  resync_work,
 			  unplug_work,
 			  md_sync_work,
-			  delay_probe_work,
-			  uuid_work;
+			  delay_probe_work;
 	struct timer_list resync_timer;
 	struct timer_list md_sync_timer;
 	struct timer_list delay_probe_timer;
@@ -1069,7 +1068,6 @@ struct drbd_conf {
 	struct timeval dps_time; /* delay-probes-start-time */
 	unsigned int dp_volume_last;  /* send_cnt of last delay probe */
 	int c_sync_rate; /* current resync rate after delay_probe magic */
-	atomic_t new_c_uuid;
 };
 
 static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1476,7 +1474,6 @@ extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int);
 extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int);
 extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int);
 extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int);
-extern int w_io_error(struct drbd_conf *, struct drbd_work *, int);
 extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int);
 extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int);
 extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int);
@@ -1542,7 +1539,7 @@ static inline void drbd_tcp_nodelay(struct socket *sock)
 
 static inline void drbd_tcp_quickack(struct socket *sock)
 {
-	int __user val = 1;
+	int __user val = 2;
 	(void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK,
 			(char __user *)&val, sizeof(val));
 }
@@ -1728,7 +1725,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
 	switch (mdev->ldev->dc.on_io_error) {
 	case EP_PASS_ON:
 		if (!forcedetach) {
-			if (printk_ratelimit())
+			if (__ratelimit(&drbd_ratelimit_state))
 				dev_err(DEV, "Local IO failed in %s."
 					     "Passing error on...\n", where);
 			break;
@@ -2219,8 +2216,6 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
 		return 0;
 	if (test_bit(BITMAP_IO, &mdev->flags))
 		return 0;
-	if (atomic_read(&mdev->new_c_uuid))
-		return 0;
 	return 1;
 }
 
@@ -2241,9 +2236,6 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count)
 	 * to avoid races with the reconnect code,
 	 * we need to atomic_inc within the spinlock. */
 
-	if (atomic_read(&mdev->new_c_uuid) && atomic_add_unless(&mdev->new_c_uuid, -1, 1))
-		drbd_queue_work_front(&mdev->data.work, &mdev->uuid_work);
-
 	spin_lock_irq(&mdev->req_lock);
 	while (!__inc_ap_bio_cond(mdev)) {
 		prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);

+ 26 - 42
drivers/block/drbd/drbd_main.c

@@ -1215,18 +1215,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
 	     ns.pdsk == D_OUTDATED)) {
 		if (get_ldev(mdev)) {
 			if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
-			    mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE &&
-			    !atomic_read(&mdev->new_c_uuid))
-				atomic_set(&mdev->new_c_uuid, 2);
+			    mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+				drbd_uuid_new_current(mdev);
+				drbd_send_uuids(mdev);
+			}
 			put_ldev(mdev);
 		}
 	}
 
 	if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
-		/* Diskless peer becomes primary or got connected do diskless, primary peer. */
-		if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0 &&
-		    !atomic_read(&mdev->new_c_uuid))
-			atomic_set(&mdev->new_c_uuid, 2);
+		if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0)
+			drbd_uuid_new_current(mdev);
 
 		/* D_DISKLESS Peer becomes secondary */
 		if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
@@ -1350,24 +1349,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
 	drbd_md_sync(mdev);
 }
 
-static int w_new_current_uuid(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
-	if (get_ldev(mdev)) {
-		if (mdev->ldev->md.uuid[UI_BITMAP] == 0) {
-			drbd_uuid_new_current(mdev);
-			if (get_net_conf(mdev)) {
-				drbd_send_uuids(mdev);
-				put_net_conf(mdev);
-			}
-			drbd_md_sync(mdev);
-		}
-		put_ldev(mdev);
-	}
-	atomic_dec(&mdev->new_c_uuid);
-	wake_up(&mdev->misc_wait);
-
-	return 1;
-}
 
 static int drbd_thread_setup(void *arg)
 {
@@ -2291,9 +2272,9 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *
  * with page_count == 0 or PageSlab.
  */
 static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
-		   int offset, size_t size)
+		   int offset, size_t size, unsigned msg_flags)
 {
-	int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0);
+	int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, msg_flags);
 	kunmap(page);
 	if (sent == size)
 		mdev->send_cnt += size>>9;
@@ -2301,7 +2282,7 @@ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
 }
 
 static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
-		    int offset, size_t size)
+		    int offset, size_t size, unsigned msg_flags)
 {
 	mm_segment_t oldfs = get_fs();
 	int sent, ok;
@@ -2314,14 +2295,15 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
 	 * __page_cache_release a page that would actually still be referenced
 	 * by someone, leading to some obscure delayed Oops somewhere else. */
 	if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
-		return _drbd_no_send_page(mdev, page, offset, size);
+		return _drbd_no_send_page(mdev, page, offset, size, msg_flags);
 
+	msg_flags |= MSG_NOSIGNAL;
 	drbd_update_congested(mdev);
 	set_fs(KERNEL_DS);
 	do {
 		sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
 							offset, len,
-							MSG_NOSIGNAL);
+							msg_flags);
 		if (sent == -EAGAIN) {
 			if (we_should_drop_the_connection(mdev,
 							  mdev->data.socket))
@@ -2350,9 +2332,11 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
 {
 	struct bio_vec *bvec;
 	int i;
+	/* hint all but last page with MSG_MORE */
 	__bio_for_each_segment(bvec, bio, i, 0) {
 		if (!_drbd_no_send_page(mdev, bvec->bv_page,
-				     bvec->bv_offset, bvec->bv_len))
+				     bvec->bv_offset, bvec->bv_len,
+				     i == bio->bi_vcnt -1 ? 0 : MSG_MORE))
 			return 0;
 	}
 	return 1;
@@ -2362,12 +2346,13 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
 {
 	struct bio_vec *bvec;
 	int i;
+	/* hint all but last page with MSG_MORE */
 	__bio_for_each_segment(bvec, bio, i, 0) {
 		if (!_drbd_send_page(mdev, bvec->bv_page,
-				     bvec->bv_offset, bvec->bv_len))
+				     bvec->bv_offset, bvec->bv_len,
+				     i == bio->bi_vcnt -1 ? 0 : MSG_MORE))
 			return 0;
 	}
-
 	return 1;
 }
 
@@ -2375,9 +2360,11 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
 {
 	struct page *page = e->pages;
 	unsigned len = e->size;
+	/* hint all but last page with MSG_MORE */
 	page_chain_for_each(page) {
 		unsigned l = min_t(unsigned, len, PAGE_SIZE);
-		if (!_drbd_send_page(mdev, page, 0, l))
+		if (!_drbd_send_page(mdev, page, 0, l,
+				page_chain_next(page) ? MSG_MORE : 0))
 			return 0;
 		len -= l;
 	}
@@ -2457,11 +2444,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
 	p.dp_flags = cpu_to_be32(dp_flags);
 	set_bit(UNPLUG_REMOTE, &mdev->flags);
 	ok = (sizeof(p) ==
-		drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE));
+		drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0));
 	if (ok && dgs) {
 		dgb = mdev->int_dig_out;
 		drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb);
-		ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+		ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0);
 	}
 	if (ok) {
 		if (mdev->net_conf->wire_protocol == DRBD_PROT_A)
@@ -2510,11 +2497,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
 		return 0;
 
 	ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
-					sizeof(p), MSG_MORE);
+					sizeof(p), dgs ? MSG_MORE : 0);
 	if (ok && dgs) {
 		dgb = mdev->int_dig_out;
 		drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb);
-		ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+		ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0);
 	}
 	if (ok)
 		ok = _drbd_send_zc_ee(mdev, e);
@@ -2708,7 +2695,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
 	atomic_set(&mdev->net_cnt, 0);
 	atomic_set(&mdev->packet_seq, 0);
 	atomic_set(&mdev->pp_in_use, 0);
-	atomic_set(&mdev->new_c_uuid, 0);
 
 	mutex_init(&mdev->md_io_mutex);
 	mutex_init(&mdev->data.mutex);
@@ -2739,14 +2725,12 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
 	INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
 	INIT_LIST_HEAD(&mdev->delay_probes);
 	INIT_LIST_HEAD(&mdev->delay_probe_work.list);
-	INIT_LIST_HEAD(&mdev->uuid_work.list);
 
 	mdev->resync_work.cb  = w_resync_inactive;
 	mdev->unplug_work.cb  = w_send_write_hint;
 	mdev->md_sync_work.cb = w_md_sync;
 	mdev->bm_io_work.w.cb = w_bitmap_io;
 	mdev->delay_probe_work.cb = w_delay_probes;
-	mdev->uuid_work.cb = w_new_current_uuid;
 	init_timer(&mdev->resync_timer);
 	init_timer(&mdev->md_sync_timer);
 	init_timer(&mdev->delay_probe_timer);
@@ -3799,7 +3783,7 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
 	if (ret) {
 		fault_count++;
 
-		if (printk_ratelimit())
+		if (__ratelimit(&drbd_ratelimit_state))
 			dev_warn(DEV, "***Simulating %s failure\n",
 				_drbd_fault_str(type));
 	}

+ 23 - 22
drivers/block/drbd/drbd_receiver.c

@@ -42,7 +42,6 @@
 #include <linux/unistd.h>
 #include <linux/vmalloc.h>
 #include <linux/random.h>
-#include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
 #include "drbd_int.h"
@@ -571,6 +570,25 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size)
 	return rv;
 }
 
+/* quoting tcp(7):
+ *   On individual connections, the socket buffer size must be set prior to the
+ *   listen(2) or connect(2) calls in order to have it take effect.
+ * This is our wrapper to do so.
+ */
+static void drbd_setbufsize(struct socket *sock, unsigned int snd,
+		unsigned int rcv)
+{
+	/* open coded SO_SNDBUF, SO_RCVBUF */
+	if (snd) {
+		sock->sk->sk_sndbuf = snd;
+		sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+	}
+	if (rcv) {
+		sock->sk->sk_rcvbuf = rcv;
+		sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+	}
+}
+
 static struct socket *drbd_try_connect(struct drbd_conf *mdev)
 {
 	const char *what;
@@ -592,6 +610,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev)
 
 	sock->sk->sk_rcvtimeo =
 	sock->sk->sk_sndtimeo =  mdev->net_conf->try_connect_int*HZ;
+	drbd_setbufsize(sock, mdev->net_conf->sndbuf_size,
+			mdev->net_conf->rcvbuf_size);
 
        /* explicitly bind to the configured IP as source IP
 	*  for the outgoing connections.
@@ -670,6 +690,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev)
 	s_listen->sk->sk_reuse    = 1; /* SO_REUSEADDR */
 	s_listen->sk->sk_rcvtimeo = timeo;
 	s_listen->sk->sk_sndtimeo = timeo;
+	drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size,
+			mdev->net_conf->rcvbuf_size);
 
 	what = "bind before listen";
 	err = s_listen->ops->bind(s_listen,
@@ -856,16 +878,6 @@ retry:
 	sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
 	msock->sk->sk_priority = TC_PRIO_INTERACTIVE;
 
-	if (mdev->net_conf->sndbuf_size) {
-		sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size;
-		sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-	}
-
-	if (mdev->net_conf->rcvbuf_size) {
-		sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size;
-		sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-	}
-
 	/* NOT YET ...
 	 * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
 	 * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
@@ -1154,17 +1166,6 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e,
 	unsigned n_bios = 0;
 	unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT;
 
-	if (atomic_read(&mdev->new_c_uuid)) {
-		if (atomic_add_unless(&mdev->new_c_uuid, -1, 1)) {
-			drbd_uuid_new_current(mdev);
-			drbd_md_sync(mdev);
-
-			atomic_dec(&mdev->new_c_uuid);
-			wake_up(&mdev->misc_wait);
-		}
-		wait_event(mdev->misc_wait, !atomic_read(&mdev->new_c_uuid));
-	}
-
 	/* In most cases, we will only need one bio.  But in case the lower
 	 * level restrictions happen to be different at this offset on this
 	 * side than those of the sending peer, we may need to submit the

+ 14 - 40
drivers/block/drbd/drbd_req.c

@@ -102,32 +102,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const
 		}
 	}
 
-	/* if it was a local io error, we want to notify our
-	 * peer about that, and see if we need to
-	 * detach the disk and stuff.
-	 * to avoid allocating some special work
-	 * struct, reuse the request. */
-
-	/* THINK
-	 * why do we do this not when we detect the error,
-	 * but delay it until it is "done", i.e. possibly
-	 * until the next barrier ack? */
-
-	if (rw == WRITE &&
-	    ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
-		if (!(req->w.list.next == LIST_POISON1 ||
-		      list_empty(&req->w.list))) {
-			/* DEBUG ASSERT only; if this triggers, we
-			 * probably corrupt the worker list here */
-			dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next);
-			dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev);
-		}
-		req->w.cb = w_io_error;
-		drbd_queue_work(&mdev->data.work, &req->w);
-		/* drbd_req_free() is done in w_io_error */
-	} else {
-		drbd_req_free(req);
-	}
+	drbd_req_free(req);
 }
 
 static void queue_barrier(struct drbd_conf *mdev)
@@ -453,9 +428,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		req->rq_state |= RQ_LOCAL_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 
-		dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n",
-		      (unsigned long long)req->sector, req->size);
-		/* and now: check how to handle local io error. */
 		__drbd_chk_io_error(mdev, FALSE);
 		_req_may_be_done(req, m);
 		put_ldev(mdev);
@@ -475,22 +447,21 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		req->rq_state |= RQ_LOCAL_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 
-		dev_alert(DEV, "Local READ failed sec=%llus size=%u\n",
-		      (unsigned long long)req->sector, req->size);
-		/* _req_mod(req,to_be_send); oops, recursion... */
 		D_ASSERT(!(req->rq_state & RQ_NET_MASK));
-		req->rq_state |= RQ_NET_PENDING;
-		inc_ap_pending(mdev);
 
 		__drbd_chk_io_error(mdev, FALSE);
 		put_ldev(mdev);
-		/* NOTE: if we have no connection,
-		 * or know the peer has no good data either,
-		 * then we don't actually need to "queue_for_net_read",
-		 * but we do so anyways, since the drbd_io_error()
-		 * and the potential state change to "Diskless"
-		 * needs to be done from process context */
 
+		/* no point in retrying if there is no good remote data,
+		 * or we have no connection. */
+		if (mdev->state.pdsk != D_UP_TO_DATE) {
+			_req_may_be_done(req, m);
+			break;
+		}
+
+		/* _req_mod(req,to_be_send); oops, recursion... */
+		req->rq_state |= RQ_NET_PENDING;
+		inc_ap_pending(mdev);
 		/* fall through: _req_mod(req,queue_for_net_read); */
 
 	case queue_for_net_read:
@@ -600,6 +571,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		_req_may_be_done(req, m);
 		break;
 
+	case read_retry_remote_canceled:
+		req->rq_state &= ~RQ_NET_QUEUED;
+		/* fall through, in case we raced with drbd_disconnect */
 	case connection_lost_while_pending:
 		/* transfer log cleanup after connection loss */
 		/* assert something? */

+ 1 - 0
drivers/block/drbd/drbd_req.h

@@ -91,6 +91,7 @@ enum drbd_req_event {
 	send_failed,
 	handed_over_to_network,
 	connection_lost_while_pending,
+	read_retry_remote_canceled,
 	recv_acked_by_peer,
 	write_acked_by_peer,
 	write_acked_by_peer_and_sis, /* and set_in_sync */

+ 2 - 22
drivers/block/drbd/drbd_worker.c

@@ -224,9 +224,6 @@ void drbd_endio_pri(struct bio *bio, int error)
 	enum drbd_req_event what;
 	int uptodate = bio_flagged(bio, BIO_UPTODATE);
 
-	if (error)
-		dev_warn(DEV, "p %s: error=%d\n",
-			 bio_data_dir(bio) == WRITE ? "write" : "read", error);
 	if (!error && !uptodate) {
 		dev_warn(DEV, "p %s: setting error to -EIO\n",
 			 bio_data_dir(bio) == WRITE ? "write" : "read");
@@ -257,20 +254,6 @@ void drbd_endio_pri(struct bio *bio, int error)
 		complete_master_bio(mdev, &m);
 }
 
-int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
-	struct drbd_request *req = container_of(w, struct drbd_request, w);
-
-	/* NOTE: mdev->ldev can be NULL by the time we get here! */
-	/* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */
-
-	/* the only way this callback is scheduled is from _req_may_be_done,
-	 * when it is done and had a local write error, see comments there */
-	drbd_req_free(req);
-
-	return TRUE;
-}
-
 int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
 	struct drbd_request *req = container_of(w, struct drbd_request, w);
@@ -280,12 +263,9 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 	 * to give the disk the chance to relocate that block */
 
 	spin_lock_irq(&mdev->req_lock);
-	if (cancel ||
-	    mdev->state.conn < C_CONNECTED ||
-	    mdev->state.pdsk <= D_INCONSISTENT) {
-		_req_mod(req, send_canceled);
+	if (cancel || mdev->state.pdsk != D_UP_TO_DATE) {
+		_req_mod(req, read_retry_remote_canceled);
 		spin_unlock_irq(&mdev->req_lock);
-		dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n");
 		return 1;
 	}
 	spin_unlock_irq(&mdev->req_lock);

+ 1 - 0
drivers/char/Kconfig

@@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig"
 
 config RAMOOPS
 	tristate "Log panic/oops to a RAM buffer"
+	depends on HAS_IOMEM
 	default n
 	help
 	  This enables panic and oops messages to be logged to a circular

+ 5 - 4
drivers/char/n_gsm.c

@@ -904,9 +904,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
 	int len;
 	/* Priority ordering: We should do priority with RR of the groups */
 	int i = 1;
-	unsigned long flags;
 
-	spin_lock_irqsave(&gsm->tx_lock, flags);
 	while (i < NUM_DLCI) {
 		struct gsm_dlci *dlci;
 
@@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
 		if (len == 0)
 			i++;
 	}
-	spin_unlock_irqrestore(&gsm->tx_lock, flags);
 }
 
 /**
@@ -2230,12 +2227,16 @@ static int gsmld_open(struct tty_struct *tty)
 static void gsmld_write_wakeup(struct tty_struct *tty)
 {
 	struct gsm_mux *gsm = tty->disc_data;
+	unsigned long flags;
 
 	/* Queue poll */
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	gsm_data_kick(gsm);
-	if (gsm->tx_bytes < TX_THRESH_LO)
+	if (gsm->tx_bytes < TX_THRESH_LO) {
+		spin_lock_irqsave(&gsm->tx_lock, flags);
 		gsm_dlci_data_sweep(gsm);
+		spin_unlock_irqrestore(&gsm->tx_lock, flags);
+	}
 }
 
 /**

+ 1 - 1
drivers/char/vt.c

@@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 	scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-	scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+	scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char,
 		    vc->vc_size_row * nr);
 }
 

+ 3 - 1
drivers/char/vt_ioctl.c

@@ -1303,7 +1303,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 		if (!perm)
 			goto eperm;
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-		if (!ret)
+		if (ret)
+			ret = -EFAULT;
+		else
 			con_clear_unimap(vc, &ui);
 		break;
 	      }

+ 13 - 9
drivers/clocksource/sh_cmt.c

@@ -412,18 +412,10 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
 static int sh_cmt_clocksource_enable(struct clocksource *cs)
 {
 	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
-	int ret;
 
 	p->total_cycles = 0;
 
-	ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
-	if (ret)
-		return ret;
-
-	/* TODO: calculate good shift from rate and counter bit width */
-	cs->shift = 0;
-	cs->mult = clocksource_hz2mult(p->rate, cs->shift);
-	return 0;
+	return sh_cmt_start(p, FLAG_CLOCKSOURCE);
 }
 
 static void sh_cmt_clocksource_disable(struct clocksource *cs)
@@ -450,8 +442,20 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
 	cs->resume = sh_cmt_clocksource_resume;
 	cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+	/* clk_get_rate() needs an enabled clock */
+	clk_enable(p->clk);
+	p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+	clk_disable(p->clk);
+
+	/* TODO: calculate good shift from rate and counter bit width */
+	cs->shift = 10;
+	cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+
 	dev_info(&p->pdev->dev, "used as clock source\n");
+
 	clocksource_register(cs);
+
 	return 0;
 }
 

+ 11 - 9
drivers/clocksource/sh_tmu.c

@@ -199,16 +199,8 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
 static int sh_tmu_clocksource_enable(struct clocksource *cs)
 {
 	struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
-	int ret;
-
-	ret = sh_tmu_enable(p);
-	if (ret)
-		return ret;
 
-	/* TODO: calculate good shift from rate and counter bit width */
-	cs->shift = 10;
-	cs->mult = clocksource_hz2mult(p->rate, cs->shift);
-	return 0;
+	return sh_tmu_enable(p);
 }
 
 static void sh_tmu_clocksource_disable(struct clocksource *cs)
@@ -228,6 +220,16 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
 	cs->disable = sh_tmu_clocksource_disable;
 	cs->mask = CLOCKSOURCE_MASK(32);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+	/* clk_get_rate() needs an enabled clock */
+	clk_enable(p->clk);
+	/* channel will be configured at parent clock / 4 */
+	p->rate = clk_get_rate(p->clk) / 4;
+	clk_disable(p->clk);
+	/* TODO: calculate good shift from rate and counter bit width */
+	cs->shift = 10;
+	cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+
 	dev_info(&p->pdev->dev, "used as clock source\n");
 	clocksource_register(cs);
 	return 0;

+ 13 - 0
drivers/edac/Kconfig

@@ -69,6 +69,9 @@ config EDAC_MM_EDAC
 	  occurred so that a particular failing memory module can be
 	  replaced.  If unsure, select 'Y'.
 
+config EDAC_MCE
+	bool
+
 config EDAC_AMD64
 	tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
 	depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
@@ -166,6 +169,16 @@ config EDAC_I5400
 	  Support for error detection and correction the Intel
 	  i5400 MCH chipset (Seaburg).
 
+config EDAC_I7CORE
+	tristate "Intel i7 Core (Nehalem) processors"
+	depends on EDAC_MM_EDAC && PCI && X86
+	select EDAC_MCE
+	help
+	  Support for error detection and correction the Intel
+	  i7 Core (Nehalem) Integrated Memory Controller that exists on
+	  newer processors like i7 Core, i7 Core Extreme, Xeon 35xx
+	  and Xeon 55xx processors.
+
 config EDAC_I82860
 	tristate "Intel 82860"
 	depends on EDAC_MM_EDAC && PCI && X86_32

+ 2 - 0
drivers/edac/Makefile

@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_EDAC)			:= edac_stub.o
 obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.o
+obj-$(CONFIG_EDAC_MCE)			+= edac_mce.o
 
 edac_core-objs	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
 edac_core-objs	+= edac_module.o edac_device_sysfs.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_EDAC_CPC925)		+= cpc925_edac.o
 obj-$(CONFIG_EDAC_I5000)		+= i5000_edac.o
 obj-$(CONFIG_EDAC_I5100)		+= i5100_edac.o
 obj-$(CONFIG_EDAC_I5400)		+= i5400_edac.o
+obj-$(CONFIG_EDAC_I7CORE)		+= i7core_edac.o
 obj-$(CONFIG_EDAC_E7XXX)		+= e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
 obj-$(CONFIG_EDAC_I82443BXGX)		+= i82443bxgx_edac.o

+ 22 - 1
drivers/edac/edac_core.h

@@ -341,12 +341,30 @@ struct csrow_info {
 	struct channel_info *channels;
 };
 
+struct mcidev_sysfs_group {
+	const char *name;				/* group name */
+	struct mcidev_sysfs_attribute *mcidev_attr;	/* group attributes */
+};
+
+struct mcidev_sysfs_group_kobj {
+	struct list_head list;		/* list for all instances within a mc */
+
+	struct kobject kobj;		/* kobj for the group */
+
+	struct mcidev_sysfs_group *grp;	/* group description table */
+	struct mem_ctl_info *mci;	/* the parent */
+};
+
 /* mcidev_sysfs_attribute structure
  *	used for driver sysfs attributes and in mem_ctl_info
  * 	sysfs top level entries
  */
 struct mcidev_sysfs_attribute {
-        struct attribute attr;
+	/* It should use either attr or grp */
+	struct attribute attr;
+	struct mcidev_sysfs_group *grp;	/* Points to a group of attributes */
+
+	/* Ops for show/store values at the attribute - not used on group */
         ssize_t (*show)(struct mem_ctl_info *,char *);
         ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
 };
@@ -424,6 +442,9 @@ struct mem_ctl_info {
 	/* edac sysfs device control */
 	struct kobject edac_mci_kobj;
 
+	/* list for all grp instances within a mc */
+	struct list_head grp_kobj_list;
+
 	/* Additional top controller level attributes, but specified
 	 * by the low level driver.
 	 *

+ 149 - 26
drivers/edac/edac_mc_sysfs.c

@@ -557,6 +557,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
 	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
 
+	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
 	if (mcidev_attr->show)
 		return mcidev_attr->show(mem_ctl_info, buffer);
 
@@ -569,6 +571,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
 	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
 
+	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
 	if (mcidev_attr->store)
 		return mcidev_attr->store(mem_ctl_info, buffer, count);
 
@@ -726,28 +730,118 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 
 #define EDAC_DEVICE_SYMLINK	"device"
 
+#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
+
+/* MCI show/store functions for top most object */
+static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
+			char *buffer)
+{
+	struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+	if (mcidev_attr->show)
+		return mcidev_attr->show(mem_ctl_info, buffer);
+
+	return -EIO;
+}
+
+static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
+			const char *buffer, size_t count)
+{
+	struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+	debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+	if (mcidev_attr->store)
+		return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+	return -EIO;
+}
+
+/* No memory to release for this kobj */
+static void edac_inst_grp_release(struct kobject *kobj)
+{
+	struct mcidev_sysfs_group_kobj *grp;
+	struct mem_ctl_info *mci;
+
+	debugf1("%s()\n", __func__);
+
+	grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
+	mci = grp->mci;
+
+	kobject_put(&mci->edac_mci_kobj);
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops inst_grp_ops = {
+	.show = inst_grp_show,
+	.store = inst_grp_store
+};
+
+/* the kobj_type instance for a instance group */
+static struct kobj_type ktype_inst_grp = {
+	.release = edac_inst_grp_release,
+	.sysfs_ops = &inst_grp_ops,
+};
+
+
 /*
  * edac_create_mci_instance_attributes
- *	create MC driver specific attributes at the topmost level
- *	directory of this mci instance.
+ *	create MC driver specific attributes bellow an specified kobj
+ * This routine calls itself recursively, in order to create an entire
+ * object tree.
  */
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
+				struct mcidev_sysfs_attribute *sysfs_attrib,
+				struct kobject *kobj)
 {
 	int err;
-	struct mcidev_sysfs_attribute *sysfs_attrib;
 
-	/* point to the start of the array and iterate over it
-	 * adding each attribute listed to this mci instance's kobject
-	 */
-	sysfs_attrib = mci->mc_driver_sysfs_attributes;
+	debugf1("%s()\n", __func__);
+
+	while (sysfs_attrib) {
+		if (sysfs_attrib->grp) {
+			struct mcidev_sysfs_group_kobj *grp_kobj;
+
+			grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
+			if (!grp_kobj)
+				return -ENOMEM;
+
+			list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
+
+			grp_kobj->grp = sysfs_attrib->grp;
+			grp_kobj->mci = mci;
+
+			debugf0("%s() grp %s, mci %p\n", __func__,
+				sysfs_attrib->grp->name, mci);
+
+			err = kobject_init_and_add(&grp_kobj->kobj,
+						&ktype_inst_grp,
+						&mci->edac_mci_kobj,
+						sysfs_attrib->grp->name);
+			if (err)
+				return err;
+
+			err = edac_create_mci_instance_attributes(mci,
+					grp_kobj->grp->mcidev_attr,
+					&grp_kobj->kobj);
+
+			if (err)
+				return err;
+		} else if (sysfs_attrib->attr.name) {
+			debugf0("%s() file %s\n", __func__,
+				sysfs_attrib->attr.name);
+
+			err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+		} else
+			break;
 
-	while (sysfs_attrib && sysfs_attrib->attr.name) {
-		err = sysfs_create_file(&mci->edac_mci_kobj,
-					(struct attribute*) sysfs_attrib);
 		if (err) {
 			return err;
 		}
-
 		sysfs_attrib++;
 	}
 
@@ -759,21 +853,44 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
  *	remove MC driver specific attributes at the topmost level
  *	directory of this mci instance.
  */
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
+				struct mcidev_sysfs_attribute *sysfs_attrib,
+				struct kobject *kobj, int count)
 {
-	struct mcidev_sysfs_attribute *sysfs_attrib;
+	struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
 
-	/* point to the start of the array and iterate over it
-	 * adding each attribute listed to this mci instance's kobject
-	 */
-	sysfs_attrib = mci->mc_driver_sysfs_attributes;
+	debugf1("%s()\n", __func__);
 
-	/* loop if there are attributes and until we hit a NULL entry */
-	while (sysfs_attrib && sysfs_attrib->attr.name) {
-		sysfs_remove_file(&mci->edac_mci_kobj,
-					(struct attribute *) sysfs_attrib);
+	/*
+	 * loop if there are attributes and until we hit a NULL entry
+	 * Remove first all the atributes
+	 */
+	while (sysfs_attrib) {
+		if (sysfs_attrib->grp) {
+			list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
+					    list)
+				if (grp_kobj->grp == sysfs_attrib->grp)
+					edac_remove_mci_instance_attributes(mci,
+						    grp_kobj->grp->mcidev_attr,
+						    &grp_kobj->kobj, count + 1);
+		} else if (sysfs_attrib->attr.name) {
+			debugf0("%s() file %s\n", __func__,
+				sysfs_attrib->attr.name);
+			sysfs_remove_file(kobj, &sysfs_attrib->attr);
+		} else
+			break;
 		sysfs_attrib++;
 	}
+
+	/*
+	 * Now that all attributes got removed, it is save to remove all groups
+	 */
+	if (!count)
+		list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
+					 list) {
+			debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
+			kobject_put(&grp_kobj->kobj);
+		}
 }
 
 
@@ -794,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 
 	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
 
+	INIT_LIST_HEAD(&mci->grp_kobj_list);
+
 	/* create a symlink for the device */
 	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
 				EDAC_DEVICE_SYMLINK);
@@ -806,7 +925,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 	 * then create them now for the driver.
 	 */
 	if (mci->mc_driver_sysfs_attributes) {
-		err = edac_create_mci_instance_attributes(mci);
+		err = edac_create_mci_instance_attributes(mci,
+					mci->mc_driver_sysfs_attributes,
+					&mci->edac_mci_kobj);
 		if (err) {
 			debugf1("%s() failure to create mci attributes\n",
 				__func__);
@@ -841,7 +962,8 @@ fail1:
 	}
 
 	/* remove the mci instance's attributes, if any */
-	edac_remove_mci_instance_attributes(mci);
+	edac_remove_mci_instance_attributes(mci,
+		mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
 
 	/* remove the symlink */
 	sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
@@ -875,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 	debugf0("%s()  remove_mci_instance\n", __func__);
 
 	/* remove this mci instance's attribtes */
-	edac_remove_mci_instance_attributes(mci);
-
+	edac_remove_mci_instance_attributes(mci,
+					    mci->mc_driver_sysfs_attributes,
+					    &mci->edac_mci_kobj, 0);
 	debugf0("%s()  unregister this mci kobj\n", __func__);
 
 	/* unregister this instance's kobject */

+ 61 - 0
drivers/edac/edac_mce.c

@@ -0,0 +1,61 @@
+/* Provides edac interface to mcelog events
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2.
+ *
+ * Copyright (c) 2009 by:
+ *	 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ */
+
+#include <linux/module.h>
+#include <linux/edac_mce.h>
+#include <asm/mce.h>
+
+int edac_mce_enabled;
+EXPORT_SYMBOL_GPL(edac_mce_enabled);
+
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(edac_mce_list);
+static DEFINE_MUTEX(edac_mce_lock);
+
+int edac_mce_register(struct edac_mce *edac_mce)
+{
+	mutex_lock(&edac_mce_lock);
+	list_add_tail(&edac_mce->list, &edac_mce_list);
+	mutex_unlock(&edac_mce_lock);
+	return 0;
+}
+EXPORT_SYMBOL(edac_mce_register);
+
+void edac_mce_unregister(struct edac_mce *edac_mce)
+{
+	mutex_lock(&edac_mce_lock);
+	list_del(&edac_mce->list);
+	mutex_unlock(&edac_mce_lock);
+}
+EXPORT_SYMBOL(edac_mce_unregister);
+
+int edac_mce_parse(struct mce *mce)
+{
+	struct edac_mce *edac_mce;
+
+	list_for_each_entry(edac_mce, &edac_mce_list, list) {
+		if (edac_mce->check_error(edac_mce->priv, mce))
+			return 1;
+	}
+
+	/* Nobody queued the error */
+	return 0;
+}
+EXPORT_SYMBOL_GPL(edac_mce_parse);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors");

+ 2078 - 0
drivers/edac/i7core_edac.c

@@ -0,0 +1,2078 @@
+/* Intel i7 core/Nehalem Memory Controller kernel module
+ *
+ * This driver supports yhe memory controllers found on the Intel
+ * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx,
+ * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield
+ * and Westmere-EP.
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2 only.
+ *
+ * Copyright (c) 2009-2010 by:
+ *	 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ *
+ * Forked and adapted from the i5400_edac driver
+ *
+ * Based on the following public Intel datasheets:
+ * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
+ * Datasheet, Volume 2:
+ *	http://download.intel.com/design/processor/datashts/320835.pdf
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ *	http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * 	http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/edac.h>
+#include <linux/mmzone.h>
+#include <linux/edac_mce.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+
+#include "edac_core.h"
+
+/*
+ * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
+ * registers start at bus 255, and are not reported by BIOS.
+ * We currently find devices with only 2 sockets. In order to support more QPI
+ * Quick Path Interconnect, just increment this number.
+ */
+#define MAX_SOCKET_BUSES	2
+
+
+/*
+ * Alter this version for the module when modifications are made
+ */
+#define I7CORE_REVISION    " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR      "i7core_edac"
+
+/*
+ * Debug macros
+ */
+#define i7core_printk(level, fmt, arg...)			\
+	edac_printk(level, "i7core", fmt, ##arg)
+
+#define i7core_mc_printk(mci, level, fmt, arg...)		\
+	edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
+
+/*
+ * i7core Memory Controller Registers
+ */
+
+	/* OFFSETS for Device 0 Function 0 */
+
+#define MC_CFG_CONTROL	0x90
+
+	/* OFFSETS for Device 3 Function 0 */
+
+#define MC_CONTROL	0x48
+#define MC_STATUS	0x4c
+#define MC_MAX_DOD	0x64
+
+/*
+ * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#define MC_TEST_ERR_RCV1	0x60
+  #define DIMM2_COR_ERR(r)			((r) & 0x7fff)
+
+#define MC_TEST_ERR_RCV0	0x64
+  #define DIMM1_COR_ERR(r)			(((r) >> 16) & 0x7fff)
+  #define DIMM0_COR_ERR(r)			((r) & 0x7fff)
+
+/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+#define MC_COR_ECC_CNT_0	0x80
+#define MC_COR_ECC_CNT_1	0x84
+#define MC_COR_ECC_CNT_2	0x88
+#define MC_COR_ECC_CNT_3	0x8c
+#define MC_COR_ECC_CNT_4	0x90
+#define MC_COR_ECC_CNT_5	0x94
+
+#define DIMM_TOP_COR_ERR(r)			(((r) >> 16) & 0x7fff)
+#define DIMM_BOT_COR_ERR(r)			((r) & 0x7fff)
+
+
+	/* OFFSETS for Devices 4,5 and 6 Function 0 */
+
+#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
+  #define THREE_DIMMS_PRESENT		(1 << 24)
+  #define SINGLE_QUAD_RANK_PRESENT	(1 << 23)
+  #define QUAD_RANK_PRESENT		(1 << 22)
+  #define REGISTERED_DIMM		(1 << 15)
+
+#define MC_CHANNEL_MAPPER	0x60
+  #define RDLCH(r, ch)		((((r) >> (3 + (ch * 6))) & 0x07) - 1)
+  #define WRLCH(r, ch)		((((r) >> (ch * 6)) & 0x07) - 1)
+
+#define MC_CHANNEL_RANK_PRESENT 0x7c
+  #define RANK_PRESENT_MASK		0xffff
+
+#define MC_CHANNEL_ADDR_MATCH	0xf0
+#define MC_CHANNEL_ERROR_MASK	0xf8
+#define MC_CHANNEL_ERROR_INJECT	0xfc
+  #define INJECT_ADDR_PARITY	0x10
+  #define INJECT_ECC		0x08
+  #define MASK_CACHELINE	0x06
+  #define MASK_FULL_CACHELINE	0x06
+  #define MASK_MSB32_CACHELINE	0x04
+  #define MASK_LSB32_CACHELINE	0x02
+  #define NO_MASK_CACHELINE	0x00
+  #define REPEAT_EN		0x01
+
+	/* OFFSETS for Devices 4,5 and 6 Function 1 */
+
+#define MC_DOD_CH_DIMM0		0x48
+#define MC_DOD_CH_DIMM1		0x4c
+#define MC_DOD_CH_DIMM2		0x50
+  #define RANKOFFSET_MASK	((1 << 12) | (1 << 11) | (1 << 10))
+  #define RANKOFFSET(x)		((x & RANKOFFSET_MASK) >> 10)
+  #define DIMM_PRESENT_MASK	(1 << 9)
+  #define DIMM_PRESENT(x)	(((x) & DIMM_PRESENT_MASK) >> 9)
+  #define MC_DOD_NUMBANK_MASK		((1 << 8) | (1 << 7))
+  #define MC_DOD_NUMBANK(x)		(((x) & MC_DOD_NUMBANK_MASK) >> 7)
+  #define MC_DOD_NUMRANK_MASK		((1 << 6) | (1 << 5))
+  #define MC_DOD_NUMRANK(x)		(((x) & MC_DOD_NUMRANK_MASK) >> 5)
+  #define MC_DOD_NUMROW_MASK		((1 << 4) | (1 << 3) | (1 << 2))
+  #define MC_DOD_NUMROW(x)		(((x) & MC_DOD_NUMROW_MASK) >> 2)
+  #define MC_DOD_NUMCOL_MASK		3
+  #define MC_DOD_NUMCOL(x)		((x) & MC_DOD_NUMCOL_MASK)
+
+#define MC_RANK_PRESENT		0x7c
+
+#define MC_SAG_CH_0	0x80
+#define MC_SAG_CH_1	0x84
+#define MC_SAG_CH_2	0x88
+#define MC_SAG_CH_3	0x8c
+#define MC_SAG_CH_4	0x90
+#define MC_SAG_CH_5	0x94
+#define MC_SAG_CH_6	0x98
+#define MC_SAG_CH_7	0x9c
+
+#define MC_RIR_LIMIT_CH_0	0x40
+#define MC_RIR_LIMIT_CH_1	0x44
+#define MC_RIR_LIMIT_CH_2	0x48
+#define MC_RIR_LIMIT_CH_3	0x4C
+#define MC_RIR_LIMIT_CH_4	0x50
+#define MC_RIR_LIMIT_CH_5	0x54
+#define MC_RIR_LIMIT_CH_6	0x58
+#define MC_RIR_LIMIT_CH_7	0x5C
+#define MC_RIR_LIMIT_MASK	((1 << 10) - 1)
+
+#define MC_RIR_WAY_CH		0x80
+  #define MC_RIR_WAY_OFFSET_MASK	(((1 << 14) - 1) & ~0x7)
+  #define MC_RIR_WAY_RANK_MASK		0x7
+
+/*
+ * i7core structs
+ */
+
+#define NUM_CHANS 3
+#define MAX_DIMMS 3		/* Max DIMMS per channel */
+#define MAX_MCR_FUNC  4
+#define MAX_CHAN_FUNC 3
+
+struct i7core_info {
+	u32	mc_control;
+	u32	mc_status;
+	u32	max_dod;
+	u32	ch_map;
+};
+
+
+struct i7core_inject {
+	int	enable;
+
+	u32	section;
+	u32	type;
+	u32	eccmask;
+
+	/* Error address mask */
+	int channel, dimm, rank, bank, page, col;
+};
+
+struct i7core_channel {
+	u32		ranks;
+	u32		dimms;
+};
+
+struct pci_id_descr {
+	int			dev;
+	int			func;
+	int 			dev_id;
+	int			optional;
+};
+
+struct pci_id_table {
+	struct pci_id_descr	*descr;
+	int			n_devs;
+};
+
+struct i7core_dev {
+	struct list_head	list;
+	u8			socket;
+	struct pci_dev		**pdev;
+	int			n_devs;
+	struct mem_ctl_info	*mci;
+};
+
+struct i7core_pvt {
+	struct pci_dev	*pci_noncore;
+	struct pci_dev	*pci_mcr[MAX_MCR_FUNC + 1];
+	struct pci_dev	*pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
+
+	struct i7core_dev *i7core_dev;
+
+	struct i7core_info	info;
+	struct i7core_inject	inject;
+	struct i7core_channel	channel[NUM_CHANS];
+
+	int		channels; /* Number of active channels */
+
+	int		ce_count_available;
+	int 		csrow_map[NUM_CHANS][MAX_DIMMS];
+
+			/* ECC corrected errors counts per udimm */
+	unsigned long	udimm_ce_count[MAX_DIMMS];
+	int		udimm_last_ce_count[MAX_DIMMS];
+			/* ECC corrected errors counts per rdimm */
+	unsigned long	rdimm_ce_count[NUM_CHANS][MAX_DIMMS];
+	int		rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS];
+
+	unsigned int	is_registered;
+
+	/* mcelog glue */
+	struct edac_mce		edac_mce;
+
+	/* Fifo double buffers */
+	struct mce		mce_entry[MCE_LOG_LEN];
+	struct mce		mce_outentry[MCE_LOG_LEN];
+
+	/* Fifo in/out counters */
+	unsigned		mce_in, mce_out;
+
+	/* Count indicator to show errors not got */
+	unsigned		mce_overrun;
+};
+
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+
+#define PCI_DESCR(device, function, device_id)	\
+	.dev = (device),			\
+	.func = (function),			\
+	.dev_id = (device_id)
+
+struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
+		/* Memory controller */
+	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR)     },
+	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD)  },
+			/* Exists only for RDIMM */
+	{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1  },
+	{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
+
+		/* Channel 0 */
+	{ PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) },
+	{ PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) },
+	{ PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) },
+	{ PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC)   },
+
+		/* Channel 1 */
+	{ PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) },
+	{ PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) },
+	{ PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) },
+	{ PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC)   },
+
+		/* Channel 2 */
+	{ PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) },
+	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
+	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
+	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC)   },
+
+		/* Generic Non-core registers */
+	/*
+	 * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
+	 * On Xeon 55xx, however, it has a different id (8086:2c40). So,
+	 * the probing code needs to test for the other address in case of
+	 * failure of this one
+	 */
+	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE)  },
+
+};
+
+struct pci_id_descr pci_dev_descr_lynnfield[] = {
+	{ PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR)         },
+	{ PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD)      },
+	{ PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST)     },
+
+	{ PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL) },
+	{ PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR) },
+	{ PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) },
+	{ PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC)   },
+
+	{ PCI_DESCR( 5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) },
+	{ PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
+	{ PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
+	{ PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC)   },
+
+	/*
+	 * This is the PCI device has an alternate address on some
+	 * processors like Core i7 860
+	 */
+	{ PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)     },
+};
+
+struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
+		/* Memory controller */
+	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2)     },
+	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2)  },
+			/* Exists only for RDIMM */
+	{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2), .optional = 1  },
+	{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2) },
+
+		/* Channel 0 */
+	{ PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2) },
+	{ PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2) },
+	{ PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2) },
+	{ PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2)   },
+
+		/* Channel 1 */
+	{ PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2) },
+	{ PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2) },
+	{ PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2) },
+	{ PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2)   },
+
+		/* Channel 2 */
+	{ PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2) },
+	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
+	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
+	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2)   },
+
+		/* Generic Non-core registers */
+	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2)  },
+
+};
+
+#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) }
+struct pci_id_table pci_dev_table[] = {
+	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
+	PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
+	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
+};
+
+/*
+ *	pci_device_id	table for which devices we are looking for
+ */
+static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
+	{0,}			/* 0 terminated list. */
+};
+
+static struct edac_pci_ctl_info *i7core_pci;
+
+/****************************************************************************
+			Anciliary status routines
+ ****************************************************************************/
+
+	/* MC_CONTROL bits */
+#define CH_ACTIVE(pvt, ch)	((pvt)->info.mc_control & (1 << (8 + ch)))
+#define ECCx8(pvt)		((pvt)->info.mc_control & (1 << 1))
+
+	/* MC_STATUS bits */
+#define ECC_ENABLED(pvt)	((pvt)->info.mc_status & (1 << 4))
+#define CH_DISABLED(pvt, ch)	((pvt)->info.mc_status & (1 << ch))
+
+	/* MC_MAX_DOD read functions */
+static inline int numdimms(u32 dimms)
+{
+	return (dimms & 0x3) + 1;
+}
+
+static inline int numrank(u32 rank)
+{
+	static int ranks[4] = { 1, 2, 4, -EINVAL };
+
+	return ranks[rank & 0x3];
+}
+
+static inline int numbank(u32 bank)
+{
+	static int banks[4] = { 4, 8, 16, -EINVAL };
+
+	return banks[bank & 0x3];
+}
+
+static inline int numrow(u32 row)
+{
+	static int rows[8] = {
+		1 << 12, 1 << 13, 1 << 14, 1 << 15,
+		1 << 16, -EINVAL, -EINVAL, -EINVAL,
+	};
+
+	return rows[row & 0x7];
+}
+
+static inline int numcol(u32 col)
+{
+	static int cols[8] = {
+		1 << 10, 1 << 11, 1 << 12, -EINVAL,
+	};
+	return cols[col & 0x3];
+}
+
+static struct i7core_dev *get_i7core_dev(u8 socket)
+{
+	struct i7core_dev *i7core_dev;
+
+	list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+		if (i7core_dev->socket == socket)
+			return i7core_dev;
+	}
+
+	return NULL;
+}
+
+/****************************************************************************
+			Memory check routines
+ ****************************************************************************/
+static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
+					  unsigned func)
+{
+	struct i7core_dev *i7core_dev = get_i7core_dev(socket);
+	int i;
+
+	if (!i7core_dev)
+		return NULL;
+
+	for (i = 0; i < i7core_dev->n_devs; i++) {
+		if (!i7core_dev->pdev[i])
+			continue;
+
+		if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
+		    PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
+			return i7core_dev->pdev[i];
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * i7core_get_active_channels() - gets the number of channels and csrows
+ * @socket:	Quick Path Interconnect socket
+ * @channels:	Number of channels that will be returned
+ * @csrows:	Number of csrows found
+ *
+ * Since EDAC core needs to know in advance the number of available channels
+ * and csrows, in order to allocate memory for csrows/channels, it is needed
+ * to run two similar steps. At the first step, implemented on this function,
+ * it checks the number of csrows/channels present at one socket.
+ * this is used in order to properly allocate the size of mci components.
+ *
+ * It should be noticed that none of the current available datasheets explain
+ * or even mention how csrows are seen by the memory controller. So, we need
+ * to add a fake description for csrows.
+ * So, this driver is attributing one DIMM memory for one csrow.
+ */
+static int i7core_get_active_channels(u8 socket, unsigned *channels,
+				      unsigned *csrows)
+{
+	struct pci_dev *pdev = NULL;
+	int i, j;
+	u32 status, control;
+
+	*channels = 0;
+	*csrows = 0;
+
+	pdev = get_pdev_slot_func(socket, 3, 0);
+	if (!pdev) {
+		i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n",
+			      socket);
+		return -ENODEV;
+	}
+
+	/* Device 3 function 0 reads */
+	pci_read_config_dword(pdev, MC_STATUS, &status);
+	pci_read_config_dword(pdev, MC_CONTROL, &control);
+
+	for (i = 0; i < NUM_CHANS; i++) {
+		u32 dimm_dod[3];
+		/* Check if the channel is active */
+		if (!(control & (1 << (8 + i))))
+			continue;
+
+		/* Check if the channel is disabled */
+		if (status & (1 << i))
+			continue;
+
+		pdev = get_pdev_slot_func(socket, i + 4, 1);
+		if (!pdev) {
+			i7core_printk(KERN_ERR, "Couldn't find socket %d "
+						"fn %d.%d!!!\n",
+						socket, i + 4, 1);
+			return -ENODEV;
+		}
+		/* Devices 4-6 function 1 */
+		pci_read_config_dword(pdev,
+				MC_DOD_CH_DIMM0, &dimm_dod[0]);
+		pci_read_config_dword(pdev,
+				MC_DOD_CH_DIMM1, &dimm_dod[1]);
+		pci_read_config_dword(pdev,
+				MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+		(*channels)++;
+
+		for (j = 0; j < 3; j++) {
+			if (!DIMM_PRESENT(dimm_dod[j]))
+				continue;
+			(*csrows)++;
+		}
+	}
+
+	debugf0("Number of active channels on socket %d: %d\n",
+		socket, *channels);
+
+	return 0;
+}
+
+static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	struct csrow_info *csr;
+	struct pci_dev *pdev;
+	int i, j;
+	unsigned long last_page = 0;
+	enum edac_type mode;
+	enum mem_type mtype;
+
+	/* Get data from the MC register, function 0 */
+	pdev = pvt->pci_mcr[0];
+	if (!pdev)
+		return -ENODEV;
+
+	/* Device 3 function 0 reads */
+	pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control);
+	pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status);
+	pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
+	pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
+
+	debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
+		pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status,
+		pvt->info.max_dod, pvt->info.ch_map);
+
+	if (ECC_ENABLED(pvt)) {
+		debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
+		if (ECCx8(pvt))
+			mode = EDAC_S8ECD8ED;
+		else
+			mode = EDAC_S4ECD4ED;
+	} else {
+		debugf0("ECC disabled\n");
+		mode = EDAC_NONE;
+	}
+
+	/* FIXME: need to handle the error codes */
+	debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked "
+		"x%x x 0x%x\n",
+		numdimms(pvt->info.max_dod),
+		numrank(pvt->info.max_dod >> 2),
+		numbank(pvt->info.max_dod >> 4),
+		numrow(pvt->info.max_dod >> 6),
+		numcol(pvt->info.max_dod >> 9));
+
+	for (i = 0; i < NUM_CHANS; i++) {
+		u32 data, dimm_dod[3], value[8];
+
+		if (!pvt->pci_ch[i][0])
+			continue;
+
+		if (!CH_ACTIVE(pvt, i)) {
+			debugf0("Channel %i is not active\n", i);
+			continue;
+		}
+		if (CH_DISABLED(pvt, i)) {
+			debugf0("Channel %i is disabled\n", i);
+			continue;
+		}
+
+		/* Devices 4-6 function 0 */
+		pci_read_config_dword(pvt->pci_ch[i][0],
+				MC_CHANNEL_DIMM_INIT_PARAMS, &data);
+
+		pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ?
+						4 : 2;
+
+		if (data & REGISTERED_DIMM)
+			mtype = MEM_RDDR3;
+		else
+			mtype = MEM_DDR3;
+#if 0
+		if (data & THREE_DIMMS_PRESENT)
+			pvt->channel[i].dimms = 3;
+		else if (data & SINGLE_QUAD_RANK_PRESENT)
+			pvt->channel[i].dimms = 1;
+		else
+			pvt->channel[i].dimms = 2;
+#endif
+
+		/* Devices 4-6 function 1 */
+		pci_read_config_dword(pvt->pci_ch[i][1],
+				MC_DOD_CH_DIMM0, &dimm_dod[0]);
+		pci_read_config_dword(pvt->pci_ch[i][1],
+				MC_DOD_CH_DIMM1, &dimm_dod[1]);
+		pci_read_config_dword(pvt->pci_ch[i][1],
+				MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+		debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
+			"%d ranks, %cDIMMs\n",
+			i,
+			RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
+			data,
+			pvt->channel[i].ranks,
+			(data & REGISTERED_DIMM) ? 'R' : 'U');
+
+		for (j = 0; j < 3; j++) {
+			u32 banks, ranks, rows, cols;
+			u32 size, npages;
+
+			if (!DIMM_PRESENT(dimm_dod[j]))
+				continue;
+
+			banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
+			ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
+			rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
+			cols = numcol(MC_DOD_NUMCOL(dimm_dod[j]));
+
+			/* DDR3 has 8 I/O banks */
+			size = (rows * cols * banks * ranks) >> (20 - 3);
+
+			pvt->channel[i].dimms++;
+
+			debugf0("\tdimm %d %d Mb offset: %x, "
+				"bank: %d, rank: %d, row: %#x, col: %#x\n",
+				j, size,
+				RANKOFFSET(dimm_dod[j]),
+				banks, ranks, rows, cols);
+
+#if PAGE_SHIFT > 20
+			npages = size >> (PAGE_SHIFT - 20);
+#else
+			npages = size << (20 - PAGE_SHIFT);
+#endif
+
+			csr = &mci->csrows[*csrow];
+			csr->first_page = last_page + 1;
+			last_page += npages;
+			csr->last_page = last_page;
+			csr->nr_pages = npages;
+
+			csr->page_mask = 0;
+			csr->grain = 8;
+			csr->csrow_idx = *csrow;
+			csr->nr_channels = 1;
+
+			csr->channels[0].chan_idx = i;
+			csr->channels[0].ce_count = 0;
+
+			pvt->csrow_map[i][j] = *csrow;
+
+			switch (banks) {
+			case 4:
+				csr->dtype = DEV_X4;
+				break;
+			case 8:
+				csr->dtype = DEV_X8;
+				break;
+			case 16:
+				csr->dtype = DEV_X16;
+				break;
+			default:
+				csr->dtype = DEV_UNKNOWN;
+			}
+
+			csr->edac_mode = mode;
+			csr->mtype = mtype;
+
+			(*csrow)++;
+		}
+
+		pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
+		pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
+		pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
+		pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
+		pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
+		pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
+		pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
+		pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
+		debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
+		for (j = 0; j < 8; j++)
+			debugf1("\t\t%#x\t%#x\t%#x\n",
+				(value[j] >> 27) & 0x1,
+				(value[j] >> 24) & 0x7,
+				(value[j] && ((1 << 24) - 1)));
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+			Error insertion routines
+ ****************************************************************************/
+
+/* The i7core has independent error injection features per channel.
+   However, to have a simpler code, we don't allow enabling error injection
+   on more than one channel.
+   Also, since a change at an inject parameter will be applied only at enable,
+   we're disabling error injection on all write calls to the sysfs nodes that
+   controls the error code injection.
+ */
+static int disable_inject(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+
+	pvt->inject.enable = 0;
+
+	if (!pvt->pci_ch[pvt->inject.channel][0])
+		return -ENODEV;
+
+	pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+				MC_CHANNEL_ERROR_INJECT, 0);
+
+	return 0;
+}
+
+/*
+ * i7core inject inject.section
+ *
+ *	accept and store error injection inject.section value
+ *	bit 0 - refers to the lower 32-byte half cacheline
+ *	bit 1 - refers to the upper 32-byte half cacheline
+ */
+static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+					   const char *data, size_t count)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	unsigned long value;
+	int rc;
+
+	if (pvt->inject.enable)
+		disable_inject(mci);
+
+	rc = strict_strtoul(data, 10, &value);
+	if ((rc < 0) || (value > 3))
+		return -EIO;
+
+	pvt->inject.section = (u32) value;
+	return count;
+}
+
+static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
+					      char *data)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	return sprintf(data, "0x%08x\n", pvt->inject.section);
+}
+
+/*
+ * i7core inject.type
+ *
+ *	accept and store error injection inject.section value
+ *	bit 0 - repeat enable - Enable error repetition
+ *	bit 1 - inject ECC error
+ *	bit 2 - inject parity error
+ */
+static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+					const char *data, size_t count)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	unsigned long value;
+	int rc;
+
+	if (pvt->inject.enable)
+		disable_inject(mci);
+
+	rc = strict_strtoul(data, 10, &value);
+	if ((rc < 0) || (value > 7))
+		return -EIO;
+
+	pvt->inject.type = (u32) value;
+	return count;
+}
+
+static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
+					      char *data)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	return sprintf(data, "0x%08x\n", pvt->inject.type);
+}
+
+/*
+ * i7core_inject_inject.eccmask_store
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ *   Any bits set to a 1 will flip the corresponding ECC bit
+ *   Correctable errors can be injected by flipping 1 bit or the bits within
+ *   a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ *   uncorrectable error to be injected.
+ */
+static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
+					const char *data, size_t count)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	unsigned long value;
+	int rc;
+
+	if (pvt->inject.enable)
+		disable_inject(mci);
+
+	rc = strict_strtoul(data, 10, &value);
+	if (rc < 0)
+		return -EIO;
+
+	pvt->inject.eccmask = (u32) value;
+	return count;
+}
+
+static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
+					      char *data)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
+}
+
+/*
+ * i7core_addrmatch
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ *   Any bits set to a 1 will flip the corresponding ECC bit
+ *   Correctable errors can be injected by flipping 1 bit or the bits within
+ *   a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ *   uncorrectable error to be injected.
+ */
+
+#define DECLARE_ADDR_MATCH(param, limit)			\
+static ssize_t i7core_inject_store_##param(			\
+		struct mem_ctl_info *mci,			\
+		const char *data, size_t count)			\
+{								\
+	struct i7core_pvt *pvt;					\
+	long value;						\
+	int rc;							\
+								\
+	debugf1("%s()\n", __func__);				\
+	pvt = mci->pvt_info;					\
+								\
+	if (pvt->inject.enable)					\
+		disable_inject(mci);				\
+								\
+	if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\
+		value = -1;					\
+	else {							\
+		rc = strict_strtoul(data, 10, &value);		\
+		if ((rc < 0) || (value >= limit))		\
+			return -EIO;				\
+	}							\
+								\
+	pvt->inject.param = value;				\
+								\
+	return count;						\
+}								\
+								\
+static ssize_t i7core_inject_show_##param(			\
+		struct mem_ctl_info *mci,			\
+		char *data)					\
+{								\
+	struct i7core_pvt *pvt;					\
+								\
+	pvt = mci->pvt_info;					\
+	debugf1("%s() pvt=%p\n", __func__, pvt);		\
+	if (pvt->inject.param < 0)				\
+		return sprintf(data, "any\n");			\
+	else							\
+		return sprintf(data, "%d\n", pvt->inject.param);\
+}
+
+#define ATTR_ADDR_MATCH(param)					\
+	{							\
+		.attr = {					\
+			.name = #param,				\
+			.mode = (S_IRUGO | S_IWUSR)		\
+		},						\
+		.show  = i7core_inject_show_##param,		\
+		.store = i7core_inject_store_##param,		\
+	}
+
+DECLARE_ADDR_MATCH(channel, 3);
+DECLARE_ADDR_MATCH(dimm, 3);
+DECLARE_ADDR_MATCH(rank, 4);
+DECLARE_ADDR_MATCH(bank, 32);
+DECLARE_ADDR_MATCH(page, 0x10000);
+DECLARE_ADDR_MATCH(col, 0x4000);
+
+static int write_and_test(struct pci_dev *dev, int where, u32 val)
+{
+	u32 read;
+	int count;
+
+	debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n",
+		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+		where, val);
+
+	for (count = 0; count < 10; count++) {
+		if (count)
+			msleep(100);
+		pci_write_config_dword(dev, where, val);
+		pci_read_config_dword(dev, where, &read);
+
+		if (read == val)
+			return 0;
+	}
+
+	i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x "
+		"write=%08x. Read=%08x\n",
+		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+		where, val, read);
+
+	return -EINVAL;
+}
+
+/*
+ * This routine prepares the Memory Controller for error injection.
+ * The error will be injected when some process tries to write to the
+ * memory that matches the given criteria.
+ * The criteria can be set in terms of a mask where dimm, rank, bank, page
+ * and col can be specified.
+ * A -1 value for any of the mask items will make the MCU to ignore
+ * that matching criteria for error injection.
+ *
+ * It should be noticed that the error will only happen after a write operation
+ * on a memory that matches the condition. if REPEAT_EN is not enabled at
+ * inject mask, then it will produce just one error. Otherwise, it will repeat
+ * until the injectmask would be cleaned.
+ *
+ * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
+ *    is reliable enough to check if the MC is using the
+ *    three channels. However, this is not clear at the datasheet.
+ */
+static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
+				       const char *data, size_t count)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	u32 injectmask;
+	u64 mask = 0;
+	int  rc;
+	long enable;
+
+	if (!pvt->pci_ch[pvt->inject.channel][0])
+		return 0;
+
+	rc = strict_strtoul(data, 10, &enable);
+	if ((rc < 0))
+		return 0;
+
+	if (enable) {
+		pvt->inject.enable = 1;
+	} else {
+		disable_inject(mci);
+		return count;
+	}
+
+	/* Sets pvt->inject.dimm mask */
+	if (pvt->inject.dimm < 0)
+		mask |= 1LL << 41;
+	else {
+		if (pvt->channel[pvt->inject.channel].dimms > 2)
+			mask |= (pvt->inject.dimm & 0x3LL) << 35;
+		else
+			mask |= (pvt->inject.dimm & 0x1LL) << 36;
+	}
+
+	/* Sets pvt->inject.rank mask */
+	if (pvt->inject.rank < 0)
+		mask |= 1LL << 40;
+	else {
+		if (pvt->channel[pvt->inject.channel].dimms > 2)
+			mask |= (pvt->inject.rank & 0x1LL) << 34;
+		else
+			mask |= (pvt->inject.rank & 0x3LL) << 34;
+	}
+
+	/* Sets pvt->inject.bank mask */
+	if (pvt->inject.bank < 0)
+		mask |= 1LL << 39;
+	else
+		mask |= (pvt->inject.bank & 0x15LL) << 30;
+
+	/* Sets pvt->inject.page mask */
+	if (pvt->inject.page < 0)
+		mask |= 1LL << 38;
+	else
+		mask |= (pvt->inject.page & 0xffff) << 14;
+
+	/* Sets pvt->inject.column mask */
+	if (pvt->inject.col < 0)
+		mask |= 1LL << 37;
+	else
+		mask |= (pvt->inject.col & 0x3fff);
+
+	/*
+	 * bit    0: REPEAT_EN
+	 * bits 1-2: MASK_HALF_CACHELINE
+	 * bit    3: INJECT_ECC
+	 * bit    4: INJECT_ADDR_PARITY
+	 */
+
+	injectmask = (pvt->inject.type & 1) |
+		     (pvt->inject.section & 0x3) << 1 |
+		     (pvt->inject.type & 0x6) << (3 - 1);
+
+	/* Unlock writes to registers - this register is write only */
+	pci_write_config_dword(pvt->pci_noncore,
+			       MC_CFG_CONTROL, 0x2);
+
+	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+			       MC_CHANNEL_ADDR_MATCH, mask);
+	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+			       MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L);
+
+	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+			       MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
+
+	write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+			       MC_CHANNEL_ERROR_INJECT, injectmask);
+
+	/*
+	 * This is something undocumented, based on my tests
+	 * Without writing 8 to this register, errors aren't injected. Not sure
+	 * why.
+	 */
+	pci_write_config_dword(pvt->pci_noncore,
+			       MC_CFG_CONTROL, 8);
+
+	debugf0("Error inject addr match 0x%016llx, ecc 0x%08x,"
+		" inject 0x%08x\n",
+		mask, pvt->inject.eccmask, injectmask);
+
+
+	return count;
+}
+
+static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
+					char *data)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	u32 injectmask;
+
+	if (!pvt->pci_ch[pvt->inject.channel][0])
+		return 0;
+
+	pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+			       MC_CHANNEL_ERROR_INJECT, &injectmask);
+
+	debugf0("Inject error read: 0x%018x\n", injectmask);
+
+	if (injectmask & 0x0c)
+		pvt->inject.enable = 1;
+
+	return sprintf(data, "%d\n", pvt->inject.enable);
+}
+
+#define DECLARE_COUNTER(param)					\
+static ssize_t i7core_show_counter_##param(			\
+		struct mem_ctl_info *mci,			\
+		char *data)					\
+{								\
+	struct i7core_pvt *pvt = mci->pvt_info;			\
+								\
+	debugf1("%s() \n", __func__);				\
+	if (!pvt->ce_count_available || (pvt->is_registered))	\
+		return sprintf(data, "data unavailable\n");	\
+	return sprintf(data, "%lu\n",				\
+			pvt->udimm_ce_count[param]);		\
+}
+
+#define ATTR_COUNTER(param)					\
+	{							\
+		.attr = {					\
+			.name = __stringify(udimm##param),	\
+			.mode = (S_IRUGO | S_IWUSR)		\
+		},						\
+		.show  = i7core_show_counter_##param		\
+	}
+
+DECLARE_COUNTER(0);
+DECLARE_COUNTER(1);
+DECLARE_COUNTER(2);
+
+/*
+ * Sysfs struct
+ */
+
+
+static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
+	ATTR_ADDR_MATCH(channel),
+	ATTR_ADDR_MATCH(dimm),
+	ATTR_ADDR_MATCH(rank),
+	ATTR_ADDR_MATCH(bank),
+	ATTR_ADDR_MATCH(page),
+	ATTR_ADDR_MATCH(col),
+	{ .attr = { .name = NULL } }
+};
+
+static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+	.name  = "inject_addrmatch",
+	.mcidev_attr = i7core_addrmatch_attrs,
+};
+
+static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+	ATTR_COUNTER(0),
+	ATTR_COUNTER(1),
+	ATTR_COUNTER(2),
+};
+
+static struct mcidev_sysfs_group i7core_udimm_counters = {
+	.name  = "all_channel_counts",
+	.mcidev_attr = i7core_udimm_counters_attrs,
+};
+
+static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
+	{
+		.attr = {
+			.name = "inject_section",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_section_show,
+		.store = i7core_inject_section_store,
+	}, {
+		.attr = {
+			.name = "inject_type",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_type_show,
+		.store = i7core_inject_type_store,
+	}, {
+		.attr = {
+			.name = "inject_eccmask",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_eccmask_show,
+		.store = i7core_inject_eccmask_store,
+	}, {
+		.grp = &i7core_inject_addrmatch,
+	}, {
+		.attr = {
+			.name = "inject_enable",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_enable_show,
+		.store = i7core_inject_enable_store,
+	},
+	{ .attr = { .name = NULL } },	/* Reserved for udimm counters */
+	{ .attr = { .name = NULL } }
+};
+
+/****************************************************************************
+	Device initialization routines: put/get, init/exit
+ ****************************************************************************/
+
+/*
+ *	i7core_put_devices	'put' all the devices that we have
+ *				reserved via 'get'
+ */
+static void i7core_put_devices(struct i7core_dev *i7core_dev)
+{
+	int i;
+
+	debugf0(__FILE__ ": %s()\n", __func__);
+	for (i = 0; i < i7core_dev->n_devs; i++) {
+		struct pci_dev *pdev = i7core_dev->pdev[i];
+		if (!pdev)
+			continue;
+		debugf0("Removing dev %02x:%02x.%d\n",
+			pdev->bus->number,
+			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+		pci_dev_put(pdev);
+	}
+	kfree(i7core_dev->pdev);
+	list_del(&i7core_dev->list);
+	kfree(i7core_dev);
+}
+
+static void i7core_put_all_devices(void)
+{
+	struct i7core_dev *i7core_dev, *tmp;
+
+	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list)
+		i7core_put_devices(i7core_dev);
+}
+
+static void __init i7core_xeon_pci_fixup(struct pci_id_table *table)
+{
+	struct pci_dev *pdev = NULL;
+	int i;
+	/*
+	 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
+	 * aren't announced by acpi. So, we need to use a legacy scan probing
+	 * to detect them
+	 */
+	while (table && table->descr) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, table->descr[0].dev_id, NULL);
+		if (unlikely(!pdev)) {
+			for (i = 0; i < MAX_SOCKET_BUSES; i++)
+				pcibios_scan_specific_bus(255-i);
+		}
+		table++;
+	}
+}
+
+/*
+ *	i7core_get_devices	Find and perform 'get' operation on the MCH's
+ *			device/functions we want to reference for this driver
+ *
+ *			Need to 'get' device 16 func 1 and func 2
+ */
+int i7core_get_onedevice(struct pci_dev **prev, int devno,
+			 struct pci_id_descr *dev_descr, unsigned n_devs)
+{
+	struct i7core_dev *i7core_dev;
+
+	struct pci_dev *pdev = NULL;
+	u8 bus = 0;
+	u8 socket = 0;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+			      dev_descr->dev_id, *prev);
+
+	/*
+	 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+	 * is at addr 8086:2c40, instead of 8086:2c41. So, we need
+	 * to probe for the alternate address in case of failure
+	 */
+	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+
+	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
+				      *prev);
+
+	if (!pdev) {
+		if (*prev) {
+			*prev = pdev;
+			return 0;
+		}
+
+		if (dev_descr->optional)
+			return 0;
+
+		if (devno == 0)
+			return -ENODEV;
+
+		i7core_printk(KERN_ERR,
+			"Device not found: dev %02x.%d PCI ID %04x:%04x\n",
+			dev_descr->dev, dev_descr->func,
+			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+		/* End of list, leave */
+		return -ENODEV;
+	}
+	bus = pdev->bus->number;
+
+	if (bus == 0x3f)
+		socket = 0;
+	else
+		socket = 255 - bus;
+
+	i7core_dev = get_i7core_dev(socket);
+	if (!i7core_dev) {
+		i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+		if (!i7core_dev)
+			return -ENOMEM;
+		i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs,
+					   GFP_KERNEL);
+		if (!i7core_dev->pdev) {
+			kfree(i7core_dev);
+			return -ENOMEM;
+		}
+		i7core_dev->socket = socket;
+		i7core_dev->n_devs = n_devs;
+		list_add_tail(&i7core_dev->list, &i7core_edac_list);
+	}
+
+	if (i7core_dev->pdev[devno]) {
+		i7core_printk(KERN_ERR,
+			"Duplicated device for "
+			"dev %02x:%02x.%d PCI ID %04x:%04x\n",
+			bus, dev_descr->dev, dev_descr->func,
+			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+		pci_dev_put(pdev);
+		return -ENODEV;
+	}
+
+	i7core_dev->pdev[devno] = pdev;
+
+	/* Sanity check */
+	if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
+			PCI_FUNC(pdev->devfn) != dev_descr->func)) {
+		i7core_printk(KERN_ERR,
+			"Device PCI ID %04x:%04x "
+			"has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n",
+			PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
+			bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			bus, dev_descr->dev, dev_descr->func);
+		return -ENODEV;
+	}
+
+	/* Be sure that the device is enabled */
+	if (unlikely(pci_enable_device(pdev) < 0)) {
+		i7core_printk(KERN_ERR,
+			"Couldn't enable "
+			"dev %02x:%02x.%d PCI ID %04x:%04x\n",
+			bus, dev_descr->dev, dev_descr->func,
+			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+		return -ENODEV;
+	}
+
+	debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
+		socket, bus, dev_descr->dev,
+		dev_descr->func,
+		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+	*prev = pdev;
+
+	return 0;
+}
+
+static int i7core_get_devices(struct pci_id_table *table)
+{
+	int i, rc;
+	struct pci_dev *pdev = NULL;
+	struct pci_id_descr *dev_descr;
+
+	while (table && table->descr) {
+		dev_descr = table->descr;
+		for (i = 0; i < table->n_devs; i++) {
+			pdev = NULL;
+			do {
+				rc = i7core_get_onedevice(&pdev, i, &dev_descr[i],
+							  table->n_devs);
+				if (rc < 0) {
+					if (i == 0) {
+						i = table->n_devs;
+						break;
+					}
+					i7core_put_all_devices();
+					return -ENODEV;
+				}
+			} while (pdev);
+		}
+		table++;
+	}
+
+	return 0;
+	return 0;
+}
+
+static int mci_bind_devs(struct mem_ctl_info *mci,
+			 struct i7core_dev *i7core_dev)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	struct pci_dev *pdev;
+	int i, func, slot;
+
+	/* Associates i7core_dev and mci for future usage */
+	pvt->i7core_dev = i7core_dev;
+	i7core_dev->mci = mci;
+
+	pvt->is_registered = 0;
+	for (i = 0; i < i7core_dev->n_devs; i++) {
+		pdev = i7core_dev->pdev[i];
+		if (!pdev)
+			continue;
+
+		func = PCI_FUNC(pdev->devfn);
+		slot = PCI_SLOT(pdev->devfn);
+		if (slot == 3) {
+			if (unlikely(func > MAX_MCR_FUNC))
+				goto error;
+			pvt->pci_mcr[func] = pdev;
+		} else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) {
+			if (unlikely(func > MAX_CHAN_FUNC))
+				goto error;
+			pvt->pci_ch[slot - 4][func] = pdev;
+		} else if (!slot && !func)
+			pvt->pci_noncore = pdev;
+		else
+			goto error;
+
+		debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
+			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			pdev, i7core_dev->socket);
+
+		if (PCI_SLOT(pdev->devfn) == 3 &&
+			PCI_FUNC(pdev->devfn) == 2)
+			pvt->is_registered = 1;
+	}
+
+	/*
+	 * Add extra nodes to count errors on udimm
+	 * For registered memory, this is not needed, since the counters
+	 * are already displayed at the standard locations
+	 */
+	if (!pvt->is_registered)
+		i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp =
+			&i7core_udimm_counters;
+
+	return 0;
+
+error:
+	i7core_printk(KERN_ERR, "Device %d, function %d "
+		      "is out of the expected range\n",
+		      slot, func);
+	return -EINVAL;
+}
+
+/****************************************************************************
+			Error check routines
+ ****************************************************************************/
+static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
+					 int chan, int dimm, int add)
+{
+	char *msg;
+	struct i7core_pvt *pvt = mci->pvt_info;
+	int row = pvt->csrow_map[chan][dimm], i;
+
+	for (i = 0; i < add; i++) {
+		msg = kasprintf(GFP_KERNEL, "Corrected error "
+				"(Socket=%d channel=%d dimm=%d)",
+				pvt->i7core_dev->socket, chan, dimm);
+
+		edac_mc_handle_fbd_ce(mci, row, 0, msg);
+		kfree (msg);
+	}
+}
+
+static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
+			int chan, int new0, int new1, int new2)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	int add0 = 0, add1 = 0, add2 = 0;
+	/* Updates CE counters if it is not the first time here */
+	if (pvt->ce_count_available) {
+		/* Updates CE counters */
+
+		add2 = new2 - pvt->rdimm_last_ce_count[chan][2];
+		add1 = new1 - pvt->rdimm_last_ce_count[chan][1];
+		add0 = new0 - pvt->rdimm_last_ce_count[chan][0];
+
+		if (add2 < 0)
+			add2 += 0x7fff;
+		pvt->rdimm_ce_count[chan][2] += add2;
+
+		if (add1 < 0)
+			add1 += 0x7fff;
+		pvt->rdimm_ce_count[chan][1] += add1;
+
+		if (add0 < 0)
+			add0 += 0x7fff;
+		pvt->rdimm_ce_count[chan][0] += add0;
+	} else
+		pvt->ce_count_available = 1;
+
+	/* Store the new values */
+	pvt->rdimm_last_ce_count[chan][2] = new2;
+	pvt->rdimm_last_ce_count[chan][1] = new1;
+	pvt->rdimm_last_ce_count[chan][0] = new0;
+
+	/*updated the edac core */
+	if (add0 != 0)
+		i7core_rdimm_update_csrow(mci, chan, 0, add0);
+	if (add1 != 0)
+		i7core_rdimm_update_csrow(mci, chan, 1, add1);
+	if (add2 != 0)
+		i7core_rdimm_update_csrow(mci, chan, 2, add2);
+
+}
+
+static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	u32 rcv[3][2];
+	int i, new0, new1, new2;
+
+	/*Read DEV 3: FUN 2:  MC_COR_ECC_CNT regs directly*/
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0,
+								&rcv[0][0]);
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1,
+								&rcv[0][1]);
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2,
+								&rcv[1][0]);
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3,
+								&rcv[1][1]);
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4,
+								&rcv[2][0]);
+	pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
+								&rcv[2][1]);
+	for (i = 0 ; i < 3; i++) {
+		debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
+			(i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
+		/*if the channel has 3 dimms*/
+		if (pvt->channel[i].dimms > 2) {
+			new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
+			new1 = DIMM_TOP_COR_ERR(rcv[i][0]);
+			new2 = DIMM_BOT_COR_ERR(rcv[i][1]);
+		} else {
+			new0 = DIMM_TOP_COR_ERR(rcv[i][0]) +
+					DIMM_BOT_COR_ERR(rcv[i][0]);
+			new1 = DIMM_TOP_COR_ERR(rcv[i][1]) +
+					DIMM_BOT_COR_ERR(rcv[i][1]);
+			new2 = 0;
+		}
+
+		i7core_rdimm_update_ce_count(mci, i, new0, new1, new2);
+	}
+}
+
+/* This function is based on the device 3 function 4 registers as described on:
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ *	http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * 	http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	u32 rcv1, rcv0;
+	int new0, new1, new2;
+
+	if (!pvt->pci_mcr[4]) {
+		debugf0("%s MCR registers not found\n", __func__);
+		return;
+	}
+
+	/* Corrected test errors */
+	pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1);
+	pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0);
+
+	/* Store the new values */
+	new2 = DIMM2_COR_ERR(rcv1);
+	new1 = DIMM1_COR_ERR(rcv0);
+	new0 = DIMM0_COR_ERR(rcv0);
+
+	/* Updates CE counters if it is not the first time here */
+	if (pvt->ce_count_available) {
+		/* Updates CE counters */
+		int add0, add1, add2;
+
+		add2 = new2 - pvt->udimm_last_ce_count[2];
+		add1 = new1 - pvt->udimm_last_ce_count[1];
+		add0 = new0 - pvt->udimm_last_ce_count[0];
+
+		if (add2 < 0)
+			add2 += 0x7fff;
+		pvt->udimm_ce_count[2] += add2;
+
+		if (add1 < 0)
+			add1 += 0x7fff;
+		pvt->udimm_ce_count[1] += add1;
+
+		if (add0 < 0)
+			add0 += 0x7fff;
+		pvt->udimm_ce_count[0] += add0;
+
+		if (add0 | add1 | add2)
+			i7core_printk(KERN_ERR, "New Corrected error(s): "
+				      "dimm0: +%d, dimm1: +%d, dimm2 +%d\n",
+				      add0, add1, add2);
+	} else
+		pvt->ce_count_available = 1;
+
+	/* Store the new values */
+	pvt->udimm_last_ce_count[2] = new2;
+	pvt->udimm_last_ce_count[1] = new1;
+	pvt->udimm_last_ce_count[0] = new0;
+}
+
+/*
+ * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32
+ * Architectures Software Developer’s Manual Volume 3B.
+ * Nehalem are defined as family 0x06, model 0x1a
+ *
+ * The MCA registers used here are the following ones:
+ *     struct mce field	MCA Register
+ *     m->status	MSR_IA32_MC8_STATUS
+ *     m->addr		MSR_IA32_MC8_ADDR
+ *     m->misc		MSR_IA32_MC8_MISC
+ * In the case of Nehalem, the error information is masked at .status and .misc
+ * fields
+ */
+static void i7core_mce_output_error(struct mem_ctl_info *mci,
+				    struct mce *m)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	char *type, *optype, *err, *msg;
+	unsigned long error = m->status & 0x1ff0000l;
+	u32 optypenum = (m->status >> 4) & 0x07;
+	u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+	u32 dimm = (m->misc >> 16) & 0x3;
+	u32 channel = (m->misc >> 18) & 0x3;
+	u32 syndrome = m->misc >> 32;
+	u32 errnum = find_first_bit(&error, 32);
+	int csrow;
+
+	if (m->mcgstatus & 1)
+		type = "FATAL";
+	else
+		type = "NON_FATAL";
+
+	switch (optypenum) {
+	case 0:
+		optype = "generic undef request";
+		break;
+	case 1:
+		optype = "read error";
+		break;
+	case 2:
+		optype = "write error";
+		break;
+	case 3:
+		optype = "addr/cmd error";
+		break;
+	case 4:
+		optype = "scrubbing error";
+		break;
+	default:
+		optype = "reserved";
+		break;
+	}
+
+	switch (errnum) {
+	case 16:
+		err = "read ECC error";
+		break;
+	case 17:
+		err = "RAS ECC error";
+		break;
+	case 18:
+		err = "write parity error";
+		break;
+	case 19:
+		err = "redundacy loss";
+		break;
+	case 20:
+		err = "reserved";
+		break;
+	case 21:
+		err = "memory range error";
+		break;
+	case 22:
+		err = "RTID out of range";
+		break;
+	case 23:
+		err = "address parity error";
+		break;
+	case 24:
+		err = "byte enable parity error";
+		break;
+	default:
+		err = "unknown";
+	}
+
+	/* FIXME: should convert addr into bank and rank information */
+	msg = kasprintf(GFP_ATOMIC,
+		"%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, "
+		"syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n",
+		type, (long long) m->addr, m->cpu, dimm, channel,
+		syndrome, core_err_cnt, (long long)m->status,
+		(long long)m->misc, optype, err);
+
+	debugf0("%s", msg);
+
+	csrow = pvt->csrow_map[channel][dimm];
+
+	/* Call the helper to output message */
+	if (m->mcgstatus & 1)
+		edac_mc_handle_fbd_ue(mci, csrow, 0,
+				0 /* FIXME: should be channel here */, msg);
+	else if (!pvt->is_registered)
+		edac_mc_handle_fbd_ce(mci, csrow,
+				0 /* FIXME: should be channel here */, msg);
+
+	kfree(msg);
+}
+
+/*
+ *	i7core_check_error	Retrieve and process errors reported by the
+ *				hardware. Called by the Core module.
+ */
+static void i7core_check_error(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	int i;
+	unsigned count = 0;
+	struct mce *m;
+
+	/*
+	 * MCE first step: Copy all mce errors into a temporary buffer
+	 * We use a double buffering here, to reduce the risk of
+	 * loosing an error.
+	 */
+	smp_rmb();
+	count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in)
+		% MCE_LOG_LEN;
+	if (!count)
+		goto check_ce_error;
+
+	m = pvt->mce_outentry;
+	if (pvt->mce_in + count > MCE_LOG_LEN) {
+		unsigned l = MCE_LOG_LEN - pvt->mce_in;
+
+		memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l);
+		smp_wmb();
+		pvt->mce_in = 0;
+		count -= l;
+		m += l;
+	}
+	memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count);
+	smp_wmb();
+	pvt->mce_in += count;
+
+	smp_rmb();
+	if (pvt->mce_overrun) {
+		i7core_printk(KERN_ERR, "Lost %d memory errors\n",
+			      pvt->mce_overrun);
+		smp_wmb();
+		pvt->mce_overrun = 0;
+	}
+
+	/*
+	 * MCE second step: parse errors and display
+	 */
+	for (i = 0; i < count; i++)
+		i7core_mce_output_error(mci, &pvt->mce_outentry[i]);
+
+	/*
+	 * Now, let's increment CE error counts
+	 */
+check_ce_error:
+	if (!pvt->is_registered)
+		i7core_udimm_check_mc_ecc_err(mci);
+	else
+		i7core_rdimm_check_mc_ecc_err(mci);
+}
+
+/*
+ * i7core_mce_check_error	Replicates mcelog routine to get errors
+ *				This routine simply queues mcelog errors, and
+ *				return. The error itself should be handled later
+ *				by i7core_check_error.
+ * WARNING: As this routine should be called at NMI time, extra care should
+ * be taken to avoid deadlocks, and to be as fast as possible.
+ */
+static int i7core_mce_check_error(void *priv, struct mce *mce)
+{
+	struct mem_ctl_info *mci = priv;
+	struct i7core_pvt *pvt = mci->pvt_info;
+
+	/*
+	 * Just let mcelog handle it if the error is
+	 * outside the memory controller
+	 */
+	if (((mce->status & 0xffff) >> 7) != 1)
+		return 0;
+
+	/* Bank 8 registers are the only ones that we know how to handle */
+	if (mce->bank != 8)
+		return 0;
+
+#ifdef CONFIG_SMP
+	/* Only handle if it is the right mc controller */
+	if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket)
+		return 0;
+#endif
+
+	smp_rmb();
+	if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
+		smp_wmb();
+		pvt->mce_overrun++;
+		return 0;
+	}
+
+	/* Copy memory error at the ringbuffer */
+	memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce));
+	smp_wmb();
+	pvt->mce_out = (pvt->mce_out + 1) % MCE_LOG_LEN;
+
+	/* Handle fatal errors immediately */
+	if (mce->mcgstatus & 1)
+		i7core_check_error(mci);
+
+	/* Advice mcelog that the error were handled */
+	return 1;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev,
+			       int num_channels, int num_csrows)
+{
+	struct mem_ctl_info *mci;
+	struct i7core_pvt *pvt;
+	int csrow = 0;
+	int rc;
+
+	/* allocate a new MC control structure */
+	mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels,
+			    i7core_dev->socket);
+	if (unlikely(!mci))
+		return -ENOMEM;
+
+	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+	/* record ptr to the generic device */
+	mci->dev = &i7core_dev->pdev[0]->dev;
+
+	pvt = mci->pvt_info;
+	memset(pvt, 0, sizeof(*pvt));
+
+	/*
+	 * FIXME: how to handle RDDR3 at MCI level? It is possible to have
+	 * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
+	 * memory channels
+	 */
+	mci->mtype_cap = MEM_FLAG_DDR3;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE;
+	mci->edac_cap = EDAC_FLAG_NONE;
+	mci->mod_name = "i7core_edac.c";
+	mci->mod_ver = I7CORE_REVISION;
+	mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d",
+				  i7core_dev->socket);
+	mci->dev_name = pci_name(i7core_dev->pdev[0]);
+	mci->ctl_page_to_phys = NULL;
+	mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs;
+	/* Set the function pointer to an actual operation function */
+	mci->edac_check = i7core_check_error;
+
+	/* Store pci devices at mci for faster access */
+	rc = mci_bind_devs(mci, i7core_dev);
+	if (unlikely(rc < 0))
+		goto fail;
+
+	/* Get dimm basic config */
+	get_dimm_config(mci, &csrow);
+
+	/* add this new MC control structure to EDAC's list of MCs */
+	if (unlikely(edac_mc_add_mc(mci))) {
+		debugf0("MC: " __FILE__
+			": %s(): failed edac_mc_add_mc()\n", __func__);
+		/* FIXME: perhaps some code should go here that disables error
+		 * reporting if we just enabled it
+		 */
+
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	/* allocating generic PCI control info */
+	i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev,
+						 EDAC_MOD_STR);
+	if (unlikely(!i7core_pci)) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
+	/* Default error mask is any memory */
+	pvt->inject.channel = 0;
+	pvt->inject.dimm = -1;
+	pvt->inject.rank = -1;
+	pvt->inject.bank = -1;
+	pvt->inject.page = -1;
+	pvt->inject.col = -1;
+
+	/* Registers on edac_mce in order to receive memory errors */
+	pvt->edac_mce.priv = mci;
+	pvt->edac_mce.check_error = i7core_mce_check_error;
+
+	rc = edac_mce_register(&pvt->edac_mce);
+	if (unlikely(rc < 0)) {
+		debugf0("MC: " __FILE__
+			": %s(): failed edac_mce_register()\n", __func__);
+	}
+
+fail:
+	if (rc < 0)
+		edac_mc_free(mci);
+	return rc;
+}
+
+/*
+ *	i7core_probe	Probe for ONE instance of device to see if it is
+ *			present.
+ *	return:
+ *		0 for FOUND a device
+ *		< 0 for error code
+ */
+static int __devinit i7core_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *id)
+{
+	int dev_idx = id->driver_data;
+	int rc;
+	struct i7core_dev *i7core_dev;
+
+	/*
+	 * All memory controllers are allocated at the first pass.
+	 */
+	if (unlikely(dev_idx >= 1))
+		return -EINVAL;
+
+	/* get the pci devices we want to reserve for our use */
+	mutex_lock(&i7core_edac_lock);
+
+	rc = i7core_get_devices(pci_dev_table);
+	if (unlikely(rc < 0))
+		goto fail0;
+
+	list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+		int channels;
+		int csrows;
+
+		/* Check the number of active and not disabled channels */
+		rc = i7core_get_active_channels(i7core_dev->socket,
+						&channels, &csrows);
+		if (unlikely(rc < 0))
+			goto fail1;
+
+		rc = i7core_register_mci(i7core_dev, channels, csrows);
+		if (unlikely(rc < 0))
+			goto fail1;
+	}
+
+	i7core_printk(KERN_INFO, "Driver loaded.\n");
+
+	mutex_unlock(&i7core_edac_lock);
+	return 0;
+
+fail1:
+	i7core_put_all_devices();
+fail0:
+	mutex_unlock(&i7core_edac_lock);
+	return rc;
+}
+
+/*
+ *	i7core_remove	destructor for one instance of device
+ *
+ */
+static void __devexit i7core_remove(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+	struct i7core_dev *i7core_dev, *tmp;
+
+	debugf0(__FILE__ ": %s()\n", __func__);
+
+	if (i7core_pci)
+		edac_pci_release_generic_ctl(i7core_pci);
+
+	/*
+	 * we have a trouble here: pdev value for removal will be wrong, since
+	 * it will point to the X58 register used to detect that the machine
+	 * is a Nehalem or upper design. However, due to the way several PCI
+	 * devices are grouped together to provide MC functionality, we need
+	 * to use a different method for releasing the devices
+	 */
+
+	mutex_lock(&i7core_edac_lock);
+	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
+		mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
+		if (mci) {
+			struct i7core_pvt *pvt = mci->pvt_info;
+
+			i7core_dev = pvt->i7core_dev;
+			edac_mce_unregister(&pvt->edac_mce);
+			kfree(mci->ctl_name);
+			edac_mc_free(mci);
+			i7core_put_devices(i7core_dev);
+		} else {
+			i7core_printk(KERN_ERR,
+				      "Couldn't find mci for socket %d\n",
+				      i7core_dev->socket);
+		}
+	}
+	mutex_unlock(&i7core_edac_lock);
+}
+
+MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
+
+/*
+ *	i7core_driver	pci_driver structure for this module
+ *
+ */
+static struct pci_driver i7core_driver = {
+	.name     = "i7core_edac",
+	.probe    = i7core_probe,
+	.remove   = __devexit_p(i7core_remove),
+	.id_table = i7core_pci_tbl,
+};
+
+/*
+ *	i7core_init		Module entry function
+ *			Try to initialize this module for its devices
+ */
+static int __init i7core_init(void)
+{
+	int pci_rc;
+
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
+	opstate_init();
+
+	i7core_xeon_pci_fixup(pci_dev_table);
+
+	pci_rc = pci_register_driver(&i7core_driver);
+
+	if (pci_rc >= 0)
+		return 0;
+
+	i7core_printk(KERN_ERR, "Failed to register device with error %d.\n",
+		      pci_rc);
+
+	return pci_rc;
+}
+
+/*
+ *	i7core_exit()	Module exit function
+ *			Unregister the driver
+ */
+static void __exit i7core_exit(void)
+{
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	pci_unregister_driver(&i7core_driver);
+}
+
+module_init(i7core_init);
+module_exit(i7core_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
+		   I7CORE_REVISION);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");

+ 1 - 3
drivers/infiniband/hw/qib/qib_fs.c

@@ -542,10 +542,8 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent)
 	list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) {
 		spin_unlock_irqrestore(&qib_devs_lock, flags);
 		ret = add_cntr_files(sb, dd);
-		if (ret) {
-			deactivate_super(sb);
+		if (ret)
 			goto bail;
-		}
 		spin_lock_irqsave(&qib_devs_lock, flags);
 	}
 

+ 2 - 1
drivers/input/serio/Kconfig

@@ -21,7 +21,8 @@ if SERIO
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
-	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN
+	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
+		   (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
 	help
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,

+ 0 - 1
drivers/input/tablet/wacom_sys.c

@@ -507,7 +507,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 			goto fail3;
 	}
 
-	input_dev->name = wacom_wac->name;
 	input_dev->name = wacom_wac->name;
 	input_dev->dev.parent = &intf->dev;
 	input_dev->open = wacom_open;

+ 59 - 14
drivers/input/tablet/wacom_wac.c

@@ -300,7 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 		case 0x823: /* Intuos3 Grip Pen */
 		case 0x813: /* Intuos3 Classic Pen */
 		case 0x885: /* Intuos3 Marker Pen */
-		case 0x802: /* Intuos4 Grip Pen Eraser */
+		case 0x802: /* Intuos4 General Pen */
 		case 0x804: /* Intuos4 Marker Pen */
 		case 0x40802: /* Intuos4 Classic Pen */
 		case 0x022:
@@ -335,7 +335,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 		case 0x81b: /* Intuos3 Classic Pen Eraser */
 		case 0x91b: /* Intuos3 Airbrush Eraser */
 		case 0x80c: /* Intuos4 Marker Pen Eraser */
-		case 0x80a: /* Intuos4 Grip Pen Eraser */
+		case 0x80a: /* Intuos4 General Pen Eraser */
 		case 0x4080a: /* Intuos4 Classic Pen Eraser */
 		case 0x90a: /* Intuos4 Airbrush Eraser */
 			wacom->tool[idx] = BTN_TOOL_RUBBER;
@@ -356,6 +356,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 		return 1;
 	}
 
+	/* older I4 styli don't work with new Cintiqs */
+	if (!((wacom->id[idx] >> 20) & 0x01) &&
+			(features->type == WACOM_21UX2))
+		return 1;
+
 	/* Exit report */
 	if ((data[1] & 0xfe) == 0x80) {
 		/*
@@ -474,21 +479,43 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 				input_report_abs(input, ABS_MISC, 0);
 			}
 		} else {
-			input_report_key(input, BTN_0, (data[5] & 0x01));
-			input_report_key(input, BTN_1, (data[5] & 0x02));
-			input_report_key(input, BTN_2, (data[5] & 0x04));
-			input_report_key(input, BTN_3, (data[5] & 0x08));
-			input_report_key(input, BTN_4, (data[6] & 0x01));
-			input_report_key(input, BTN_5, (data[6] & 0x02));
-			input_report_key(input, BTN_6, (data[6] & 0x04));
-			input_report_key(input, BTN_7, (data[6] & 0x08));
-			input_report_key(input, BTN_8, (data[5] & 0x10));
-			input_report_key(input, BTN_9, (data[6] & 0x10));
+			if (features->type == WACOM_21UX2) {
+				input_report_key(input, BTN_0, (data[5] & 0x01));
+				input_report_key(input, BTN_1, (data[6] & 0x01));
+				input_report_key(input, BTN_2, (data[6] & 0x02));
+				input_report_key(input, BTN_3, (data[6] & 0x04));
+				input_report_key(input, BTN_4, (data[6] & 0x08));
+				input_report_key(input, BTN_5, (data[6] & 0x10));
+				input_report_key(input, BTN_6, (data[6] & 0x20));
+				input_report_key(input, BTN_7, (data[6] & 0x40));
+				input_report_key(input, BTN_8, (data[6] & 0x80));
+				input_report_key(input, BTN_9, (data[7] & 0x01));
+				input_report_key(input, BTN_A, (data[8] & 0x01));
+				input_report_key(input, BTN_B, (data[8] & 0x02));
+				input_report_key(input, BTN_C, (data[8] & 0x04));
+				input_report_key(input, BTN_X, (data[8] & 0x08));
+				input_report_key(input, BTN_Y, (data[8] & 0x10));
+				input_report_key(input, BTN_Z, (data[8] & 0x20));
+				input_report_key(input, BTN_BASE, (data[8] & 0x40));
+				input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+			} else {
+				input_report_key(input, BTN_0, (data[5] & 0x01));
+				input_report_key(input, BTN_1, (data[5] & 0x02));
+				input_report_key(input, BTN_2, (data[5] & 0x04));
+				input_report_key(input, BTN_3, (data[5] & 0x08));
+				input_report_key(input, BTN_4, (data[6] & 0x01));
+				input_report_key(input, BTN_5, (data[6] & 0x02));
+				input_report_key(input, BTN_6, (data[6] & 0x04));
+				input_report_key(input, BTN_7, (data[6] & 0x08));
+				input_report_key(input, BTN_8, (data[5] & 0x10));
+				input_report_key(input, BTN_9, (data[6] & 0x10));
+			}
 			input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
 			input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
 
 			if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
-				data[2] | (data[3] & 0x1f) | data[4]) {
+				data[2] | (data[3] & 0x1f) | data[4] | data[8] |
+				(data[7] & 0x01)) {
 				input_report_key(input, wacom->tool[1], 1);
 				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
 			} else {
@@ -640,7 +667,7 @@ static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
 	if (!idx)
 		input_report_key(input, BTN_TOUCH, 1);
 	input_event(input, EV_MSC, MSC_SERIAL, finger);
-	input_sync(wacom->input);
+	input_sync(input);
 
 	wacom->last_finger = finger;
 }
@@ -826,6 +853,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 	case INTUOS4L:
 	case CINTIQ:
 	case WACOM_BEE:
+	case WACOM_21UX2:
 		sync = wacom_intuos_irq(wacom_wac);
 		break;
 
@@ -921,6 +949,17 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 		__set_bit(BTN_STYLUS2, input_dev->keybit);
 		break;
 
+	case WACOM_21UX2:
+		__set_bit(BTN_A, input_dev->keybit);
+		__set_bit(BTN_B, input_dev->keybit);
+		__set_bit(BTN_C, input_dev->keybit);
+		__set_bit(BTN_X, input_dev->keybit);
+		__set_bit(BTN_Y, input_dev->keybit);
+		__set_bit(BTN_Z, input_dev->keybit);
+		__set_bit(BTN_BASE, input_dev->keybit);
+		__set_bit(BTN_BASE2, input_dev->keybit);
+		/* fall through */
+
 	case WACOM_BEE:
 		__set_bit(BTN_8, input_dev->keybit);
 		__set_bit(BTN_9, input_dev->keybit);
@@ -1105,6 +1144,8 @@ static const struct wacom_features wacom_features_0xBA =
 	{ "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L };
 static const struct wacom_features wacom_features_0xBB =
 	{ "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0xBC =
+	{ "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40840, 25400, 2047, 63, INTUOS4 };
 static const struct wacom_features wacom_features_0x3F =
 	{ "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ };
 static const struct wacom_features wacom_features_0xC5 =
@@ -1113,6 +1154,8 @@ static const struct wacom_features wacom_features_0xC6 =
 	{ "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
 static const struct wacom_features wacom_features_0xC7 =
 	{ "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0xCC =
+	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047, 63, WACOM_21UX2 };
 static const struct wacom_features wacom_features_0x90 =
 	{ "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
 static const struct wacom_features wacom_features_0x93 =
@@ -1185,10 +1228,12 @@ const struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0xB9) },
 	{ USB_DEVICE_WACOM(0xBA) },
 	{ USB_DEVICE_WACOM(0xBB) },
+	{ USB_DEVICE_WACOM(0xBC) },
 	{ USB_DEVICE_WACOM(0x3F) },
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC6) },
 	{ USB_DEVICE_WACOM(0xC7) },
+	{ USB_DEVICE_WACOM(0xCC) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x93) },
 	{ USB_DEVICE_WACOM(0x9A) },

+ 1 - 0
drivers/input/tablet/wacom_wac.h

@@ -50,6 +50,7 @@ enum {
 	INTUOS4S,
 	INTUOS4,
 	INTUOS4L,
+	WACOM_21UX2,
 	CINTIQ,
 	WACOM_BEE,
 	WACOM_MO,

+ 1 - 1
drivers/input/touchscreen/Kconfig

@@ -156,7 +156,7 @@ config TOUCHSCREEN_FUJITSU
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
-	select S3C24XX_ADC
+	select S3C_ADC
 	help
 	  Say Y here if you have the s3c2410 touchscreen.
 

+ 1 - 1
drivers/input/touchscreen/ads7846.c

@@ -1164,7 +1164,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 	ts->reg = regulator_get(&spi->dev, "vcc");
 	if (IS_ERR(ts->reg)) {
 		err = PTR_ERR(ts->reg);
-		dev_err(&spi->dev, "unable to get regulator: %ld\n", err);
+		dev_err(&spi->dev, "unable to get regulator: %d\n", err);
 		goto err_free_gpio;
 	}
 

+ 1 - 1
drivers/input/touchscreen/s3c2410_ts.c

@@ -173,7 +173,7 @@ static irqreturn_t stylus_irq(int irq, void *dev_id)
 	if (down)
 		s3c_adc_start(ts.client, 0, 1 << ts.shift);
 	else
-		dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count);
+		dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
 
 	if (ts.features & FEAT_PEN_IRQ) {
 		/* Clear pen down/up interrupt */

+ 4 - 8
drivers/input/touchscreen/tps6507x-ts.c

@@ -221,7 +221,7 @@ done:
 
 	if (poll) {
 		schd = queue_delayed_work(tsc->wq, &tsc->work,
-					  tsc->poll_period * HZ / 1000);
+					  msecs_to_jiffies(tsc->poll_period));
 		if (schd)
 			tsc->polling = 1;
 		else {
@@ -326,7 +326,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
 		goto err2;
 
 	schd = queue_delayed_work(tsc->wq, &tsc->work,
-				  tsc->poll_period * HZ / 1000);
+				  msecs_to_jiffies(tsc->poll_period));
 
 	if (schd)
 		tsc->polling = 1;
@@ -339,10 +339,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
 	return 0;
 
 err2:
-	cancel_delayed_work(&tsc->work);
-	flush_workqueue(tsc->wq);
+	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
-	tsc->wq = 0;
 	input_free_device(input_dev);
 err1:
 	kfree(tsc);
@@ -360,10 +358,8 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
 	if (!tsc)
 		return 0;
 
-	cancel_delayed_work(&tsc->work);
-	flush_workqueue(tsc->wq);
+	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
-	tsc->wq = 0;
 
 	input_free_device(input_dev);
 

+ 2 - 0
drivers/media/IR/Kconfig

@@ -13,6 +13,7 @@ source "drivers/media/IR/keymaps/Kconfig"
 config IR_NEC_DECODER
 	tristate "Enable IR raw decoder for the NEC protocol"
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 
 	---help---
@@ -22,6 +23,7 @@ config IR_NEC_DECODER
 config IR_RC5_DECODER
 	tristate "Enable IR raw decoder for the RC-5 protocol"
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 
 	---help---

+ 41 - 34
drivers/media/IR/imon.c

@@ -94,6 +94,7 @@ struct imon_context {
 
 	bool display_supported;		/* not all controllers do */
 	bool display_isopen;		/* display port has been opened */
+	bool rf_device;			/* true if iMON 2.4G LT/DT RF device */
 	bool rf_isassociating;		/* RF remote associating */
 	bool dev_present_intf0;		/* USB device presence, interface 0 */
 	bool dev_present_intf1;		/* USB device presence, interface 1 */
@@ -385,7 +386,7 @@ static int display_open(struct inode *inode, struct file *file)
 		err("%s: display port is already open", __func__);
 		retval = -EBUSY;
 	} else {
-		ictx->display_isopen = 1;
+		ictx->display_isopen = true;
 		file->private_data = ictx;
 		dev_dbg(ictx->dev, "display port opened\n");
 	}
@@ -422,7 +423,7 @@ static int display_close(struct inode *inode, struct file *file)
 		err("%s: display is not open", __func__);
 		retval = -EIO;
 	} else {
-		ictx->display_isopen = 0;
+		ictx->display_isopen = false;
 		dev_dbg(ictx->dev, "display port closed\n");
 		if (!ictx->dev_present_intf0) {
 			/*
@@ -491,12 +492,12 @@ static int send_packet(struct imon_context *ictx)
 	}
 
 	init_completion(&ictx->tx.finished);
-	ictx->tx.busy = 1;
+	ictx->tx.busy = true;
 	smp_rmb(); /* ensure later readers know we're busy */
 
 	retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
 	if (retval) {
-		ictx->tx.busy = 0;
+		ictx->tx.busy = false;
 		smp_rmb(); /* ensure later readers know we're not busy */
 		err("%s: error submitting urb(%d)", __func__, retval);
 	} else {
@@ -682,7 +683,7 @@ static ssize_t store_associate_remote(struct device *d,
 		return -ENODEV;
 
 	mutex_lock(&ictx->lock);
-	ictx->rf_isassociating = 1;
+	ictx->rf_isassociating = true;
 	send_associate_24g(ictx);
 	mutex_unlock(&ictx->lock);
 
@@ -950,7 +951,7 @@ static void usb_tx_callback(struct urb *urb)
 	ictx->tx.status = urb->status;
 
 	/* notify waiters that write has finished */
-	ictx->tx.busy = 0;
+	ictx->tx.busy = false;
 	smp_rmb(); /* ensure later readers know we're not busy */
 	complete(&ictx->tx.finished);
 }
@@ -1215,7 +1216,7 @@ static bool imon_mouse_event(struct imon_context *ictx,
 {
 	char rel_x = 0x00, rel_y = 0x00;
 	u8 right_shift = 1;
-	bool mouse_input = 1;
+	bool mouse_input = true;
 	int dir = 0;
 
 	/* newer iMON device PAD or mouse button */
@@ -1246,7 +1247,7 @@ static bool imon_mouse_event(struct imon_context *ictx,
 	} else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
 		dir = -1;
 	} else
-		mouse_input = 0;
+		mouse_input = false;
 
 	if (mouse_input) {
 		dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
@@ -1450,7 +1451,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
 	unsigned char *buf = urb->transfer_buffer;
 	struct device *dev = ictx->dev;
 	u32 kc;
-	bool norelease = 0;
+	bool norelease = false;
 	int i;
 	u64 temp_key;
 	u64 panel_key = 0;
@@ -1465,7 +1466,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
 	idev = ictx->idev;
 
 	/* filter out junk data on the older 0xffdc imon devices */
-	if ((buf[0] == 0xff) && (buf[7] == 0xff))
+	if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
 		return;
 
 	/* Figure out what key was pressed */
@@ -1517,7 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
 	     !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
 		len = 8;
 		imon_pad_to_keys(ictx, buf);
-		norelease = 1;
+		norelease = true;
 	}
 
 	if (debug) {
@@ -1580,7 +1581,7 @@ not_input_data:
 	    (buf[6] == 0x5E && buf[7] == 0xDF))) {	/* DT */
 		dev_warn(dev, "%s: remote associated refid=%02X\n",
 			 __func__, buf[1]);
-		ictx->rf_isassociating = 0;
+		ictx->rf_isassociating = false;
 	}
 }
 
@@ -1790,9 +1791,9 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 	int ifnum = iface_desc->desc.bInterfaceNumber;
 	int num_endpts = iface_desc->desc.bNumEndpoints;
 	int i, ep_dir, ep_type;
-	bool ir_ep_found = 0;
-	bool display_ep_found = 0;
-	bool tx_control = 0;
+	bool ir_ep_found = false;
+	bool display_ep_found = false;
+	bool tx_control = false;
 
 	/*
 	 * Scan the endpoint list and set:
@@ -1808,13 +1809,13 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 		    ep_type == USB_ENDPOINT_XFER_INT) {
 
 			rx_endpoint = ep;
-			ir_ep_found = 1;
+			ir_ep_found = true;
 			dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
 
 		} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
 			   ep_type == USB_ENDPOINT_XFER_INT) {
 			tx_endpoint = ep;
-			display_ep_found = 1;
+			display_ep_found = true;
 			dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
 		}
 	}
@@ -1835,8 +1836,8 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 	 * newer iMON devices that use control urb instead of interrupt
 	 */
 	if (!display_ep_found) {
-		tx_control = 1;
-		display_ep_found = 1;
+		tx_control = true;
+		display_ep_found = true;
 		dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
 			"interface OUT endpoint\n", __func__);
 	}
@@ -1847,7 +1848,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 	 * and without... :\
 	 */
 	if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
-		display_ep_found = 0;
+		display_ep_found = false;
 		dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
 	}
 
@@ -1856,7 +1857,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 	 * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
 	 */
 	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
-		display_ep_found = 0;
+		display_ep_found = false;
 		dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
 	}
 
@@ -1905,9 +1906,10 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
 
 	ictx->dev = dev;
 	ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
-	ictx->dev_present_intf0 = 1;
+	ictx->dev_present_intf0 = true;
 	ictx->rx_urb_intf0 = rx_urb;
 	ictx->tx_urb = tx_urb;
+	ictx->rf_device = false;
 
 	ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
 	ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
@@ -1979,7 +1981,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
 	}
 
 	ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
-	ictx->dev_present_intf1 = 1;
+	ictx->dev_present_intf1 = true;
 	ictx->rx_urb_intf1 = rx_urb;
 
 	ret = -ENODEV;
@@ -2047,6 +2049,12 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
 		dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
 		ictx->display_supported = false;
 		break;
+	/* iMON 2.4G LT (usb stick), no display, iMON RF */
+	case 0x4e:
+		dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
+		ictx->display_supported = false;
+		ictx->rf_device = true;
+		break;
 	/* iMON VFD, no IR (does have vol knob tho) */
 	case 0x35:
 		dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
@@ -2197,15 +2205,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
 			goto fail;
 		}
 
-		if (product == 0xffdc) {
-			/* RF products *also* use 0xffdc... sigh... */
-			sysfs_err = sysfs_create_group(&interface->dev.kobj,
-						       &imon_rf_attribute_group);
-			if (sysfs_err)
-				err("%s: Could not create RF sysfs entries(%d)",
-				    __func__, sysfs_err);
-		}
-
 	} else {
 	/* this is the secondary interface on the device */
 		ictx = imon_init_intf1(interface, first_if_ctx);
@@ -2233,6 +2232,14 @@ static int __devinit imon_probe(struct usb_interface *interface,
 
 		imon_set_display_type(ictx, interface);
 
+		if (product == 0xffdc && ictx->rf_device) {
+			sysfs_err = sysfs_create_group(&interface->dev.kobj,
+						       &imon_rf_attribute_group);
+			if (sysfs_err)
+				err("%s: Could not create RF sysfs entries(%d)",
+				    __func__, sysfs_err);
+		}
+
 		if (ictx->display_supported)
 			imon_init_display(ictx, interface);
 	}
@@ -2297,7 +2304,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
 	}
 
 	if (ifnum == 0) {
-		ictx->dev_present_intf0 = 0;
+		ictx->dev_present_intf0 = false;
 		usb_kill_urb(ictx->rx_urb_intf0);
 		input_unregister_device(ictx->idev);
 		if (ictx->display_supported) {
@@ -2307,7 +2314,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
 				usb_deregister_dev(interface, &imon_vfd_class);
 		}
 	} else {
-		ictx->dev_present_intf1 = 0;
+		ictx->dev_present_intf1 = false;
 		usb_kill_urb(ictx->rx_urb_intf1);
 		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
 			input_unregister_device(ictx->touch);

+ 10 - 7
drivers/media/IR/ir-keytable.c

@@ -490,11 +490,12 @@ int __ir_input_register(struct input_dev *input_dev,
 	if (rc < 0)
 		goto out_table;
 
-	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
-		rc = ir_raw_event_register(input_dev);
-		if (rc < 0)
-			goto out_event;
-	}
+	if (ir_dev->props)
+		if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
+			rc = ir_raw_event_register(input_dev);
+			if (rc < 0)
+				goto out_event;
+		}
 
 	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
 		   driver_name, rc_tab->name);
@@ -530,8 +531,10 @@ void ir_input_unregister(struct input_dev *input_dev)
 	IR_dprintk(1, "Freed keycode table\n");
 
 	del_timer_sync(&ir_dev->timer_keyup);
-	if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
-		ir_raw_event_unregister(input_dev);
+	if (ir_dev->props)
+		if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
+			ir_raw_event_unregister(input_dev);
+
 	rc_tab = &ir_dev->rc_tab;
 	rc_tab->size = 0;
 	kfree(rc_tab->scan);

+ 4 - 3
drivers/media/IR/ir-sysfs.c

@@ -221,9 +221,10 @@ int ir_register_class(struct input_dev *input_dev)
 	if (unlikely(devno < 0))
 		return devno;
 
-	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
-		ir_dev->dev.type = &rc_dev_type;
-	else
+	if (ir_dev->props) {
+		if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+			ir_dev->dev.type = &rc_dev_type;
+	} else
 		ir_dev->dev.type = &ir_raw_dev_type;
 
 	ir_dev->dev.class = &ir_input_class;

+ 2 - 1
drivers/media/IR/keymaps/Makefile

@@ -6,7 +6,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-avermedia.o \
 			rc-avermedia-cardbus.o \
 			rc-avermedia-dvbt.o \
-			rc-avermedia-m135a-rm-jx.o \
+			rc-avermedia-m135a.o \
+			rc-avermedia-m733a-rm-k6.o \
 			rc-avertv-303.o \
 			rc-behold.o \
 			rc-behold-columbus.o \

+ 0 - 90
drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c

@@ -1,90 +0,0 @@
-/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.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.
- */
-
-#include <media/rc-map.h>
-
-/*
- * Avermedia M135A with IR model RM-JX
- * The same codes exist on both Positivo (BR) and original IR
- * Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-static struct ir_scancode avermedia_m135a_rm_jx[] = {
-	{ 0x0200, KEY_POWER2 },
-	{ 0x022e, KEY_DOT },		/* '.' */
-	{ 0x0201, KEY_MODE },		/* TV/FM or SOURCE */
-
-	{ 0x0205, KEY_1 },
-	{ 0x0206, KEY_2 },
-	{ 0x0207, KEY_3 },
-	{ 0x0209, KEY_4 },
-	{ 0x020a, KEY_5 },
-	{ 0x020b, KEY_6 },
-	{ 0x020d, KEY_7 },
-	{ 0x020e, KEY_8 },
-	{ 0x020f, KEY_9 },
-	{ 0x0211, KEY_0 },
-
-	{ 0x0213, KEY_RIGHT },		/* -> or L */
-	{ 0x0212, KEY_LEFT },		/* <- or R */
-
-	{ 0x0217, KEY_SLEEP },		/* Capturar Imagem or Snapshot */
-	{ 0x0210, KEY_SHUFFLE },	/* Amostra or 16 chan prev */
-
-	{ 0x0303, KEY_CHANNELUP },
-	{ 0x0302, KEY_CHANNELDOWN },
-	{ 0x021f, KEY_VOLUMEUP },
-	{ 0x021e, KEY_VOLUMEDOWN },
-	{ 0x020c, KEY_ENTER },		/* Full Screen */
-
-	{ 0x0214, KEY_MUTE },
-	{ 0x0208, KEY_AUDIO },
-
-	{ 0x0203, KEY_TEXT },		/* Teletext */
-	{ 0x0204, KEY_EPG },
-	{ 0x022b, KEY_TV2 },		/* TV2 or PIP */
-
-	{ 0x021d, KEY_RED },
-	{ 0x021c, KEY_YELLOW },
-	{ 0x0301, KEY_GREEN },
-	{ 0x0300, KEY_BLUE },
-
-	{ 0x021a, KEY_PLAYPAUSE },
-	{ 0x0219, KEY_RECORD },
-	{ 0x0218, KEY_PLAY },
-	{ 0x021b, KEY_STOP },
-};
-
-static struct rc_keymap avermedia_m135a_rm_jx_map = {
-	.map = {
-		.scan    = avermedia_m135a_rm_jx,
-		.size    = ARRAY_SIZE(avermedia_m135a_rm_jx),
-		.ir_type = IR_TYPE_NEC,
-		.name    = RC_MAP_AVERMEDIA_M135A_RM_JX,
-	}
-};
-
-static int __init init_rc_map_avermedia_m135a_rm_jx(void)
-{
-	return ir_register_map(&avermedia_m135a_rm_jx_map);
-}
-
-static void __exit exit_rc_map_avermedia_m135a_rm_jx(void)
-{
-	ir_unregister_map(&avermedia_m135a_rm_jx_map);
-}
-
-module_init(init_rc_map_avermedia_m135a_rm_jx)
-module_exit(exit_rc_map_avermedia_m135a_rm_jx)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");

+ 147 - 0
drivers/media/IR/keymaps/rc-avermedia-m135a.c

@@ -0,0 +1,147 @@
+/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * 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 <media/rc-map.h>
+
+/*
+ * Avermedia M135A with RM-JX and RM-K6 remote controls
+ *
+ * On Avermedia M135A with IR model RM-JX, the same codes exist on both
+ * Positivo (BR) and original IR, initial version and remote control codes
+ * added by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Positivo also ships Avermedia M135A with model RM-K6, extra control
+ * codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct ir_scancode avermedia_m135a[] = {
+	/* RM-JX */
+	{ 0x0200, KEY_POWER2 },
+	{ 0x022e, KEY_DOT },		/* '.' */
+	{ 0x0201, KEY_MODE },		/* TV/FM or SOURCE */
+
+	{ 0x0205, KEY_1 },
+	{ 0x0206, KEY_2 },
+	{ 0x0207, KEY_3 },
+	{ 0x0209, KEY_4 },
+	{ 0x020a, KEY_5 },
+	{ 0x020b, KEY_6 },
+	{ 0x020d, KEY_7 },
+	{ 0x020e, KEY_8 },
+	{ 0x020f, KEY_9 },
+	{ 0x0211, KEY_0 },
+
+	{ 0x0213, KEY_RIGHT },		/* -> or L */
+	{ 0x0212, KEY_LEFT },		/* <- or R */
+
+	{ 0x0217, KEY_SLEEP },		/* Capturar Imagem or Snapshot */
+	{ 0x0210, KEY_SHUFFLE },	/* Amostra or 16 chan prev */
+
+	{ 0x0303, KEY_CHANNELUP },
+	{ 0x0302, KEY_CHANNELDOWN },
+	{ 0x021f, KEY_VOLUMEUP },
+	{ 0x021e, KEY_VOLUMEDOWN },
+	{ 0x020c, KEY_ENTER },		/* Full Screen */
+
+	{ 0x0214, KEY_MUTE },
+	{ 0x0208, KEY_AUDIO },
+
+	{ 0x0203, KEY_TEXT },		/* Teletext */
+	{ 0x0204, KEY_EPG },
+	{ 0x022b, KEY_TV2 },		/* TV2 or PIP */
+
+	{ 0x021d, KEY_RED },
+	{ 0x021c, KEY_YELLOW },
+	{ 0x0301, KEY_GREEN },
+	{ 0x0300, KEY_BLUE },
+
+	{ 0x021a, KEY_PLAYPAUSE },
+	{ 0x0219, KEY_RECORD },
+	{ 0x0218, KEY_PLAY },
+	{ 0x021b, KEY_STOP },
+
+	/* RM-K6 */
+	{ 0x0401, KEY_POWER2 },
+	{ 0x0406, KEY_MUTE },
+	{ 0x0408, KEY_MODE },     /* TV/FM */
+
+	{ 0x0409, KEY_1 },
+	{ 0x040a, KEY_2 },
+	{ 0x040b, KEY_3 },
+	{ 0x040c, KEY_4 },
+	{ 0x040d, KEY_5 },
+	{ 0x040e, KEY_6 },
+	{ 0x040f, KEY_7 },
+	{ 0x0410, KEY_8 },
+	{ 0x0411, KEY_9 },
+	{ 0x044c, KEY_DOT },      /* '.' */
+	{ 0x0412, KEY_0 },
+	{ 0x0407, KEY_REFRESH },  /* Refresh/Reload */
+
+	{ 0x0413, KEY_AUDIO },
+	{ 0x0440, KEY_SCREEN },   /* Full Screen toggle */
+	{ 0x0441, KEY_HOME },
+	{ 0x0442, KEY_BACK },
+	{ 0x0447, KEY_UP },
+	{ 0x0448, KEY_DOWN },
+	{ 0x0449, KEY_LEFT },
+	{ 0x044a, KEY_RIGHT },
+	{ 0x044b, KEY_OK },
+	{ 0x0404, KEY_VOLUMEUP },
+	{ 0x0405, KEY_VOLUMEDOWN },
+	{ 0x0402, KEY_CHANNELUP },
+	{ 0x0403, KEY_CHANNELDOWN },
+
+	{ 0x0443, KEY_RED },
+	{ 0x0444, KEY_GREEN },
+	{ 0x0445, KEY_YELLOW },
+	{ 0x0446, KEY_BLUE },
+
+	{ 0x0414, KEY_TEXT },
+	{ 0x0415, KEY_EPG },
+	{ 0x041a, KEY_TV2 },      /* PIP */
+	{ 0x041b, KEY_MHP },      /* Snapshot */
+
+	{ 0x0417, KEY_RECORD },
+	{ 0x0416, KEY_PLAYPAUSE },
+	{ 0x0418, KEY_STOP },
+	{ 0x0419, KEY_PAUSE },
+
+	{ 0x041f, KEY_PREVIOUS },
+	{ 0x041c, KEY_REWIND },
+	{ 0x041d, KEY_FORWARD },
+	{ 0x041e, KEY_NEXT },
+};
+
+static struct rc_keymap avermedia_m135a_map = {
+	.map = {
+		.scan    = avermedia_m135a,
+		.size    = ARRAY_SIZE(avermedia_m135a),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_AVERMEDIA_M135A,
+	}
+};
+
+static int __init init_rc_map_avermedia_m135a(void)
+{
+	return ir_register_map(&avermedia_m135a_map);
+}
+
+static void __exit exit_rc_map_avermedia_m135a(void)
+{
+	ir_unregister_map(&avermedia_m135a_map);
+}
+
+module_init(init_rc_map_avermedia_m135a)
+module_exit(exit_rc_map_avermedia_m135a)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");

+ 95 - 0
drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c

@@ -0,0 +1,95 @@
+/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller
+ *
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * 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 <media/rc-map.h>
+
+/*
+ * Avermedia M733A with IR model RM-K6
+ * This is the stock remote controller used with Positivo machines with M733A
+ * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct ir_scancode avermedia_m733a_rm_k6[] = {
+	{ 0x0401, KEY_POWER2 },
+	{ 0x0406, KEY_MUTE },
+	{ 0x0408, KEY_MODE },     /* TV/FM */
+
+	{ 0x0409, KEY_1 },
+	{ 0x040a, KEY_2 },
+	{ 0x040b, KEY_3 },
+	{ 0x040c, KEY_4 },
+	{ 0x040d, KEY_5 },
+	{ 0x040e, KEY_6 },
+	{ 0x040f, KEY_7 },
+	{ 0x0410, KEY_8 },
+	{ 0x0411, KEY_9 },
+	{ 0x044c, KEY_DOT },      /* '.' */
+	{ 0x0412, KEY_0 },
+	{ 0x0407, KEY_REFRESH },  /* Refresh/Reload */
+
+	{ 0x0413, KEY_AUDIO },
+	{ 0x0440, KEY_SCREEN },   /* Full Screen toggle */
+	{ 0x0441, KEY_HOME },
+	{ 0x0442, KEY_BACK },
+	{ 0x0447, KEY_UP },
+	{ 0x0448, KEY_DOWN },
+	{ 0x0449, KEY_LEFT },
+	{ 0x044a, KEY_RIGHT },
+	{ 0x044b, KEY_OK },
+	{ 0x0404, KEY_VOLUMEUP },
+	{ 0x0405, KEY_VOLUMEDOWN },
+	{ 0x0402, KEY_CHANNELUP },
+	{ 0x0403, KEY_CHANNELDOWN },
+
+	{ 0x0443, KEY_RED },
+	{ 0x0444, KEY_GREEN },
+	{ 0x0445, KEY_YELLOW },
+	{ 0x0446, KEY_BLUE },
+
+	{ 0x0414, KEY_TEXT },
+	{ 0x0415, KEY_EPG },
+	{ 0x041a, KEY_TV2 },      /* PIP */
+	{ 0x041b, KEY_MHP },      /* Snapshot */
+
+	{ 0x0417, KEY_RECORD },
+	{ 0x0416, KEY_PLAYPAUSE },
+	{ 0x0418, KEY_STOP },
+	{ 0x0419, KEY_PAUSE },
+
+	{ 0x041f, KEY_PREVIOUS },
+	{ 0x041c, KEY_REWIND },
+	{ 0x041d, KEY_FORWARD },
+	{ 0x041e, KEY_NEXT },
+};
+
+static struct rc_keymap avermedia_m733a_rm_k6_map = {
+	.map = {
+		.scan    = avermedia_m733a_rm_k6,
+		.size    = ARRAY_SIZE(avermedia_m733a_rm_k6),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_AVERMEDIA_M733A_RM_K6,
+	}
+};
+
+static int __init init_rc_map_avermedia_m733a_rm_k6(void)
+{
+	return ir_register_map(&avermedia_m733a_rm_k6_map);
+}
+
+static void __exit exit_rc_map_avermedia_m733a_rm_k6(void)
+{
+	ir_unregister_map(&avermedia_m733a_rm_k6_map);
+}
+
+module_init(init_rc_map_avermedia_m733a_rm_k6)
+module_exit(exit_rc_map_avermedia_m733a_rm_k6)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");

+ 1 - 1
drivers/media/dvb/dm1105/dm1105.c

@@ -594,7 +594,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id)
 int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
 {
 	struct input_dev *input_dev;
-	char *ir_codes = NULL;
+	char *ir_codes = RC_MAP_DM1105_NEC;
 	int err = -ENOMEM;
 
 	input_dev = input_allocate_device();

+ 11 - 1
drivers/media/dvb/dvb-core/dvb_net.c

@@ -351,6 +351,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 	const u8 *ts, *ts_end, *from_where = NULL;
 	u8 ts_remain = 0, how_much = 0, new_ts = 1;
 	struct ethhdr *ethh = NULL;
+	bool error = false;
 
 #ifdef ULE_DEBUG
 	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
@@ -460,10 +461,16 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 
 						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 						if (priv->ule_skb) {
-							dev_kfree_skb( priv->ule_skb );
+							error = true;
+							dev_kfree_skb(priv->ule_skb);
+						}
+
+						if (error || priv->ule_sndu_remain) {
 							dev->stats.rx_errors++;
 							dev->stats.rx_frame_errors++;
+							error = false;
 						}
+
 						reset_ule(priv);
 						priv->need_pusi = 1;
 						continue;
@@ -535,6 +542,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				from_where += 2;
 			}
 
+			priv->ule_sndu_remain = priv->ule_sndu_len + 2;
 			/*
 			 * State of current TS:
 			 *   ts_remain (remaining bytes in the current TS cell)
@@ -544,6 +552,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 			 */
 			switch (ts_remain) {
 				case 1:
+					priv->ule_sndu_remain--;
 					priv->ule_sndu_type = from_where[0] << 8;
 					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
 					ts_remain -= 1; from_where += 1;
@@ -557,6 +566,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				default: /* complete ULE header is present in current TS. */
 					/* Extract ULE type field. */
 					if (priv->ule_sndu_type_1) {
+						priv->ule_sndu_type_1 = 0;
 						priv->ule_sndu_type |= from_where[0];
 						from_where += 1; /* points to payload start. */
 						ts_remain -= 1;

+ 3 - 1
drivers/media/dvb/dvb-usb/Kconfig

@@ -76,6 +76,7 @@ config DVB_USB_DIB0700
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
@@ -134,6 +135,7 @@ config DVB_USB_M920X
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_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
@@ -264,7 +266,7 @@ config DVB_USB_DW2102
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
-	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_MT312 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
 	select DVB_DS3000 if !DVB_FE_CUSTOMISE

+ 3 - 1
drivers/media/dvb/dvb-usb/cxusb.c

@@ -1026,8 +1026,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
 	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 
 	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-				 &cxusb_dualdig4_rev2_config) < 0)
+				     &cxusb_dualdig4_rev2_config) < 0) {
+		printk(KERN_WARNING "Unable to enumerate dib7000p\n");
 		return -ENODEV;
+	}
 
 	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
 			      &cxusb_dualdig4_rev2_config);

+ 1 - 0
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

@@ -198,6 +198,7 @@
 #define USB_PID_AVERMEDIA_A850				0x850a
 #define USB_PID_AVERMEDIA_A805				0xa805
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
+#define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058

+ 89 - 6
drivers/media/dvb/dvb-usb/ttusb2.c

@@ -29,6 +29,8 @@
 
 #include "tda826x.h"
 #include "tda10086.h"
+#include "tda1002x.h"
+#include "tda827x.h"
 #include "lnbp21.h"
 
 /* debug */
@@ -150,7 +152,17 @@ static struct tda10086_config tda10086_config = {
 	.xtal_freq = TDA10086_XTAL_16M,
 };
 
-static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
+static struct tda10023_config tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 0,
+	.xtal = 16000000,
+	.pll_m = 11,
+	.pll_p = 3,
+	.pll_n = 1,
+	.deltaf = 0xa511,
+};
+
+static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
 {
 	if (usb_set_interface(adap->dev->udev,0,3) < 0)
 		err("set interface to alts=3 failed");
@@ -163,7 +175,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
-static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
+static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
+		err("set interface to alts=3 failed");
+	if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
+		deb_info("TDA10023 attach failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
+{
+	if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
+		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
 {
 	if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
 		deb_info("TDA8263 attach failed\n");
@@ -180,6 +212,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties ttusb2_properties;
 static struct dvb_usb_device_properties ttusb2_properties_s2400;
+static struct dvb_usb_device_properties ttusb2_properties_ct3650;
 
 static int ttusb2_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
@@ -187,6 +220,8 @@ static int ttusb2_probe(struct usb_interface *intf,
 	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
 				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
 	return -ENODEV;
@@ -197,6 +232,8 @@ static struct usb_device_id ttusb2_table [] = {
 	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
 	{ USB_DEVICE(USB_VID_TECHNOTREND,
 		USB_PID_TECHNOTREND_CONNECT_S2400) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND,
+		USB_PID_TECHNOTREND_CONNECT_CT3650) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -214,8 +251,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
 		{
 			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
 
-			.frontend_attach  = ttusb2_frontend_attach,
-			.tuner_attach     = ttusb2_tuner_attach,
+			.frontend_attach  = ttusb2_frontend_tda10086_attach,
+			.tuner_attach     = ttusb2_tuner_tda826x_attach,
 
 			/* parameter for the MPEG2-data transfer */
 			.stream = {
@@ -266,8 +303,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
 		{
 			.streaming_ctrl   = NULL,
 
-			.frontend_attach  = ttusb2_frontend_attach,
-			.tuner_attach     = ttusb2_tuner_attach,
+			.frontend_attach  = ttusb2_frontend_tda10086_attach,
+			.tuner_attach     = ttusb2_tuner_tda826x_attach,
 
 			/* parameter for the MPEG2-data transfer */
 			.stream = {
@@ -301,6 +338,52 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
 	}
 };
 
+static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.size_of_priv = sizeof(struct ttusb2_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = NULL,
+
+			.frontend_attach  = ttusb2_frontend_tda10023_attach,
+			.tuner_attach = ttusb2_tuner_tda827x_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		},
+	},
+
+	.power_ctrl       = ttusb2_power_ctrl,
+	.identify_state   = ttusb2_identify_state,
+
+	.i2c_algo         = &ttusb2_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Technotrend TT-connect CT-3650",
+			.warm_ids = { &ttusb2_table[3], NULL },
+		},
+	}
+};
+
 static struct usb_driver ttusb2_driver = {
 	.name		= "dvb_usb_ttusb2",
 	.probe		= ttusb2_probe,

+ 1 - 1
drivers/media/dvb/firewire/firedtv-1394.c

@@ -58,7 +58,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
 	num = hpsb_iso_n_ready(iso);
 
 	if (!fdtv) {
-		dev_err(fdtv->device, "received at unknown iso channel\n");
+		pr_err("received at unknown iso channel\n");
 		goto out;
 	}
 

+ 0 - 26
drivers/media/dvb/frontends/au8522_decoder.c

@@ -567,30 +567,6 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 /* ----------------------------------------------------------------------- */
 
-static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
-	switch (fmt->type) {
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
-	switch (fmt->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		/* Not yet implemented */
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int au8522_g_register(struct v4l2_subdev *sd,
 			     struct v4l2_dbg_register *reg)
@@ -772,8 +748,6 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
 
 static const struct v4l2_subdev_video_ops au8522_video_ops = {
 	.s_routing = au8522_s_video_routing,
-	.g_fmt = au8522_g_fmt,
-	.s_fmt = au8522_s_fmt,
 	.s_stream = au8522_s_stream,
 };
 

+ 1 - 4
drivers/media/dvb/frontends/ds3000.c

@@ -969,15 +969,12 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
 	dprintk("%s\n", __func__);
 
 	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL);
+	state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
 	if (state == NULL) {
 		printk(KERN_ERR "Unable to kmalloc\n");
 		goto error2;
 	}
 
-	/* setup the state */
-	memset(state, 0, sizeof(struct ds3000_state));
-
 	state->config = config;
 	state->i2c = i2c;
 	state->prevUCBS2 = 0;

+ 4 - 1
drivers/media/dvb/frontends/stv6110x.c

@@ -303,7 +303,10 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
 
 static int stv6110x_sleep(struct dvb_frontend *fe)
 {
-	return stv6110x_set_mode(fe, TUNER_SLEEP);
+	if (fe->tuner_priv)
+		return stv6110x_set_mode(fe, TUNER_SLEEP);
+
+	return 0;
 }
 
 static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)

+ 15 - 0
drivers/media/dvb/ngene/ngene-cards.c

@@ -217,6 +217,19 @@ static struct ngene_info ngene_info_cineS2v5 = {
 	.fw_version	= 15,
 };
 
+static struct ngene_info ngene_info_duoFlexS2 = {
+	.type           = NGENE_SIDEWINDER,
+	.name           = "Digital Devices DuoFlex S2 miniPCIe",
+	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach   = {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config      = {&fe_cineS2, &fe_cineS2},
+	.tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb            = {0x0a, 0x08},
+	.tsf            = {3, 3},
+	.fw_version     = 15,
+};
+
 static struct ngene_info ngene_info_m780 = {
 	.type           = NGENE_APP,
 	.name           = "Aver M780 ATSC/QAM-B",
@@ -256,6 +269,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
 	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
 	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
 	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+	NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),
+	NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),
 	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
 	{0}
 };

+ 55 - 25
drivers/media/dvb/ngene/ngene-core.c

@@ -53,8 +53,6 @@ MODULE_PARM_DESC(debug, "Print debugging information.");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-#define COMMAND_TIMEOUT_WORKAROUND
-
 #define dprintk	if (debug) printk
 
 #define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
@@ -147,24 +145,24 @@ static void demux_tasklet(unsigned long data)
 		} else {
 			if (chan->HWState == HWSTATE_RUN) {
 				u32 Flags = 0;
+				IBufferExchange *exch1 = chan->pBufferExchange;
+				IBufferExchange *exch2 = chan->pBufferExchange2;
 				if (Cur->ngeneBuffer.SR.Flags & 0x01)
 					Flags |= BEF_EVEN_FIELD;
 				if (Cur->ngeneBuffer.SR.Flags & 0x20)
 					Flags |= BEF_OVERFLOW;
-				if (chan->pBufferExchange)
-					chan->pBufferExchange(chan,
-							      Cur->Buffer1,
-							      chan->
-							      Capture1Length,
-							      Cur->ngeneBuffer.
-							      SR.Clock, Flags);
-				if (chan->pBufferExchange2)
-					chan->pBufferExchange2(chan,
-							       Cur->Buffer2,
-							       chan->
-							       Capture2Length,
-							       Cur->ngeneBuffer.
-							       SR.Clock, Flags);
+				spin_unlock_irq(&chan->state_lock);
+				if (exch1)
+					exch1(chan, Cur->Buffer1,
+						chan->Capture1Length,
+						Cur->ngeneBuffer.SR.Clock,
+						Flags);
+				if (exch2)
+					exch2(chan, Cur->Buffer2,
+						chan->Capture2Length,
+						Cur->ngeneBuffer.SR.Clock,
+						Flags);
+				spin_lock_irq(&chan->state_lock);
 			} else if (chan->HWState != HWSTATE_STOP)
 				chan->HWState = HWSTATE_RUN;
 		}
@@ -572,11 +570,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream,
 	u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
 	u16 BsSDO = 0x9B00;
 
-	/* down(&dev->stream_mutex); */
-	while (down_trylock(&dev->stream_mutex)) {
-		printk(KERN_INFO DEVICE_NAME ": SC locked\n");
-		msleep(1);
-	}
+	down(&dev->stream_mutex);
 	memset(&com, 0, sizeof(com));
 	com.cmd.hdr.Opcode = CMD_CONTROL;
 	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
@@ -1252,14 +1246,17 @@ static int ngene_load_firm(struct ngene *dev)
 		version = 15;
 		size = 23466;
 		fw_name = "ngene_15.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 	case 16:
 		size = 23498;
 		fw_name = "ngene_16.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 	case 17:
 		size = 24446;
 		fw_name = "ngene_17.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 	}
 
@@ -1299,11 +1296,16 @@ static void ngene_stop(struct ngene *dev)
 	ngwritel(0, NGENE_EVENT);
 	ngwritel(0, NGENE_EVENT_HI);
 	free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+	if (dev->msi_enabled)
+		pci_disable_msi(dev->pci_dev);
+#endif
 }
 
 static int ngene_start(struct ngene *dev)
 {
 	int stat;
+	unsigned long flags;
 	int i;
 
 	pci_set_master(dev->pci_dev);
@@ -1333,6 +1335,28 @@ static int ngene_start(struct ngene *dev)
 	if (stat < 0)
 		goto fail;
 
+#ifdef CONFIG_PCI_MSI
+	/* enable MSI if kernel and card support it */
+	if (pci_msi_enabled() && dev->card_info->msi_supported) {
+		ngwritel(0, NGENE_INT_ENABLE);
+		free_irq(dev->pci_dev->irq, dev);
+		stat = pci_enable_msi(dev->pci_dev);
+		if (stat) {
+			printk(KERN_INFO DEVICE_NAME
+				": MSI not available\n");
+			flags = IRQF_SHARED;
+		} else {
+			flags = 0;
+			dev->msi_enabled = true;
+		}
+		stat = request_irq(dev->pci_dev->irq, irq_handler,
+					flags, "nGene", dev);
+		if (stat < 0)
+			goto fail2;
+		ngwritel(1, NGENE_INT_ENABLE);
+	}
+#endif
+
 	stat = ngene_i2c_init(dev, 0);
 	if (stat < 0)
 		goto fail;
@@ -1358,10 +1382,18 @@ static int ngene_start(struct ngene *dev)
 			bconf = BUFFER_CONFIG_3333;
 		stat = ngene_command_config_buf(dev, bconf);
 	}
-	return stat;
+	if (!stat)
+		return stat;
+
+	/* otherwise error: fall through */
 fail:
 	ngwritel(0, NGENE_INT_ENABLE);
 	free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+fail2:
+	if (dev->msi_enabled)
+		pci_disable_msi(dev->pci_dev);
+#endif
 	return stat;
 }
 
@@ -1379,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan)
 	struct ngene_info *ni = dev->card_info;
 	int io = ni->io_type[chan->number];
 
-#ifdef COMMAND_TIMEOUT_WORKAROUND
-	if (chan->running)
+	if (chan->dev->cmd_timeout_workaround && chan->running)
 		set_transfer(chan, 0);
-#endif
 
 	tasklet_kill(&chan->demux_tasklet);
 

+ 3 - 12
drivers/media/dvb/ngene/ngene-dvb.c

@@ -37,15 +37,12 @@
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
 #include <linux/vmalloc.h>
 
 #include "ngene.h"
 
-#define COMMAND_TIMEOUT_WORKAROUND
-
 
 /****************************************************************************/
 /* COMMAND API interface ****************************************************/
@@ -69,9 +66,7 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 	struct ngene_channel *chan = priv;
 
 
-#ifdef COMMAND_TIMEOUT_WORKAROUND
 	if (chan->users > 0)
-#endif
 		dvb_dmx_swfilter(&chan->demux, buf, len);
 	return NULL;
 }
@@ -106,11 +101,8 @@ int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 	struct ngene_channel *chan = dvbdmx->priv;
 
 	if (chan->users == 0) {
-#ifdef COMMAND_TIMEOUT_WORKAROUND
-		if (!chan->running)
-#endif
+		if (!chan->dev->cmd_timeout_workaround || !chan->running)
 			set_transfer(chan, 1);
-		/* msleep(10); */
 	}
 
 	return ++chan->users;
@@ -124,9 +116,8 @@ int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 	if (--chan->users)
 		return chan->users;
 
-#ifndef COMMAND_TIMEOUT_WORKAROUND
-	set_transfer(chan, 0);
-#endif
+	if (!chan->dev->cmd_timeout_workaround)
+		set_transfer(chan, 0);
 
 	return 0;
 }

+ 0 - 1
drivers/media/dvb/ngene/ngene-i2c.c

@@ -39,7 +39,6 @@
 #include <linux/pci_ids.h>
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
 #include <linux/vmalloc.h>

+ 3 - 0
drivers/media/dvb/ngene/ngene.h

@@ -725,6 +725,8 @@ struct ngene {
 	u32                   device_version;
 	u32                   fw_interface_version;
 	u32                   icounts;
+	bool                  msi_enabled;
+	bool                  cmd_timeout_workaround;
 
 	u8                   *CmdDoneByte;
 	int                   BootFirmware;
@@ -797,6 +799,7 @@ struct ngene_info {
 #define NGENE_VBOX_V2	 7
 
 	int   fw_version;
+	bool  msi_supported;
 	char *name;
 
 	int   io_type[MAX_STREAM];

+ 3 - 2
drivers/media/dvb/ttpci/Kconfig

@@ -68,13 +68,14 @@ config DVB_BUDGET
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
 	select DVB_L64781 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
-	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
 	help
 	  Support for simple SAA7146 based DVB cards (so called Budget-
 	  or Nova-PCI cards) without onboard MPEG2 decoder, and without

+ 1 - 0
drivers/media/dvb/ttpci/budget-ci.c

@@ -215,6 +215,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 		break;
 	case 0x1010:
 	case 0x1017:
+	case 0x1019:
 	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
 		ir_codes = RC_MAP_TT_1500;

+ 2 - 2
drivers/media/video/Kconfig

@@ -646,7 +646,7 @@ config VIDEO_PMS
 
 config VIDEO_BWQCAM
 	tristate "Quickcam BW Video For Linux"
-	depends on PARPORT && VIDEO_V4L1
+	depends on PARPORT && VIDEO_V4L2
 	help
 	  Say Y have if you the black and white version of the QuickCam
 	  camera. See the next option for the color version.
@@ -656,7 +656,7 @@ config VIDEO_BWQCAM
 
 config VIDEO_CQCAM
 	tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1
+	depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
 	help
 	  This is the video4linux driver for the colour version of the
 	  Connectix QuickCam.  If you have one of these cameras, say Y here,

+ 2 - 1
drivers/media/video/ak881x.c

@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/videodev2.h>
 
 #include <media/ak881x.h>
@@ -141,7 +142,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
 	return ak881x_try_g_mbus_fmt(sd, mf);
 }
 
-static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index,
+static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
 				enum v4l2_mbus_pixelcode *code)
 {
 	if (index)

+ 414 - 345
drivers/media/video/bw-qcam.c

@@ -66,19 +66,58 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/parport.h>
 #include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
-
-#include "bw-qcam.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+/* One from column A... */
+#define QC_NOTSET 0
+#define QC_UNIDIR 1
+#define QC_BIDIR  2
+#define QC_SERIAL 3
+
+/* ... and one from column B */
+#define QC_ANY          0x00
+#define QC_FORCE_UNIDIR 0x10
+#define QC_FORCE_BIDIR  0x20
+#define QC_FORCE_SERIAL 0x30
+/* in the port_mode member */
+
+#define QC_MODE_MASK    0x07
+#define QC_FORCE_MASK   0x70
+
+#define MAX_HEIGHT 243
+#define MAX_WIDTH 336
+
+/* Bit fields for status flags */
+#define QC_PARAM_CHANGE	0x01 /* Camera status change has occurred */
+
+struct qcam {
+	struct v4l2_device v4l2_dev;
+	struct video_device vdev;
+	struct pardevice *pdev;
+	struct parport *pport;
+	struct mutex lock;
+	int width, height;
+	int bpp;
+	int mode;
+	int contrast, brightness, whitebal;
+	int port_mode;
+	int transfer_scale;
+	int top, left;
+	int status;
+	unsigned int saved_bits;
+	unsigned long in_use;
+};
 
 static unsigned int maxpoll = 250;   /* Maximum busy-loop count for qcam I/O */
 static unsigned int yieldlines = 4;  /* Yield after this many during capture */
@@ -93,22 +132,26 @@ module_param(video_nr, int, 0);
  * immediately attempt to initialize qcam */
 module_param(force_init, int, 0);
 
-static inline int read_lpstatus(struct qcam_device *q)
+#define MAX_CAMS 4
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline int read_lpstatus(struct qcam *q)
 {
 	return parport_read_status(q->pport);
 }
 
-static inline int read_lpdata(struct qcam_device *q)
+static inline int read_lpdata(struct qcam *q)
 {
 	return parport_read_data(q->pport);
 }
 
-static inline void write_lpdata(struct qcam_device *q, int d)
+static inline void write_lpdata(struct qcam *q, int d)
 {
 	parport_write_data(q->pport, d);
 }
 
-static inline void write_lpcontrol(struct qcam_device *q, int d)
+static void write_lpcontrol(struct qcam *q, int d)
 {
 	if (d & 0x20) {
 		/* Set bidirectional mode to reverse (data in) */
@@ -124,126 +167,11 @@ static inline void write_lpcontrol(struct qcam_device *q, int d)
 	parport_write_control(q->pport, d);
 }
 
-static int qc_waithand(struct qcam_device *q, int val);
-static int qc_command(struct qcam_device *q, int command);
-static int qc_readparam(struct qcam_device *q);
-static int qc_setscanmode(struct qcam_device *q);
-static int qc_readbytes(struct qcam_device *q, char buffer[]);
-
-static struct video_device qcam_template;
-
-static int qc_calibrate(struct qcam_device *q)
-{
-	/*
-	 *	Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
-	 *	The white balance is an individiual value for each
-	 *	quickcam.
-	 */
-
-	int value;
-	int count = 0;
-
-	qc_command(q, 27);	/* AutoAdjustOffset */
-	qc_command(q, 0);	/* Dummy Parameter, ignored by the camera */
-
-	/* GetOffset (33) will read 255 until autocalibration */
-	/* is finished. After that, a value of 1-254 will be */
-	/* returned. */
-
-	do {
-		qc_command(q, 33);
-		value = qc_readparam(q);
-		mdelay(1);
-		schedule();
-		count++;
-	} while (value == 0xff && count < 2048);
-
-	q->whitebal = value;
-	return value;
-}
-
-/* Initialize the QuickCam driver control structure.  This is where
- * defaults are set for people who don't have a config file.*/
-
-static struct qcam_device *qcam_init(struct parport *port)
-{
-	struct qcam_device *q;
-
-	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
-	if (q == NULL)
-		return NULL;
-
-	q->pport = port;
-	q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
-			NULL, 0, NULL);
-	if (q->pdev == NULL) {
-		printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
-				port->name);
-		kfree(q);
-		return NULL;
-	}
-
-	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
-	mutex_init(&q->lock);
-
-	q->port_mode = (QC_ANY | QC_NOTSET);
-	q->width = 320;
-	q->height = 240;
-	q->bpp = 4;
-	q->transfer_scale = 2;
-	q->contrast = 192;
-	q->brightness = 180;
-	q->whitebal = 105;
-	q->top = 1;
-	q->left = 14;
-	q->mode = -1;
-	q->status = QC_PARAM_CHANGE;
-	return q;
-}
-
-
-/* qc_command is probably a bit of a misnomer -- it's used to send
- * bytes *to* the camera.  Generally, these bytes are either commands
- * or arguments to commands, so the name fits, but it still bugs me a
- * bit.  See the documentation for a list of commands. */
-
-static int qc_command(struct qcam_device *q, int command)
-{
-	int n1, n2;
-	int cmd;
-
-	write_lpdata(q, command);
-	write_lpcontrol(q, 6);
-
-	n1 = qc_waithand(q, 1);
-
-	write_lpcontrol(q, 0xe);
-	n2 = qc_waithand(q, 0);
-
-	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
-	return cmd;
-}
-
-static int qc_readparam(struct qcam_device *q)
-{
-	int n1, n2;
-	int cmd;
-
-	write_lpcontrol(q, 6);
-	n1 = qc_waithand(q, 1);
-
-	write_lpcontrol(q, 0xe);
-	n2 = qc_waithand(q, 0);
-
-	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
-	return cmd;
-}
 
 /* qc_waithand busy-waits for a handshake signal from the QuickCam.
  * Almost all communication with the camera requires handshaking. */
 
-static int qc_waithand(struct qcam_device *q, int val)
+static int qc_waithand(struct qcam *q, int val)
 {
 	int status;
 	int runs = 0;
@@ -286,7 +214,7 @@ static int qc_waithand(struct qcam_device *q, int val)
  * (bit 3 of status register).  It also returns the last value read,
  * since this data is useful. */
 
-static unsigned int qc_waithand2(struct qcam_device *q, int val)
+static unsigned int qc_waithand2(struct qcam *q, int val)
 {
 	unsigned int status;
 	int runs = 0;
@@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
 	return status;
 }
 
+/* qc_command is probably a bit of a misnomer -- it's used to send
+ * bytes *to* the camera.  Generally, these bytes are either commands
+ * or arguments to commands, so the name fits, but it still bugs me a
+ * bit.  See the documentation for a list of commands. */
+
+static int qc_command(struct qcam *q, int command)
+{
+	int n1, n2;
+	int cmd;
+
+	write_lpdata(q, command);
+	write_lpcontrol(q, 6);
+
+	n1 = qc_waithand(q, 1);
+
+	write_lpcontrol(q, 0xe);
+	n2 = qc_waithand(q, 0);
+
+	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+	return cmd;
+}
+
+static int qc_readparam(struct qcam *q)
+{
+	int n1, n2;
+	int cmd;
+
+	write_lpcontrol(q, 6);
+	n1 = qc_waithand(q, 1);
+
+	write_lpcontrol(q, 0xe);
+	n2 = qc_waithand(q, 0);
+
+	cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+	return cmd;
+}
+
 
 /* Try to detect a QuickCam.  It appears to flash the upper 4 bits of
    the status register at 5-10 Hz.  This is only used in the autoprobe
@@ -317,7 +282,7 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
    almost completely safe, while their method screws up my printer if
    I plug it in before the camera. */
 
-static int qc_detect(struct qcam_device *q)
+static int qc_detect(struct qcam *q)
 {
 	int reg, lastreg;
 	int count = 0;
@@ -358,41 +323,6 @@ static int qc_detect(struct qcam_device *q)
 	}
 }
 
-
-/* Reset the QuickCam.  This uses the same sequence the Windows
- * QuickPic program uses.  Someone with a bi-directional port should
- * check that bi-directional mode is detected right, and then
- * implement bi-directional mode in qc_readbyte(). */
-
-static void qc_reset(struct qcam_device *q)
-{
-	switch (q->port_mode & QC_FORCE_MASK) {
-	case QC_FORCE_UNIDIR:
-		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
-		break;
-
-	case QC_FORCE_BIDIR:
-		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
-		break;
-
-	case QC_ANY:
-		write_lpcontrol(q, 0x20);
-		write_lpdata(q, 0x75);
-
-		if (read_lpdata(q) != 0x75)
-			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
-		else
-			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
-		break;
-	}
-
-	write_lpcontrol(q, 0xb);
-	udelay(250);
-	write_lpcontrol(q, 0xe);
-	qc_setscanmode(q);		/* in case port_mode changed */
-}
-
-
 /* Decide which scan mode to use.  There's no real requirement that
  * the scanmode match the resolution in q->height and q-> width -- the
  * camera takes the picture at the resolution specified in the
@@ -402,7 +332,7 @@ static void qc_reset(struct qcam_device *q)
  * returned.  If the scan is smaller, then the rest of the image
  * returned contains garbage. */
 
-static int qc_setscanmode(struct qcam_device *q)
+static int qc_setscanmode(struct qcam *q)
 {
 	int old_mode = q->mode;
 
@@ -442,10 +372,45 @@ static int qc_setscanmode(struct qcam_device *q)
 }
 
 
+/* Reset the QuickCam.  This uses the same sequence the Windows
+ * QuickPic program uses.  Someone with a bi-directional port should
+ * check that bi-directional mode is detected right, and then
+ * implement bi-directional mode in qc_readbyte(). */
+
+static void qc_reset(struct qcam *q)
+{
+	switch (q->port_mode & QC_FORCE_MASK) {
+	case QC_FORCE_UNIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
+
+	case QC_FORCE_BIDIR:
+		q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+		break;
+
+	case QC_ANY:
+		write_lpcontrol(q, 0x20);
+		write_lpdata(q, 0x75);
+
+		if (read_lpdata(q) != 0x75)
+			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+		else
+			q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+		break;
+	}
+
+	write_lpcontrol(q, 0xb);
+	udelay(250);
+	write_lpcontrol(q, 0xe);
+	qc_setscanmode(q);		/* in case port_mode changed */
+}
+
+
+
 /* Reset the QuickCam and program for brightness, contrast,
  * white-balance, and resolution. */
 
-static void qc_set(struct qcam_device *q)
+static void qc_set(struct qcam *q)
 {
 	int val;
 	int val2;
@@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q)
    the supplied buffer.  It returns the number of bytes read,
    or -1 on error. */
 
-static inline int qc_readbytes(struct qcam_device *q, char buffer[])
+static inline int qc_readbytes(struct qcam *q, char buffer[])
 {
 	int ret = 1;
 	unsigned int hi, lo;
@@ -590,7 +555,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
  * n=2^(bit depth)-1.  Ask me for more details if you don't understand
  * this. */
 
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
 {
 	int i, j, k, yield;
 	int bytes;
@@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
  *	Video4linux interfacing
  */
 
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
 {
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
-
-	switch (cmd) {
-	case VIDIOCGCAP:
-		{
-			struct video_capability *b = arg;
-			strcpy(b->name, "Quickcam");
-			b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME;
-			b->channels = 1;
-			b->audios = 0;
-			b->maxwidth = 320;
-			b->maxheight = 240;
-			b->minwidth = 80;
-			b->minheight = 60;
-			return 0;
-		}
-	case VIDIOCGCHAN:
-		{
-			struct video_channel *v = arg;
-			if (v->channel != 0)
-				return -EINVAL;
-			v->flags = 0;
-			v->tuners = 0;
-			/* Good question.. its composite or SVHS so.. */
-			v->type = VIDEO_TYPE_CAMERA;
-			strcpy(v->name, "Camera");
-			return 0;
-		}
-	case VIDIOCSCHAN:
-		{
-			struct video_channel *v = arg;
-			if (v->channel != 0)
-				return -EINVAL;
-			return 0;
-		}
-	case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-			if (v->tuner)
-				return -EINVAL;
-			strcpy(v->name, "Format");
-			v->rangelow = 0;
-			v->rangehigh = 0;
-			v->flags = 0;
-			v->mode = VIDEO_MODE_AUTO;
-			return 0;
-		}
-	case VIDIOCSTUNER:
-		{
-			struct video_tuner *v = arg;
-			if (v->tuner)
-				return -EINVAL;
-			if (v->mode != VIDEO_MODE_AUTO)
-				return -EINVAL;
-			return 0;
-		}
-	case VIDIOCGPICT:
-		{
-			struct video_picture *p = arg;
-			p->colour = 0x8000;
-			p->hue = 0x8000;
-			p->brightness = qcam->brightness << 8;
-			p->contrast = qcam->contrast << 8;
-			p->whiteness = qcam->whitebal << 8;
-			p->depth = qcam->bpp;
-			p->palette = VIDEO_PALETTE_GREY;
-			return 0;
-		}
-	case VIDIOCSPICT:
-		{
-			struct video_picture *p = arg;
-			if (p->palette != VIDEO_PALETTE_GREY)
-				return -EINVAL;
-			if (p->depth != 4 && p->depth != 6)
-				return -EINVAL;
-
-			/*
-			 *	Now load the camera.
-			 */
-
-			qcam->brightness = p->brightness >> 8;
-			qcam->contrast = p->contrast >> 8;
-			qcam->whitebal = p->whiteness >> 8;
-			qcam->bpp = p->depth;
-
-			mutex_lock(&qcam->lock);
-			qc_setscanmode(qcam);
-			mutex_unlock(&qcam->lock);
-			qcam->status |= QC_PARAM_CHANGE;
+	struct qcam *qcam = video_drvdata(file);
 
-			return 0;
-		}
-	case VIDIOCSWIN:
-		{
-			struct video_window *vw = arg;
-			if (vw->flags)
-				return -EINVAL;
-			if (vw->clipcount)
-				return -EINVAL;
-			if (vw->height < 60 || vw->height > 240)
-				return -EINVAL;
-			if (vw->width < 80 || vw->width > 320)
-				return -EINVAL;
-
-			qcam->width = 320;
-			qcam->height = 240;
-			qcam->transfer_scale = 4;
-
-			if (vw->width >= 160 && vw->height >= 120)
-				qcam->transfer_scale = 2;
-			if (vw->width >= 320 && vw->height >= 240) {
-				qcam->width = 320;
-				qcam->height = 240;
-				qcam->transfer_scale = 1;
-			}
-			mutex_lock(&qcam->lock);
-			qc_setscanmode(qcam);
-			mutex_unlock(&qcam->lock);
+	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	vcap->version = KERNEL_VERSION(0, 0, 2);
+	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	return 0;
+}
 
-			/* We must update the camera before we grab. We could
-			   just have changed the grab size */
-			qcam->status |= QC_PARAM_CHANGE;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
+}
 
-			/* Ok we figured out what to use from our wide choice */
-			return 0;
-		}
-	case VIDIOCGWIN:
-		{
-			struct video_window *vw = arg;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
 
-			memset(vw, 0, sizeof(*vw));
-			vw->width = qcam->width / qcam->transfer_scale;
-			vw->height = qcam->height / qcam->transfer_scale;
-			return 0;
-		}
-	case VIDIOCKEY:
-		return 0;
-	case VIDIOCCAPTURE:
-	case VIDIOCGFBUF:
-	case VIDIOCSFBUF:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return -EINVAL;
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+	case V4L2_CID_GAMMA:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
+	}
+	return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = qcam->brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = qcam->contrast;
+		break;
+	case V4L2_CID_GAMMA:
+		ctrl->value = qcam->whitebal;
+		break;
 	default:
-		return -ENOIOCTLCMD;
+		ret = -EINVAL;
+		break;
 	}
+	return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->value;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->value;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret == 0) {
+		qc_setscanmode(qcam);
+		qcam->status |= QC_PARAM_CHANGE;
+	}
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
+
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = qcam->width / qcam->transfer_scale;
+	pix->height = qcam->height / qcam->transfer_scale;
+	pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = qcam->width;
+	pix->sizeimage = qcam->width * qcam->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height <= 60 || pix->width <= 80) {
+		pix->height = 60;
+		pix->width = 80;
+	} else if (pix->height <= 120 || pix->width <= 160) {
+		pix->height = 120;
+		pix->width = 160;
+	} else {
+		pix->height = 240;
+		pix->width = 320;
+	}
+	if (pix->pixelformat != V4L2_PIX_FMT_Y4 &&
+	    pix->pixelformat != V4L2_PIX_FMT_Y6)
+		pix->pixelformat = V4L2_PIX_FMT_Y4;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width;
+	pix->sizeimage = pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	qcam->width = 320;
+	qcam->height = 240;
+	if (pix->height == 60)
+		qcam->transfer_scale = 4;
+	else if (pix->height == 120)
+		qcam->transfer_scale = 2;
+	else
+		qcam->transfer_scale = 1;
+	if (pix->pixelformat == V4L2_PIX_FMT_Y6)
+		qcam->bpp = 6;
+	else
+		qcam->bpp = 4;
+
+	mutex_lock(&qcam->lock);
+	qc_setscanmode(qcam);
+	/* We must update the camera before we grab. We could
+	   just have changed the grab size */
+	qcam->status |= QC_PARAM_CHANGE;
+	mutex_unlock(&qcam->lock);
 	return 0;
 }
 
-static long qcam_ioctl(struct file *file,
-		unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
 {
-	return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
+		  { 0, 0, 0, 0 }
+		},
+		{ 0, 0, 0,
+		  "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
+		  { 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 ssize_t qcam_read(struct file *file, char __user *buf,
 		size_t count, loff_t *ppos)
 {
-	struct video_device *v = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)v;
+	struct qcam *qcam = video_drvdata(file);
 	int len;
 	parport_claim_or_block(qcam->pdev);
 
@@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 	return len;
 }
 
-static int qcam_exclusive_open(struct file *file)
+static const struct v4l2_file_operations qcam_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl          = video_ioctl2,
+	.read		= qcam_read,
+};
+
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+	.vidioc_querycap    		    = qcam_querycap,
+	.vidioc_g_input      		    = qcam_g_input,
+	.vidioc_s_input      		    = qcam_s_input,
+	.vidioc_enum_input   		    = qcam_enum_input,
+	.vidioc_queryctrl 		    = qcam_queryctrl,
+	.vidioc_g_ctrl  		    = qcam_g_ctrl,
+	.vidioc_s_ctrl 			    = qcam_s_ctrl,
+	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
+};
+
+/* Initialize the QuickCam driver control structure.  This is where
+ * defaults are set for people who don't have a config file.*/
+
+static struct qcam *qcam_init(struct parport *port)
 {
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
+
+	qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
+	if (qcam == NULL)
+		return NULL;
+
+	v4l2_dev = &qcam->v4l2_dev;
+	strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name));
 
-	return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return NULL;
+	}
+
+	qcam->pport = port;
+	qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
+			NULL, 0, NULL);
+	if (qcam->pdev == NULL) {
+		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		kfree(qcam);
+		return NULL;
+	}
+
+	strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
+	qcam->vdev.v4l2_dev = v4l2_dev;
+	qcam->vdev.fops = &qcam_fops;
+	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+	qcam->vdev.release = video_device_release_empty;
+	video_set_drvdata(&qcam->vdev, qcam);
+
+	mutex_init(&qcam->lock);
+
+	qcam->port_mode = (QC_ANY | QC_NOTSET);
+	qcam->width = 320;
+	qcam->height = 240;
+	qcam->bpp = 4;
+	qcam->transfer_scale = 2;
+	qcam->contrast = 192;
+	qcam->brightness = 180;
+	qcam->whitebal = 105;
+	qcam->top = 1;
+	qcam->left = 14;
+	qcam->mode = -1;
+	qcam->status = QC_PARAM_CHANGE;
+	return qcam;
 }
 
-static int qcam_exclusive_release(struct file *file)
+static int qc_calibrate(struct qcam *q)
 {
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
+	/*
+	 *	Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
+	 *	The white balance is an individual value for each
+	 *	quickcam.
+	 */
 
-	clear_bit(0, &qcam->in_use);
-	return 0;
-}
+	int value;
+	int count = 0;
 
-static const struct v4l2_file_operations qcam_fops = {
-	.owner		= THIS_MODULE,
-	.open           = qcam_exclusive_open,
-	.release        = qcam_exclusive_release,
-	.ioctl          = qcam_ioctl,
-	.read		= qcam_read,
-};
-static struct video_device qcam_template = {
-	.name		= "Connectix Quickcam",
-	.fops           = &qcam_fops,
-	.release 	= video_device_release_empty,
-};
+	qc_command(q, 27);	/* AutoAdjustOffset */
+	qc_command(q, 0);	/* Dummy Parameter, ignored by the camera */
 
-#define MAX_CAMS 4
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
+	/* GetOffset (33) will read 255 until autocalibration */
+	/* is finished. After that, a value of 1-254 will be */
+	/* returned. */
+
+	do {
+		qc_command(q, 33);
+		value = qc_readparam(q);
+		mdelay(1);
+		schedule();
+		count++;
+	} while (value == 0xff && count < 2048);
+
+	q->whitebal = value;
+	return value;
+}
 
 static int init_bwqcam(struct parport *port)
 {
-	struct qcam_device *qcam;
+	struct qcam *qcam;
 
 	if (num_cams == MAX_CAMS) {
 		printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
@@ -919,7 +988,7 @@ static int init_bwqcam(struct parport *port)
 
 	parport_release(qcam->pdev);
 
-	printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
+	v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name);
 
 	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		parport_unregister_device(qcam->pdev);
@@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port)
 	return 0;
 }
 
-static void close_bwqcam(struct qcam_device *qcam)
+static void close_bwqcam(struct qcam *qcam)
 {
 	video_unregister_device(&qcam->vdev);
 	parport_unregister_device(qcam->pdev);
@@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port)
 {
 	int i;
 	for (i = 0; i < num_cams; i++) {
-		struct qcam_device *qcam = qcams[i];
+		struct qcam *qcam = qcams[i];
 		if (qcam && qcam->pdev->port == port) {
 			qcams[i] = NULL;
 			close_bwqcam(qcam);

+ 0 - 69
drivers/media/video/bw-qcam.h

@@ -1,69 +0,0 @@
-/*
- *	Video4Linux bw-qcam driver
- *
- *	Derived from code..
- */
-
-/******************************************************************
-
-Copyright (C) 1996 by Scott Laird
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-******************************************************************/
-
-/* One from column A... */
-#define QC_NOTSET 0
-#define QC_UNIDIR 1
-#define QC_BIDIR  2
-#define QC_SERIAL 3
-
-/* ... and one from column B */
-#define QC_ANY          0x00
-#define QC_FORCE_UNIDIR 0x10
-#define QC_FORCE_BIDIR  0x20
-#define QC_FORCE_SERIAL 0x30
-/* in the port_mode member */
-
-#define QC_MODE_MASK    0x07
-#define QC_FORCE_MASK   0x70
-
-#define MAX_HEIGHT 243
-#define MAX_WIDTH 336
-
-/* Bit fields for status flags */
-#define QC_PARAM_CHANGE	0x01 /* Camera status change has occurred */
-
-struct qcam_device {
-	struct video_device vdev;
-	struct pardevice *pdev;
-	struct parport *pport;
-	struct mutex lock;
-	int width, height;
-	int bpp;
-	int mode;
-	int contrast, brightness, whitebal;
-	int port_mode;
-	int transfer_scale;
-	int top, left;
-	int status;
-	unsigned int saved_bits;
-	unsigned long in_use;
-};

+ 330 - 304
drivers/media/video/c-qcam.c

@@ -33,15 +33,17 @@
 #include <linux/mm.h>
 #include <linux/parport.h>
 #include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <linux/mutex.h>
 #include <linux/jiffies.h>
-
+#include <linux/version.h>
+#include <linux/videodev2.h>
 #include <asm/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 
-struct qcam_device {
+struct qcam {
+	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
 	struct pardevice *pdev;
 	struct parport *pport;
@@ -51,7 +53,6 @@ struct qcam_device {
 	int contrast, brightness, whitebal;
 	int top, left;
 	unsigned int bidirectional;
-	unsigned long in_use;
 	struct mutex lock;
 };
 
@@ -68,33 +69,45 @@ struct qcam_device {
 #define QC_DECIMATION_2		2
 #define QC_DECIMATION_4		4
 
-#define BANNER "Colour QuickCam for Video4Linux v0.05"
+#define BANNER "Colour QuickCam for Video4Linux v0.06"
 
 static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 static int probe = 2;
 static int force_rgb;
 static int video_nr = -1;
 
-static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
+/* FIXME: parport=auto would never have worked, surely? --RR */
+MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
+			  "probe=<0|1|2> for camera detection method\n"
+			  "force_rgb=<0|1> for RGB data format (default BGR)");
+module_param_array(parport, int, NULL, 0);
+module_param(probe, int, 0);
+module_param(force_rgb, bool, 0);
+module_param(video_nr, int, 0);
+
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
 {
 	/* note: the QC specs refer to the PCAck pin by voltage, not
 	   software level.  PC ports have builtin inverters. */
 	parport_frob_control(qcam->pport, 8, i ? 8 : 0);
 }
 
-static inline unsigned int qcam_ready1(struct qcam_device *qcam)
+static inline unsigned int qcam_ready1(struct qcam *qcam)
 {
 	return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
 }
 
-static inline unsigned int qcam_ready2(struct qcam_device *qcam)
+static inline unsigned int qcam_ready2(struct qcam *qcam)
 {
 	return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
 }
 
-static unsigned int qcam_await_ready1(struct qcam_device *qcam,
-					     int value)
+static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
 {
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
@@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
 	}
 
 	/* Probably somebody pulled the plug out.  Not much we can do. */
-	printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
+	v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
 	       parport_read_status(qcam->pport),
 	       parport_read_control(qcam->pport));
 	return 1;
 }
 
-static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
+static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
 {
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
@@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
 	}
 
 	/* Probably somebody pulled the plug out.  Not much we can do. */
-	printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
+	v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
 	       parport_read_status(qcam->pport),
 	       parport_read_control(qcam->pport),
 	       parport_read_data(qcam->pport));
 	return 1;
 }
 
-static int qcam_read_data(struct qcam_device *qcam)
+static int qcam_read_data(struct qcam *qcam)
 {
 	unsigned int idata;
 
@@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam)
 	return idata;
 }
 
-static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
+static int qcam_write_data(struct qcam *qcam, unsigned int data)
 {
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
 	unsigned int idata;
 
 	parport_write_data(qcam->pport, data);
 	idata = qcam_read_data(qcam);
 	if (data != idata) {
-		printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
+		v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
 		       idata);
 		return 1;
 	}
 	return 0;
 }
 
-static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
+static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
 {
 	if (qcam_write_data(qcam, cmd))
 		return -1;
@@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned
 	return 0;
 }
 
-static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
+static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
 {
 	if (qcam_write_data(qcam, cmd))
 		return -1;
 	return qcam_read_data(qcam);
 }
 
-static int qc_detect(struct qcam_device *qcam)
+static int qc_detect(struct qcam *qcam)
 {
 	unsigned int stat, ostat, i, count = 0;
 
@@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam)
 	return 0;
 }
 
-static void qc_reset(struct qcam_device *qcam)
+static void qc_reset(struct qcam *qcam)
 {
 	parport_write_control(qcam->pport, 0xc);
 	parport_write_control(qcam->pport, 0x8);
@@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam)
 /* Reset the QuickCam and program for brightness, contrast,
  * white-balance, and resolution. */
 
-static void qc_setup(struct qcam_device *q)
+static void qc_setup(struct qcam *qcam)
 {
-	qc_reset(q);
+	qc_reset(qcam);
 
 	/* Set the brightness. */
-	qcam_set(q, 11, q->brightness);
+	qcam_set(qcam, 11, qcam->brightness);
 
 	/* Set the height and width.  These refer to the actual
 	   CCD area *before* applying the selected decimation.  */
-	qcam_set(q, 17, q->ccd_height);
-	qcam_set(q, 19, q->ccd_width / 2);
+	qcam_set(qcam, 17, qcam->ccd_height);
+	qcam_set(qcam, 19, qcam->ccd_width / 2);
 
 	/* Set top and left.  */
-	qcam_set(q, 0xd, q->top);
-	qcam_set(q, 0xf, q->left);
+	qcam_set(qcam, 0xd, qcam->top);
+	qcam_set(qcam, 0xf, qcam->left);
 
 	/* Set contrast and white balance.  */
-	qcam_set(q, 0x19, q->contrast);
-	qcam_set(q, 0x1f, q->whitebal);
+	qcam_set(qcam, 0x19, qcam->contrast);
+	qcam_set(qcam, 0x1f, qcam->whitebal);
 
 	/* Set the speed.  */
-	qcam_set(q, 45, 2);
+	qcam_set(qcam, 45, 2);
 }
 
 /* Read some bytes from the camera and put them in the buffer.
    nbytes should be a multiple of 3, because bidirectional mode gives
    us three bytes at a time.  */
 
-static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
+static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
 {
 	unsigned int bytes = 0;
 
-	qcam_set_ack(q, 0);
-	if (q->bidirectional) {
+	qcam_set_ack(qcam, 0);
+	if (qcam->bidirectional) {
 		/* It's a bidirectional port */
 		while (bytes < nbytes) {
 			unsigned int lo1, hi1, lo2, hi2;
 			unsigned char r, g, b;
 
-			if (qcam_await_ready2(q, 1))
+			if (qcam_await_ready2(qcam, 1))
 				return bytes;
-			lo1 = parport_read_data(q->pport) >> 1;
-			hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
-			qcam_set_ack(q, 1);
-			if (qcam_await_ready2(q, 0))
+			lo1 = parport_read_data(qcam->pport) >> 1;
+			hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+			qcam_set_ack(qcam, 1);
+			if (qcam_await_ready2(qcam, 0))
 				return bytes;
-			lo2 = parport_read_data(q->pport) >> 1;
-			hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
-			qcam_set_ack(q, 0);
+			lo2 = parport_read_data(qcam->pport) >> 1;
+			hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+			qcam_set_ack(qcam, 0);
 			r = lo1 | ((hi1 & 1) << 7);
 			g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
 			b = lo2 | ((hi2 & 1) << 7);
@@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
 		while (bytes < nbytes) {
 			unsigned int hi, lo;
 
-			if (qcam_await_ready1(q, 1))
+			if (qcam_await_ready1(qcam, 1))
 				return bytes;
-			hi = (parport_read_status(q->pport) & 0xf0);
-			qcam_set_ack(q, 1);
-			if (qcam_await_ready1(q, 0))
+			hi = (parport_read_status(qcam->pport) & 0xf0);
+			qcam_set_ack(qcam, 1);
+			if (qcam_await_ready1(qcam, 0))
 				return bytes;
-			lo = (parport_read_status(q->pport) & 0xf0);
-			qcam_set_ack(q, 0);
+			lo = (parport_read_status(qcam->pport) & 0xf0);
+			qcam_set_ack(qcam, 0);
 			/* flip some bits */
 			rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
 			if (i >= 2) {
@@ -361,10 +376,11 @@ get_fragment:
 
 #define BUFSZ	150
 
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
 {
+	struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
 	unsigned lines, pixelsperline, bitsperxfer;
-	unsigned int is_bi_dir = q->bidirectional;
+	unsigned int is_bi_dir = qcam->bidirectional;
 	size_t wantlen, outptr = 0;
 	char tmpbuf[BUFSZ];
 
@@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 
 	/* Wait for camera to become ready */
 	for (;;) {
-		int i = qcam_get(q, 41);
+		int i = qcam_get(qcam, 41);
 
 		if (i == -1) {
-			qc_setup(q);
+			qc_setup(qcam);
 			return -EIO;
 		}
 		if ((i & 0x80) == 0)
@@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		schedule();
 	}
 
-	if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1))
+	if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
 		return -EIO;
 
-	lines = q->height;
-	pixelsperline = q->width;
+	lines = qcam->height;
+	pixelsperline = qcam->width;
 	bitsperxfer = (is_bi_dir) ? 24 : 8;
 
 	if (is_bi_dir) {
 		/* Turn the port around */
-		parport_data_reverse(q->pport);
+		parport_data_reverse(qcam->pport);
 		mdelay(3);
-		qcam_set_ack(q, 0);
-		if (qcam_await_ready1(q, 1)) {
-			qc_setup(q);
+		qcam_set_ack(qcam, 0);
+		if (qcam_await_ready1(qcam, 1)) {
+			qc_setup(qcam);
 			return -EIO;
 		}
-		qcam_set_ack(q, 1);
-		if (qcam_await_ready1(q, 0)) {
-			qc_setup(q);
+		qcam_set_ack(qcam, 1);
+		if (qcam_await_ready1(qcam, 0)) {
+			qc_setup(qcam);
 			return -EIO;
 		}
 	}
@@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		size_t t, s;
 
 		s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
-		t = qcam_read_bytes(q, tmpbuf, s);
+		t = qcam_read_bytes(qcam, tmpbuf, s);
 		if (outptr < len) {
 			size_t sz = len - outptr;
 
@@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 	len = outptr;
 
 	if (wantlen) {
-		printk(KERN_ERR "qcam: short read.\n");
+		v4l2_err(v4l2_dev, "short read.\n");
 		if (is_bi_dir)
-			parport_data_forward(q->pport);
-		qc_setup(q);
+			parport_data_forward(qcam->pport);
+		qc_setup(qcam);
 		return len;
 	}
 
@@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		int l;
 
 		do {
-			l = qcam_read_bytes(q, tmpbuf, 3);
+			l = qcam_read_bytes(qcam, tmpbuf, 3);
 			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
-				printk(KERN_ERR "qcam: bad EOF\n");
+				v4l2_err(v4l2_dev, "bad EOF\n");
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
-				printk(KERN_ERR "qcam: bad EOF\n");
+				v4l2_err(v4l2_dev, "bad EOF\n");
 		}
-		qcam_set_ack(q, 0);
-		if (qcam_await_ready1(q, 1)) {
-			printk(KERN_ERR "qcam: no ack after EOF\n");
-			parport_data_forward(q->pport);
-			qc_setup(q);
+		qcam_set_ack(qcam, 0);
+		if (qcam_await_ready1(qcam, 1)) {
+			v4l2_err(v4l2_dev, "no ack after EOF\n");
+			parport_data_forward(qcam->pport);
+			qc_setup(qcam);
 			return len;
 		}
-		parport_data_forward(q->pport);
+		parport_data_forward(qcam->pport);
 		mdelay(3);
-		qcam_set_ack(q, 1);
-		if (qcam_await_ready1(q, 0)) {
-			printk(KERN_ERR "qcam: no ack to port turnaround\n");
-			qc_setup(q);
+		qcam_set_ack(qcam, 1);
+		if (qcam_await_ready1(qcam, 0)) {
+			v4l2_err(v4l2_dev, "no ack to port turnaround\n");
+			qc_setup(qcam);
 			return len;
 		}
 	} else {
 		int l;
 
 		do {
-			l = qcam_read_bytes(q, tmpbuf, 1);
+			l = qcam_read_bytes(qcam, tmpbuf, 1);
 			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
-		l = qcam_read_bytes(q, tmpbuf + 1, 2);
+		l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
-				printk(KERN_ERR "qcam: bad EOF\n");
+				v4l2_err(v4l2_dev, "bad EOF\n");
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
-				printk(KERN_ERR "qcam: bad EOF\n");
+				v4l2_err(v4l2_dev, "bad EOF\n");
 		}
 	}
 
-	qcam_write_data(q, 0);
+	qcam_write_data(qcam, 0);
 	return len;
 }
 
@@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
  *	Video4linux interfacing
  */
 
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *vcap)
 {
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
+	struct qcam *qcam = video_drvdata(file);
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *b = arg;
+	strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+	strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
+	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+	vcap->version = KERNEL_VERSION(0, 0, 3);
+	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	return 0;
+}
 
-		strcpy(b->name, "Quickcam");
-		b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-		b->channels = 1;
-		b->audios = 0;
-		b->maxwidth = 320;
-		b->maxheight = 240;
-		b->minwidth = 80;
-		b->minheight = 60;
-		return 0;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *v = arg;
-
-		if (v->channel != 0)
-			return -EINVAL;
-		v->flags = 0;
-		v->tuners = 0;
-		/* Good question.. its composite or SVHS so.. */
-		v->type = VIDEO_TYPE_CAMERA;
-		strcpy(v->name, "Camera");
-		return 0;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *v = arg;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+	if (vin->index > 0)
+		return -EINVAL;
+	strlcpy(vin->name, "Camera", sizeof(vin->name));
+	vin->type = V4L2_INPUT_TYPE_CAMERA;
+	vin->audioset = 0;
+	vin->tuner = 0;
+	vin->std = 0;
+	vin->status = 0;
+	return 0;
+}
 
-		if (v->channel != 0)
-			return -EINVAL;
-		return 0;
-	}
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *v = arg;
-
-		if (v->tuner)
-			return -EINVAL;
-		memset(v, 0, sizeof(*v));
-		strcpy(v->name, "Format");
-		v->mode = VIDEO_MODE_AUTO;
-		return 0;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+	*inp = 0;
+	return 0;
+}
+
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+	return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+	case V4L2_CID_GAMMA:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
 	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner *v = arg;
-
-		if (v->tuner)
-			return -EINVAL;
-		if (v->mode != VIDEO_MODE_AUTO)
-			return -EINVAL;
-		return 0;
+	return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = qcam->brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = qcam->contrast;
+		break;
+	case V4L2_CID_GAMMA:
+		ctrl->value = qcam->whitebal;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
 	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture *p = arg;
-
-		p->colour = 0x8000;
-		p->hue = 0x8000;
-		p->brightness = qcam->brightness << 8;
-		p->contrast = qcam->contrast << 8;
-		p->whiteness = qcam->whitebal << 8;
-		p->depth = 24;
-		p->palette = VIDEO_PALETTE_RGB24;
-		return 0;
+	return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct qcam *qcam = video_drvdata(file);
+	int ret = 0;
+
+	mutex_lock(&qcam->lock);
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		qcam->brightness = ctrl->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		qcam->contrast = ctrl->value;
+		break;
+	case V4L2_CID_GAMMA:
+		qcam->whitebal = ctrl->value;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
 	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *p = arg;
-
-		/*
-		 *	Sanity check args
-		 */
-		if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
-			return -EINVAL;
-
-		/*
-		 *	Now load the camera.
-		 */
-		qcam->brightness = p->brightness >> 8;
-		qcam->contrast = p->contrast >> 8;
-		qcam->whitebal = p->whiteness >> 8;
-
-		mutex_lock(&qcam->lock);
+	if (ret == 0) {
 		parport_claim_or_block(qcam->pdev);
 		qc_setup(qcam);
 		parport_release(qcam->pdev);
-		mutex_unlock(&qcam->lock);
-		return 0;
 	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *vw = arg;
-
-		if (vw->flags)
-			return -EINVAL;
-		if (vw->clipcount)
-			return -EINVAL;
-		if (vw->height < 60 || vw->height > 240)
-			return -EINVAL;
-		if (vw->width < 80 || vw->width > 320)
-			return -EINVAL;
-
-		qcam->width = 80;
-		qcam->height = 60;
-		qcam->mode = QC_DECIMATION_4;
+	mutex_unlock(&qcam->lock);
+	return ret;
+}
 
-		if (vw->width >= 160 && vw->height >= 120) {
-			qcam->width = 160;
-			qcam->height = 120;
-			qcam->mode = QC_DECIMATION_2;
-		}
-		if (vw->width >= 320 && vw->height >= 240) {
-			qcam->width = 320;
-			qcam->height = 240;
-			qcam->mode = QC_DECIMATION_1;
-		}
-		qcam->mode |= QC_MILLIONS;
-#if 0
-		if (vw->width >= 640 && vw->height >= 480) {
-			qcam->width = 640;
-			qcam->height = 480;
-			qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
-		}
-#endif
-		/* Ok we figured out what to use from our
-		   wide choice */
-		mutex_lock(&qcam->lock);
-		parport_claim_or_block(qcam->pdev);
-		qc_setup(qcam);
-		parport_release(qcam->pdev);
-		mutex_unlock(&qcam->lock);
-		return 0;
-	}
-	case VIDIOCGWIN:
-	{
-		struct video_window *vw = arg;
-		memset(vw, 0, sizeof(*vw));
-		vw->width = qcam->width;
-		vw->height = qcam->height;
-		return 0;
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	pix->width = qcam->width;
+	pix->height = qcam->height;
+	pix->pixelformat = V4L2_PIX_FMT_RGB24;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 3 * qcam->width;
+	pix->sizeimage = 3 * qcam->width * qcam->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+	if (pix->height < 60 || pix->width < 80) {
+		pix->height = 60;
+		pix->width = 80;
+	} else if (pix->height < 120 || pix->width < 160) {
+		pix->height = 120;
+		pix->width = 160;
+	} else {
+		pix->height = 240;
+		pix->width = 320;
 	}
-	case VIDIOCKEY:
-		return 0;
-	case VIDIOCCAPTURE:
-	case VIDIOCGFBUF:
-	case VIDIOCSFBUF:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return -EINVAL;
+	pix->pixelformat = V4L2_PIX_FMT_RGB24;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 3 * pix->width;
+	pix->sizeimage = 3 * pix->width * pix->height;
+	/* Just a guess */
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct qcam *qcam = video_drvdata(file);
+	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	switch (pix->height) {
+	case 60:
+		qcam->mode = QC_DECIMATION_4;
+		break;
+	case 120:
+		qcam->mode = QC_DECIMATION_2;
+		break;
 	default:
-		return -ENOIOCTLCMD;
+		qcam->mode = QC_DECIMATION_1;
+		break;
 	}
+
+	mutex_lock(&qcam->lock);
+	qcam->mode |= QC_MILLIONS;
+	qcam->height = pix->height;
+	qcam->width = pix->width;
+	parport_claim_or_block(qcam->pdev);
+	qc_setup(qcam);
+	parport_release(qcam->pdev);
+	mutex_unlock(&qcam->lock);
 	return 0;
 }
 
-static long qcam_ioctl(struct file *file,
-		      unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
 {
-	return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+	static struct v4l2_fmtdesc formats[] = {
+		{ 0, 0, 0,
+		  "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
+		  { 0, 0, 0, 0 }
+		},
+	};
+	enum v4l2_buf_type type = fmt->type;
+
+	if (fmt->index > 0)
+		return -EINVAL;
+
+	*fmt = formats[fmt->index];
+	fmt->type = type;
+	return 0;
 }
 
 static ssize_t qcam_read(struct file *file, char __user *buf,
 			 size_t count, loff_t *ppos)
 {
-	struct video_device *v = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)v;
+	struct qcam *qcam = video_drvdata(file);
 	int len;
 
 	mutex_lock(&qcam->lock);
@@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 	return len;
 }
 
-static int qcam_exclusive_open(struct file *file)
-{
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
-
-	return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
-}
-
-static int qcam_exclusive_release(struct file *file)
-{
-	struct video_device *dev = video_devdata(file);
-	struct qcam_device *qcam = (struct qcam_device *)dev;
-
-	clear_bit(0, &qcam->in_use);
-	return 0;
-}
-
-/* video device template */
 static const struct v4l2_file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
-	.open           = qcam_exclusive_open,
-	.release        = qcam_exclusive_release,
-	.ioctl          = qcam_ioctl,
+	.ioctl		= video_ioctl2,
 	.read		= qcam_read,
 };
 
-static struct video_device qcam_template = {
-	.name		= "Colour QuickCam",
-	.fops           = &qcam_fops,
-	.release 	= video_device_release_empty,
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+	.vidioc_querycap    		    = qcam_querycap,
+	.vidioc_g_input      		    = qcam_g_input,
+	.vidioc_s_input      		    = qcam_s_input,
+	.vidioc_enum_input   		    = qcam_enum_input,
+	.vidioc_queryctrl 		    = qcam_queryctrl,
+	.vidioc_g_ctrl  		    = qcam_g_ctrl,
+	.vidioc_s_ctrl 			    = qcam_s_ctrl,
+	.vidioc_enum_fmt_vid_cap 	    = qcam_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap 		    = qcam_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap  		    = qcam_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  	    = qcam_try_fmt_vid_cap,
 };
 
 /* Initialize the QuickCam driver control structure. */
 
-static struct qcam_device *qcam_init(struct parport *port)
+static struct qcam *qcam_init(struct parport *port)
 {
-	struct qcam_device *q;
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
 
-	q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
-	if (q == NULL)
+	qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
+	if (qcam == NULL)
 		return NULL;
 
-	q->pport = port;
-	q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
+	v4l2_dev = &qcam->v4l2_dev;
+	strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
+
+	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		return NULL;
+	}
+
+	qcam->pport = port;
+	qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
 					  NULL, 0, NULL);
 
-	q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
+	qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
 
-	if (q->pdev == NULL) {
-		printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
-		       port->name);
-		kfree(q);
+	if (qcam->pdev == NULL) {
+		v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+		kfree(qcam);
 		return NULL;
 	}
 
-	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
-	mutex_init(&q->lock);
-	q->width = q->ccd_width = 320;
-	q->height = q->ccd_height = 240;
-	q->mode = QC_MILLIONS | QC_DECIMATION_1;
-	q->contrast = 192;
-	q->brightness = 240;
-	q->whitebal = 128;
-	q->top = 1;
-	q->left = 14;
-	return q;
+	strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
+	qcam->vdev.v4l2_dev = v4l2_dev;
+	qcam->vdev.fops = &qcam_fops;
+	qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+	qcam->vdev.release = video_device_release_empty;
+	video_set_drvdata(&qcam->vdev, qcam);
+
+	mutex_init(&qcam->lock);
+	qcam->width = qcam->ccd_width = 320;
+	qcam->height = qcam->ccd_height = 240;
+	qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
+	qcam->contrast = 192;
+	qcam->brightness = 240;
+	qcam->whitebal = 128;
+	qcam->top = 1;
+	qcam->left = 14;
+	return qcam;
 }
 
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
-
 static int init_cqcam(struct parport *port)
 {
-	struct qcam_device *qcam;
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
 
 	if (parport[0] != -1) {
 		/* The user gave specific instructions */
@@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port)
 	if (qcam == NULL)
 		return -ENODEV;
 
+	v4l2_dev = &qcam->v4l2_dev;
+
 	parport_claim_or_block(qcam->pdev);
 
 	qc_reset(qcam);
@@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port)
 	parport_release(qcam->pdev);
 
 	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
-		printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
+		v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
 		       qcam->pport->name);
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
 		return -ENODEV;
 	}
 
-	printk(KERN_INFO "%s: Colour QuickCam found on %s\n",
+	v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
 	       video_device_node_name(&qcam->vdev), qcam->pport->name);
 
 	qcams[num_cams++] = qcam;
@@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port)
 	return 0;
 }
 
-static void close_cqcam(struct qcam_device *qcam)
+static void close_cqcam(struct qcam *qcam)
 {
 	video_unregister_device(&qcam->vdev);
 	parport_unregister_device(qcam->pdev);
@@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = {
 
 static int __init cqcam_init(void)
 {
-	printk(BANNER "\n");
+	printk(KERN_INFO BANNER "\n");
 
 	return parport_register_driver(&cqcam_driver);
 }
@@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
 MODULE_DESCRIPTION(BANNER);
 MODULE_LICENSE("GPL");
 
-/* FIXME: parport=auto would never have worked, surely? --RR */
-MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
-			  "probe=<0|1|2> for camera detection method\n"
-			  "force_rgb=<0|1> for RGB data format (default BGR)");
-module_param_array(parport, int, NULL, 0);
-module_param(probe, int, 0);
-module_param(force_rgb, bool, 0);
-module_param(video_nr, int, 0);
-
 module_init(cqcam_init);
 module_exit(cqcam_cleanup);

+ 1 - 1
drivers/media/video/cx18/cx18-alsa-main.c

@@ -1,7 +1,7 @@
 /*
  *  ALSA interface to cx18 PCM capture streams
  *
- *  Copyright (C) 2009  Andy Walls <awalls@radix.net>
+ *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
  *  Copyright (C) 2009  Devin Heitmueller <dheitmueller@kernellabs.com>
  *
  *  Portions of this work were sponsored by ONELAN Limited.

Some files were not shown because too many files changed in this diff