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>
 </contrib>
 	<affiliation>
 	<affiliation>
 	  <address>
 	  <address>
-	    <email>awalls@radix.net</email>
+	    <email>awalls@md.metrocast.net</email>
 	  </address>
 	  </address>
 	</affiliation>
 	</affiliation>
       </author>
       </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
 automatically, similar to sensing the video standard. To do so, applications
 call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
 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
 &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>
 
 
   <refsect1>
   <refsect1>

+ 152 - 0
Documentation/edac.txt

@@ -6,6 +6,8 @@ Written by Doug Thompson <dougthompson@xmission.com>
 7 Dec 2005
 7 Dec 2005
 17 Jul 2007	Updated
 17 Jul 2007	Updated
 
 
+(c) Mauro Carvalho Chehab <mchehab@redhat.com>
+05 Aug 2009	Nehalem interface
 
 
 EDAC is maintained and written by:
 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
 The 'test_device_edac' sample driver is located at the
 bluesmoke.sourceforge.net project site for EDAC.
 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]
 175 -> Leadtek Winfast DTV1000S                 [107d:6655]
 176 -> Beholder BeholdTV 505 RDS                [0000:5051]
 176 -> Beholder BeholdTV 505 RDS                [0000:5051]
 177 -> Hawell HW-404M7
 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:6040	Speed NVC 350K
 sonixj		0c45:607c	Sonix sn9c102p Hv7131R
 sonixj		0c45:607c	Sonix sn9c102p Hv7131R
 sonixj		0c45:60c0	Sangha Sn535
 sonixj		0c45:60c0	Sangha Sn535
+sonixj		0c45:60ce	USB-PC-Camera-168 (TALK-5067)
 sonixj		0c45:60ec	SN9C105+MO4000
 sonixj		0c45:60ec	SN9C105+MO4000
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fc	LG-LIC300
 sonixj		0c45:60fc	LG-LIC300

+ 2 - 2
MAINTAINERS

@@ -1731,7 +1731,7 @@ S:	Maintained
 F:	sound/pci/cs5535audio/
 F:	sound/pci/cs5535audio/
 
 
 CX18 VIDEO4LINUX DRIVER
 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:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 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
 F:	drivers/hwmon/it87.c
 
 
 IVTV VIDEO4LINUX DRIVER
 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:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 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:
  out_of_memory:
 	up_read(&mm->mmap_sem);
 	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:
  do_sigbus:
 	up_read(&mm->mmap_sem);
 	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))
 	if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC))
 	  goto bad_area;
 	  goto bad_area;
 
 
-survive:
 	/*
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * make sure we exit gracefully rather than endlessly redo
@@ -271,15 +270,10 @@ no_context:
  */
  */
 out_of_memory:
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	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:
 do_sigbus:
 	up_read(&mm->mmap_sem);
 	up_read(&mm->mmap_sem);

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

@@ -338,11 +338,10 @@ no_context:
  */
  */
 out_of_memory:
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	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:
 do_sigbus:
 	up_read(&mm->mmap_sem);
 	up_read(&mm->mmap_sem);

+ 15 - 1
arch/sh/Kconfig

@@ -9,7 +9,7 @@ config SUPERH
 	def_bool y
 	def_bool y
 	select EMBEDDED
 	select EMBEDDED
 	select HAVE_CLK
 	select HAVE_CLK
-	select HAVE_IDE
+	select HAVE_IDE if HAS_IOPORT
 	select HAVE_LMB
 	select HAVE_LMB
 	select HAVE_OPROFILE
 	select HAVE_OPROFILE
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_GENERIC_DMA_COHERENT
@@ -174,6 +174,9 @@ config ARCH_HAS_DEFAULT_IDLE
 config ARCH_HAS_CPU_IDLE_WAIT
 config ARCH_HAS_CPU_IDLE_WAIT
 	def_bool y
 	def_bool y
 
 
+config NO_IOPORT
+	bool
+
 config IO_TRAPPED
 config IO_TRAPPED
 	bool
 	bool
 
 
@@ -776,6 +779,17 @@ config ENTRY_OFFSET
 	default "0x00010000" if PAGE_SIZE_64KB
 	default "0x00010000" if PAGE_SIZE_64KB
 	default "0x00000000"
 	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
 choice
 	prompt "Kernel command line"
 	prompt "Kernel command line"
 	optional
 	optional

+ 3 - 0
arch/sh/boards/Kconfig

@@ -154,6 +154,7 @@ config SH_SDK7786
 	bool "SDK7786"
 	bool "SDK7786"
 	depends on CPU_SUBTYPE_SH7786
 	depends on CPU_SUBTYPE_SH7786
 	select SYS_SUPPORTS_PCI
 	select SYS_SUPPORTS_PCI
+	select NO_IOPORT if !PCI
 	help
 	help
 	  Select SDK7786 if configuring for a Renesas Technology Europe
 	  Select SDK7786 if configuring for a Renesas Technology Europe
 	  SH7786-65nm board.
 	  SH7786-65nm board.
@@ -190,6 +191,7 @@ config SH_URQUELL
 	depends on CPU_SUBTYPE_SH7786
 	depends on CPU_SUBTYPE_SH7786
 	select ARCH_REQUIRE_GPIOLIB
 	select ARCH_REQUIRE_GPIOLIB
 	select SYS_SUPPORTS_PCI
 	select SYS_SUPPORTS_PCI
+	select NO_IOPORT if !PCI
 
 
 config SH_MIGOR
 config SH_MIGOR
 	bool "Migo-R"
 	bool "Migo-R"
@@ -286,6 +288,7 @@ config SH_LBOX_RE2
 config SH_X3PROTO
 config SH_X3PROTO
 	bool "SH-X3 Prototype board"
 	bool "SH-X3 Prototype board"
 	depends on CPU_SUBTYPE_SHX3
 	depends on CPU_SUBTYPE_SHX3
+	select NO_IOPORT if !PCI
 
 
 config SH_MAGIC_PANEL_R2
 config SH_MAGIC_PANEL_R2
 	bool "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,
 	.set_capture = camera_set_capture,
 };
 };
 
 
-struct soc_camera_link camera_link = {
+static struct soc_camera_link camera_link = {
 	.bus_id		= 0,
 	.bus_id		= 0,
 	.add_device	= ap325rxa_camera_add,
 	.add_device	= ap325rxa_camera_add,
 	.del_device	= ap325rxa_camera_del,
 	.del_device	= ap325rxa_camera_del,

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

@@ -12,6 +12,8 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/sh_mobile_sdhi.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/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
@@ -26,7 +28,6 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/input/sh_keysc.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mobile_lcdc.h>
 #include <sound/sh_fsi.h>
 #include <sound/sh_fsi.h>
 #include <media/sh_mobile_ceu.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 */
 	.phy = 0x1f, /* SMSC LAN8700 */
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 	.ether_link_active_low = 1
 	.ether_link_active_low = 1
@@ -159,7 +160,7 @@ static struct platform_device sh_eth_device = {
 };
 };
 
 
 /* USB0 host */
 /* 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);
 	gpio_set_value(GPIO_PTB4, power);
 }
 }
@@ -195,7 +196,7 @@ static struct platform_device usb0_host_device = {
 };
 };
 
 
 /* USB1 host/function */
 /* 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);
 	gpio_set_value(GPIO_PTB5, power);
 }
 }
@@ -421,7 +422,7 @@ static int ts_init(void)
 	return 0;
 	return 0;
 }
 }
 
 
-struct tsc2007_platform_data tsc2007_info = {
+static struct tsc2007_platform_data tsc2007_info = {
 	.model			= 2007,
 	.model			= 2007,
 	.x_plate_ohms		= 180,
 	.x_plate_ohms		= 180,
 	.get_pendown_state	= ts_get_pendown_state,
 	.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
 #ifdef CONFIG_MFD_SH_MOBILE_SDHI
-/* SHDI0 */
+/* SDHI0 */
 static void sdhi0_set_pwr(struct platform_device *pdev, int state)
 static void sdhi0_set_pwr(struct platform_device *pdev, int state)
 {
 {
 	gpio_set_value(GPIO_PTB6, 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)
 static void sdhi1_set_pwr(struct platform_device *pdev, int state)
 {
 {
 	gpio_set_value(GPIO_PTB7, state);
 	gpio_set_value(GPIO_PTB7, state);
@@ -511,6 +513,7 @@ static struct platform_device sdhi1_device = {
 		.hwblk_id = HWBLK_SDHI1,
 		.hwblk_id = HWBLK_SDHI1,
 	},
 	},
 };
 };
+#endif /* CONFIG_MMC_SH_MMCIF */
 
 
 #else
 #else
 
 
@@ -720,7 +723,7 @@ static struct clk fsimckb_clk = {
 	.rate		= 0, /* unknown */
 	.rate		= 0, /* unknown */
 };
 };
 
 
-struct sh_fsi_platform_info fsi_info = {
+static struct sh_fsi_platform_info fsi_info = {
 	.portb_flags = SH_FSI_BRS_INV |
 	.portb_flags = SH_FSI_BRS_INV |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_IN_SLAVE_MODE |
 		       SH_FSI_IN_SLAVE_MODE |
@@ -777,7 +780,7 @@ static struct platform_device irda_device = {
 #include <media/ak881x.h>
 #include <media/ak881x.h>
 #include <media/sh_vou.h>
 #include <media/sh_vou.h>
 
 
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
 	.flags = AK881X_IF_MODE_SLAVE,
 	.flags = AK881X_IF_MODE_SLAVE,
 };
 };
 
 
@@ -786,7 +789,7 @@ static struct i2c_board_info ak8813 = {
 	.platform_data = &ak881x_pdata,
 	.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,
 	.bus_fmt	= SH_VOU_BUS_8BIT,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,
 	.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 = {
 static struct platform_device *ecovec_devices[] __initdata = {
 	&heartbeat_device,
 	&heartbeat_device,
 	&nor_flash_device,
 	&nor_flash_device,
@@ -831,7 +886,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
 	&keysc_device,
 	&keysc_device,
 #ifdef CONFIG_MFD_SH_MOBILE_SDHI
 #ifdef CONFIG_MFD_SH_MOBILE_SDHI
 	&sdhi0_device,
 	&sdhi0_device,
+#if !defined(CONFIG_MMC_SH_MMCIF)
 	&sdhi1_device,
 	&sdhi1_device,
+#endif
 #else
 #else
 	&msiof0_device,
 	&msiof0_device,
 #endif
 #endif
@@ -841,6 +898,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
 	&fsi_device,
 	&fsi_device,
 	&irda_device,
 	&irda_device,
 	&vou_device,
 	&vou_device,
+#if defined(CONFIG_MMC_SH_MMCIF)
+	&sh_mmcif_device,
+#endif
 };
 };
 
 
 #ifdef CONFIG_I2C
 #ifdef CONFIG_I2C
@@ -1134,6 +1194,7 @@ static int __init arch_setup(void)
 	gpio_request(GPIO_PTB6, NULL);
 	gpio_request(GPIO_PTB6, NULL);
 	gpio_direction_output(GPIO_PTB6, 0);
 	gpio_direction_output(GPIO_PTB6, 0);
 
 
+#if !defined(CONFIG_MMC_SH_MMCIF)
 	/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
 	/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
 	gpio_request(GPIO_FN_SDHI1CD,  NULL);
 	gpio_request(GPIO_FN_SDHI1CD,  NULL);
 	gpio_request(GPIO_FN_SDHI1WP,  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 */
 	/* I/O buffer drive ability is high for SDHI1 */
 	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
 	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+#endif /* CONFIG_MMC_SH_MMCIF */
 #else
 #else
 	/* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */
 	/* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */
 	gpio_request(GPIO_FN_MSIOF0_TXD, NULL);
 	gpio_request(GPIO_FN_MSIOF0_TXD, NULL);
@@ -1223,6 +1285,25 @@ static int __init arch_setup(void)
 	gpio_request(GPIO_PTU5, NULL);
 	gpio_request(GPIO_PTU5, NULL);
 	gpio_direction_output(GPIO_PTU5, 0);
 	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 */
 	/* enable I2C device */
 	i2c_register_board_info(0, i2c0_devices,
 	i2c_register_board_info(0, i2c0_devices,
 				ARRAY_SIZE(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 */
 	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 = {
 	.chip = {
 		.nr_chips = 1,
 		.nr_chips = 1,
 		.partitions = migor_nand_flash_partitions,
 		.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 */
 /* 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 |
 	.porta_flags = SH_FSI_BRS_INV |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_OUT_SLAVE_MODE |
 		       SH_FSI_IN_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 */
 	.phy = 0x1f, /* SMSC LAN8187 */
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 	.edmac_endian = EDMAC_LITTLE_ENDIAN,
 };
 };
@@ -535,7 +535,7 @@ static struct platform_device irda_device = {
 #include <media/ak881x.h>
 #include <media/ak881x.h>
 #include <media/sh_vou.h>
 #include <media/sh_vou.h>
 
 
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
 	.flags = AK881X_IF_MODE_SLAVE,
 	.flags = AK881X_IF_MODE_SLAVE,
 };
 };
 
 
@@ -545,7 +545,7 @@ static struct i2c_board_info ak8813 = {
 	.platform_data = &ak881x_pdata,
 	.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,
 	.bus_fmt	= SH_VOU_BUS_8BIT,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,
 	.board_info	= &ak8813,

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

@@ -1,16 +1,21 @@
 #
 #
 # linux/arch/sh/boot/romimage/Makefile
 # 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
 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
 		   -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)
 	$(call if_changed,ld)
 	@:
 	@:
 
 

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

@@ -12,8 +12,40 @@ romstart:
 	/* include board specific setup code */
 	/* include board specific setup code */
 #include <mach/romimage.h>
 #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 */
 	/* 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.l	empty_zero_page_dst, r1
 	mov	#(PAGE_SHIFT - 4), r4
 	mov	#(PAGE_SHIFT - 4), r4
 	mov	#1, r3
 	mov	#1, r3
@@ -37,7 +69,9 @@ romstart:
 	mov	#PAGE_SHIFT, r4
 	mov	#PAGE_SHIFT, r4
 	mov	#1, r1
 	mov	#1, r1
 	shld	r4, 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
 	add	r1, r0
 	jmp	@r0
 	jmp	@r0
 	 nop
 	 nop
@@ -45,4 +79,6 @@ romstart:
 	.align 2
 	.align 2
 empty_zero_page_dst:
 empty_zero_page_dst:
 	.long	_text
 	.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
 SECTIONS
 {
 {
   .text : {
   .text : {
+	zero_page_pos = .;
 	*(.data)
 	*(.data)
+	end_data = .;
 	}
 	}
 }
 }

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

@@ -39,6 +39,8 @@
 #include <asm/io_generic.h>
 #include <asm/io_generic.h>
 #include <asm/io_trapped.h>
 #include <asm/io_trapped.h>
 
 
+#ifdef CONFIG_HAS_IOPORT
+
 #define inb(p)			sh_mv.mv_inb((p))
 #define inb(p)			sh_mv.mv_inb((p))
 #define inw(p)			sh_mv.mv_inw((p))
 #define inw(p)			sh_mv.mv_inw((p))
 #define inl(p)			sh_mv.mv_inl((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 outsw(p,b,c)		sh_mv.mv_outsw((p), (b), (c))
 #define outsl(p,b,c)		sh_mv.mv_outsl((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_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_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))
 #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
 #define IO_SPACE_LIMIT 0xffffffff
 
 
+#ifdef CONFIG_HAS_IOPORT
+
 /*
 /*
  * This function provides a method for the generic case where a
  * This function provides a method for the generic case where a
  * board-specific ioport_map simply needs to return the port + some
  * 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))
 #define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n))
 
 
+#endif
+
 /* We really want to try and get these to memcpy etc */
 /* We really want to try and get these to memcpy etc */
 void memcpy_fromio(void *, const volatile void __iomem *, unsigned long);
 void memcpy_fromio(void *, const volatile void __iomem *, unsigned long);
 void memcpy_toio(volatile void __iomem *, const void *, 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;
 	const char *mv_name;
 	int mv_nr_irqs;
 	int mv_nr_irqs;
 
 
+	int (*mv_irq_demux)(int irq);
+	void (*mv_init_irq)(void);
+
+#ifdef CONFIG_HAS_IOPORT
 	u8 (*mv_inb)(unsigned long);
 	u8 (*mv_inb)(unsigned long);
 	u16 (*mv_inw)(unsigned long);
 	u16 (*mv_inw)(unsigned long);
 	u32 (*mv_inl)(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_outsw)(unsigned long, const void *src, unsigned long count);
 	void (*mv_outsl)(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 __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
 	void (*mv_ioport_unmap)(void __iomem *);
 	void (*mv_ioport_unmap)(void __iomem *);
+#endif
 
 
 	int (*mv_clk_init)(void);
 	int (*mv_clk_init)(void);
 	int (*mv_mode_pins)(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]
  * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
  * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
  * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
  * MD8: Test Mode
  * MD8: Test Mode
+ * BOOT: FBR - Boot Mode (L: MMCIF, H: Area0)
  */
  */
 
 
 /* Pin Function Controller:
 /* Pin Function Controller:

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

@@ -1 +1,11 @@
+#ifdef __ASSEMBLY__
+
 /* do nothing here by default */
 /* 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:
 /* EcoVec board specific boot code:
  * converts the "partner-jet-script.txt" script into assembly
  * converts the "partner-jet-script.txt" script into assembly
  * the assembly code is the first code to be executed in the romImage
  * the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,28 @@
 	.align 2
 	.align 2
 1 :	.long 0xa8000000
 1 :	.long 0xa8000000
 2 :
 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:
 /* kfr2r09 board specific boot code:
  * converts the "partner-jet-script.txt" script into assembly
  * converts the "partner-jet-script.txt" script into assembly
  * the assembly code is the first code to be executed in the romImage
  * the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,11 @@
 	.align 2
 	.align 2
 1:	.long 0xa8000000
 1:	.long 0xa8000000
 2:
 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
 CFLAGS_REMOVE_return_address.o = -pg
 
 
 obj-y	:= clkdev.o debugtraps.o dma-nommu.o dumpstack.o 		\
 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		\
 	   irq_$(BITS).o machvec.o nmi_debug.o process.o		\
 	   process_$(BITS).o ptrace_$(BITS).o				\
 	   process_$(BITS).o ptrace_$(BITS).o				\
 	   reboot.o return_address.o					\
 	   reboot.o return_address.o					\
@@ -39,6 +39,7 @@ obj-$(CONFIG_DUMP_CODE)		+= disassemble.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o
 obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
 obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.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_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)	+= localtimer.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 struct dwarf_cie *cached_cie;
 
 
+static unsigned int dwarf_unwinder_ready;
+
 /**
 /**
  *	dwarf_frame_alloc_reg - allocate memory for a DWARF register
  *	dwarf_frame_alloc_reg - allocate memory for a DWARF register
  *	@frame: the DWARF frame whose list of registers we insert on
  *	@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;
 	struct dwarf_reg *reg;
 	unsigned long addr;
 	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
 	 * 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
 	 * 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)
 static int __init dwarf_unwinder_init(void)
 {
 {
-	int err;
+	int err = -ENOMEM;
 
 
 	dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
 	dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
 			sizeof(struct dwarf_frame), 0,
 			sizeof(struct dwarf_frame), 0,
@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void)
 					  mempool_alloc_slab,
 					  mempool_alloc_slab,
 					  mempool_free_slab,
 					  mempool_free_slab,
 					  dwarf_frame_cachep);
 					  dwarf_frame_cachep);
+	if (!dwarf_frame_pool)
+		goto out;
 
 
 	dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
 	dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
 					 mempool_alloc_slab,
 					 mempool_alloc_slab,
 					 mempool_free_slab,
 					 mempool_free_slab,
 					 dwarf_reg_cachep);
 					 dwarf_reg_cachep);
+	if (!dwarf_reg_pool)
+		goto out;
 
 
 	err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
 	err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
 	if (err)
 	if (err)
@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void)
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
+	dwarf_unwinder_ready = 1;
+
 	return 0;
 	return 0;
 
 
 out:
 out:
 	printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
 	printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
 	dwarf_unwinder_cleanup();
 	dwarf_unwinder_cleanup();
-	return -EINVAL;
+	return err;
 }
 }
 early_initcall(dwarf_unwinder_init);
 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);
 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)
 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;
 	tiop->magic = IO_TRAPPED_MAGIC;
 	INIT_LIST_HEAD(&tiop->list);
 	INIT_LIST_HEAD(&tiop->list);
 	spin_lock_irq(&trapped_lock);
 	spin_lock_irq(&trapped_lock);
+#ifdef CONFIG_HAS_IOPORT
 	if (flags & IORESOURCE_IO)
 	if (flags & IORESOURCE_IO)
 		list_add(&tiop->list, &trapped_io);
 		list_add(&tiop->list, &trapped_io);
+#endif
+#ifdef CONFIG_HAS_IOMEM
 	if (flags & IORESOURCE_MEM)
 	if (flags & IORESOURCE_MEM)
 		list_add(&tiop->list, &trapped_mem);
 		list_add(&tiop->list, &trapped_mem);
+#endif
 	spin_unlock_irq(&trapped_lock);
 	spin_unlock_irq(&trapped_lock);
 
 
 	return 0;
 	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; \
 		sh_mv.mv_##elem = generic_##elem; \
 } while (0)
 } 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(inb);	mv_set(inw);	mv_set(inl);
 	mv_set(outb);	mv_set(outw);	mv_set(outl);
 	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_map);
 	mv_set(ioport_unmap);
 	mv_set(ioport_unmap);
+
+#endif
+
 	mv_set(irq_demux);
 	mv_set(irq_demux);
 	mv_set(mode_pins);
 	mv_set(mode_pins);
 	mv_set(mem_init);
 	mv_set(mem_init);
 
 
 	if (!sh_mv.mv_nr_irqs)
 	if (!sh_mv.mv_nr_irqs)
 		sh_mv.mv_nr_irqs = 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;
 		struct dwarf_frame *tmp;
 
 
 		tmp = dwarf_unwind_stack(ra, frame);
 		tmp = dwarf_unwind_stack(ra, frame);
+		if (!tmp)
+			return NULL;
 
 
 		if (frame)
 		if (frame)
 			dwarf_free_frame(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;
 	current->thread.fault_catcher = NULL;
 
 
-	kunmap_atomic(page, KM_UML_USERCOPY);
+	kunmap_atomic((void *)addr, KM_UML_USERCOPY);
 
 
 	return n;
 	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_bus *pci_root_bus;
 extern struct pci_ops pci_root_ops;
 extern struct pci_ops pci_root_ops;
 
 
+void pcibios_scan_specific_bus(int busn);
+
 /* pci-irq.c */
 /* pci-irq.c */
 
 
 struct irq_info {
 struct irq_info {

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

@@ -36,6 +36,7 @@
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
+#include <linux/edac_mce.h>
 
 
 #include <asm/processor.h>
 #include <asm/processor.h>
 #include <asm/hw_irq.h>
 #include <asm/hw_irq.h>
@@ -168,6 +169,15 @@ void mce_log(struct mce *mce)
 	for (;;) {
 	for (;;) {
 		entry = rcu_dereference_check_mce(mcelog.next);
 		entry = rcu_dereference_check_mce(mcelog.next);
 		for (;;) {
 		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.
 			 * When the buffer fills up discard new entries.
 			 * Assume that the earlier errors are the more
 			 * 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)
 static void __devinit pcibios_fixup_peer_bridges(void)
 {
 {
-	int n, devfn;
-	long node;
+	int n;
 
 
 	if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
 	if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
 		return;
 		return;
 	DBG("PCI: Peer bridge fixup\n");
 	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)
 int __init pci_legacy_init(void)
@@ -50,6 +36,28 @@ int __init pci_legacy_init(void)
 	return 0;
 	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)
 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
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 * the fault.
 	 */
 	 */
-survive:
 	fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
 	fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		if (fault & VM_FAULT_OOM)
 		if (fault & VM_FAULT_OOM)
@@ -146,15 +145,10 @@ bad_area:
 	 */
 	 */
 out_of_memory:
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	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;
 	return;
 
 
 do_sigbus:
 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;
 	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->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
 	rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
 	rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
 	rl->elvpriv = 0;
 	rl->elvpriv = 0;
@@ -570,9 +573,17 @@ EXPORT_SYMBOL(blk_init_queue);
 struct request_queue *
 struct request_queue *
 blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 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);
 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;
 		return NULL;
 
 
 	q->node = node_id;
 	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;
 		return NULL;
-	}
 
 
 	q->request_fn		= rfn;
 	q->request_fn		= rfn;
 	q->prep_rq_fn		= NULL;
 	q->prep_rq_fn		= NULL;
@@ -618,7 +627,6 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
 		return q;
 		return q;
 	}
 	}
 
 
-	blk_put_queue(q);
 	return NULL;
 	return NULL;
 }
 }
 EXPORT_SYMBOL(blk_init_allocated_queue_node);
 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 struct completion *ioc_gone;
 static DEFINE_SPINLOCK(ioc_gone_lock);
 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_PRIO_LISTS		IOPRIO_BE_NR
 #define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
 #define cfq_class_idle(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
 #define cfq_class_rt(cfqq)	((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
 #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_latency;
 	unsigned int cfq_group_isolation;
 	unsigned int cfq_group_isolation;
 
 
+	unsigned int cic_index;
 	struct list_head cic_list;
 	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;
 	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
  * 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).
  * 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)
 static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic)
 {
 {
 	unsigned long flags;
 	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);
 	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);
 	hlist_del_rcu(&cic->cic_list);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 	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);
 	__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;
 	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
 	 * If this queue was scheduled to merge with another queue, be
 	 * sure to drop the reference taken on that queue (and others in
 	 * 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);
 		cfq_put_queue(__cfqq);
 		__cfqq = next;
 		__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);
 	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);
 	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();
 	smp_wmb();
-	cic->dead_key = (unsigned long) cic->key;
-	cic->key = NULL;
+	cic->key = cfqd_dead_key(cfqd);
 
 
 	if (ioc->ioc_data == cic)
 	if (ioc->ioc_data == cic)
 		rcu_assign_pointer(ioc->ioc_data, NULL);
 		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,
 static void cfq_exit_single_io_context(struct io_context *ioc,
 				       struct cfq_io_context *cic)
 				       struct cfq_io_context *cic)
 {
 {
-	struct cfq_data *cfqd = cic->key;
+	struct cfq_data *cfqd = cic_to_cfqd(cic);
 
 
 	if (cfqd) {
 	if (cfqd) {
 		struct request_queue *q = cfqd->queue;
 		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
 		 * race between exiting task and queue
 		 */
 		 */
 		smp_read_barrier_depends();
 		smp_read_barrier_depends();
-		if (cic->key)
+		if (cic->key == cfqd)
 			__cfq_exit_single_io_context(cfqd, cic);
 			__cfq_exit_single_io_context(cfqd, cic);
 
 
 		spin_unlock_irqrestore(q->queue_lock, flags);
 		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)
 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;
 	struct cfq_queue *cfqq;
 	unsigned long flags;
 	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)
 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_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;
 	unsigned long flags;
 	struct request_queue *q;
 	struct request_queue *q;
 
 
@@ -2883,12 +2910,13 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
 	unsigned long flags;
 	unsigned long flags;
 
 
 	WARN_ON(!list_empty(&cic->queue_list));
 	WARN_ON(!list_empty(&cic->queue_list));
+	BUG_ON(cic->key != cfqd_dead_key(cfqd));
 
 
 	spin_lock_irqsave(&ioc->lock, flags);
 	spin_lock_irqsave(&ioc->lock, flags);
 
 
 	BUG_ON(ioc->ioc_data == cic);
 	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);
 	hlist_del_rcu(&cic->cic_list);
 	spin_unlock_irqrestore(&ioc->lock, flags);
 	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;
 	struct cfq_io_context *cic;
 	unsigned long flags;
 	unsigned long flags;
-	void *k;
 
 
 	if (unlikely(!ioc))
 	if (unlikely(!ioc))
 		return NULL;
 		return NULL;
@@ -2917,13 +2944,11 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
 	}
 	}
 
 
 	do {
 	do {
-		cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd);
+		cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index);
 		rcu_read_unlock();
 		rcu_read_unlock();
 		if (!cic)
 		if (!cic)
 			break;
 			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);
 			cfq_drop_dead_cic(cfqd, ioc, cic);
 			rcu_read_lock();
 			rcu_read_lock();
 			continue;
 			continue;
@@ -2956,7 +2981,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
 
 
 		spin_lock_irqsave(&ioc->lock, flags);
 		spin_lock_irqsave(&ioc->lock, flags);
 		ret = radix_tree_insert(&ioc->radix_root,
 		ret = radix_tree_insert(&ioc->radix_root,
-						(unsigned long) cfqd, cic);
+						cfqd->cic_index, cic);
 		if (!ret)
 		if (!ret)
 			hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list);
 			hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list);
 		spin_unlock_irqrestore(&ioc->lock, flags);
 		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);
 	cic_set_cfqq(cic, NULL, 1);
+
+	cfq_put_cooperator(cfqq);
+
 	cfq_put_queue(cfqq);
 	cfq_put_queue(cfqq);
 	return NULL;
 	return NULL;
 }
 }
@@ -3708,10 +3736,32 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
 
 	cfq_shutdown_timer_wq(cfqd);
 	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. */
 	/* Wait for cfqg->blkg->key accessors to exit their grace periods. */
 	call_rcu(&cfqd->rcu, cfq_cfqd_free);
 	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)
 static void *cfq_init_queue(struct request_queue *q)
 {
 {
 	struct cfq_data *cfqd;
 	struct cfq_data *cfqd;
@@ -3719,10 +3769,16 @@ static void *cfq_init_queue(struct request_queue *q)
 	struct cfq_group *cfqg;
 	struct cfq_group *cfqg;
 	struct cfq_rb_root *st;
 	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);
 	cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
 	if (!cfqd)
 	if (!cfqd)
 		return NULL;
 		return NULL;
 
 
+	cfqd->cic_index = i;
+
 	/* Init root service tree */
 	/* Init root service tree */
 	cfqd->grp_service_tree = CFQ_RB_ROOT;
 	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))
 	if (elv_ioc_count_read(cfq_ioc_count))
 		wait_for_completion(&all_gone);
 		wait_for_completion(&all_gone);
+	ida_destroy(&cic_index_ida);
 	cfq_slab_kill();
 	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_type *e = NULL;
 	struct elevator_queue *eq;
 	struct elevator_queue *eq;
-	int ret = 0;
 	void *data;
 	void *data;
 
 
+	if (unlikely(q->elevator))
+		return 0;
+
 	INIT_LIST_HEAD(&q->queue_head);
 	INIT_LIST_HEAD(&q->queue_head);
 	q->last_merge = NULL;
 	q->last_merge = NULL;
 	q->end_sector = 0;
 	q->end_sector = 0;
@@ -284,7 +286,7 @@ int elevator_init(struct request_queue *q, char *name)
 	}
 	}
 
 
 	elevator_attach(q, eq, data);
 	elevator_attach(q, eq, data);
-	return ret;
+	return 0;
 }
 }
 EXPORT_SYMBOL(elevator_init);
 EXPORT_SYMBOL(elevator_init);
 
 
@@ -1097,7 +1099,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
 	struct elevator_type *__e;
 	struct elevator_type *__e;
 	int len = 0;
 	int len = 0;
 
 
-	if (!q->elevator)
+	if (!q->elevator || !blk_queue_stackable(q))
 		return sprintf(name, "none\n");
 		return sprintf(name, "none\n");
 
 
 	elv = e->elevator_type;
 	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;
 	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
  * Free all backing store pages and radix tree. This must only be called when
  * there are no other users of the device.
  * 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;
 	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.
  * 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))
 						get_capacity(bdev->bd_disk))
 		goto out;
 		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);
 	rw = bio_rw(bio);
 	if (rw == READA)
 	if (rw == READA)
 		rw = READ;
 		rw = READ;
@@ -320,7 +366,7 @@ out:
 }
 }
 
 
 #ifdef CONFIG_BLK_DEV_XIP
 #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)
 			void **kaddr, unsigned long *pfn)
 {
 {
 	struct brd_device *brd = bdev->bd_disk->private_data;
 	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_max_hw_sectors(brd->brd_queue, 1024);
 	blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
 	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);
 	disk = brd->brd_disk = alloc_disk(1 << part_shift);
 	if (!disk)
 	if (!disk)
 		goto out_free_queue;
 		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;
 	sa = h->scsi_ctlr;
 	stk = &sa->cmd_stack; 
 	stk = &sa->cmd_stack; 
+	stk->top++;
 	if (stk->top >= CMD_STACK_SIZE) {
 	if (stk->top >= CMD_STACK_SIZE) {
 		printk("cciss: scsi_cmd_free called too many times.\n");
 		printk("cciss: scsi_cmd_free called too many times.\n");
 		BUG();
 		BUG();
 	}
 	}
-	stk->top++;
 	stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
 	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,
 	struct drbd_work  resync_work,
 			  unplug_work,
 			  unplug_work,
 			  md_sync_work,
 			  md_sync_work,
-			  delay_probe_work,
-			  uuid_work;
+			  delay_probe_work;
 	struct timer_list resync_timer;
 	struct timer_list resync_timer;
 	struct timer_list md_sync_timer;
 	struct timer_list md_sync_timer;
 	struct timer_list delay_probe_timer;
 	struct timer_list delay_probe_timer;
@@ -1069,7 +1068,6 @@ struct drbd_conf {
 	struct timeval dps_time; /* delay-probes-start-time */
 	struct timeval dps_time; /* delay-probes-start-time */
 	unsigned int dp_volume_last;  /* send_cnt of last delay probe */
 	unsigned int dp_volume_last;  /* send_cnt of last delay probe */
 	int c_sync_rate; /* current resync rate after delay_probe magic */
 	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)
 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_ov_finished(struct drbd_conf *, struct drbd_work *, int);
 extern int w_resync_inactive(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_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_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_make_resync_request(struct drbd_conf *, struct drbd_work *, int);
 extern int w_send_dblock(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)
 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,
 	(void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK,
 			(char __user *)&val, sizeof(val));
 			(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) {
 	switch (mdev->ldev->dc.on_io_error) {
 	case EP_PASS_ON:
 	case EP_PASS_ON:
 		if (!forcedetach) {
 		if (!forcedetach) {
-			if (printk_ratelimit())
+			if (__ratelimit(&drbd_ratelimit_state))
 				dev_err(DEV, "Local IO failed in %s."
 				dev_err(DEV, "Local IO failed in %s."
 					     "Passing error on...\n", where);
 					     "Passing error on...\n", where);
 			break;
 			break;
@@ -2219,8 +2216,6 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
 		return 0;
 		return 0;
 	if (test_bit(BITMAP_IO, &mdev->flags))
 	if (test_bit(BITMAP_IO, &mdev->flags))
 		return 0;
 		return 0;
-	if (atomic_read(&mdev->new_c_uuid))
-		return 0;
 	return 1;
 	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,
 	 * to avoid races with the reconnect code,
 	 * we need to atomic_inc within the spinlock. */
 	 * 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);
 	spin_lock_irq(&mdev->req_lock);
 	while (!__inc_ap_bio_cond(mdev)) {
 	while (!__inc_ap_bio_cond(mdev)) {
 		prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
 		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)) {
 	     ns.pdsk == D_OUTDATED)) {
 		if (get_ldev(mdev)) {
 		if (get_ldev(mdev)) {
 			if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
 			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);
 			put_ldev(mdev);
 		}
 		}
 	}
 	}
 
 
 	if (ns.pdsk < D_INCONSISTENT && get_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 */
 		/* D_DISKLESS Peer becomes secondary */
 		if (os.peer == R_PRIMARY && ns.peer == R_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);
 	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)
 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.
  * with page_count == 0 or PageSlab.
  */
  */
 static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
 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);
 	kunmap(page);
 	if (sent == size)
 	if (sent == size)
 		mdev->send_cnt += size>>9;
 		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,
 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();
 	mm_segment_t oldfs = get_fs();
 	int sent, ok;
 	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
 	 * __page_cache_release a page that would actually still be referenced
 	 * by someone, leading to some obscure delayed Oops somewhere else. */
 	 * by someone, leading to some obscure delayed Oops somewhere else. */
 	if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
 	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);
 	drbd_update_congested(mdev);
 	set_fs(KERNEL_DS);
 	set_fs(KERNEL_DS);
 	do {
 	do {
 		sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
 		sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
 							offset, len,
 							offset, len,
-							MSG_NOSIGNAL);
+							msg_flags);
 		if (sent == -EAGAIN) {
 		if (sent == -EAGAIN) {
 			if (we_should_drop_the_connection(mdev,
 			if (we_should_drop_the_connection(mdev,
 							  mdev->data.socket))
 							  mdev->data.socket))
@@ -2350,9 +2332,11 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
 {
 {
 	struct bio_vec *bvec;
 	struct bio_vec *bvec;
 	int i;
 	int i;
+	/* hint all but last page with MSG_MORE */
 	__bio_for_each_segment(bvec, bio, i, 0) {
 	__bio_for_each_segment(bvec, bio, i, 0) {
 		if (!_drbd_no_send_page(mdev, bvec->bv_page,
 		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 0;
 	}
 	}
 	return 1;
 	return 1;
@@ -2362,12 +2346,13 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
 {
 {
 	struct bio_vec *bvec;
 	struct bio_vec *bvec;
 	int i;
 	int i;
+	/* hint all but last page with MSG_MORE */
 	__bio_for_each_segment(bvec, bio, i, 0) {
 	__bio_for_each_segment(bvec, bio, i, 0) {
 		if (!_drbd_send_page(mdev, bvec->bv_page,
 		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 0;
 	}
 	}
-
 	return 1;
 	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;
 	struct page *page = e->pages;
 	unsigned len = e->size;
 	unsigned len = e->size;
+	/* hint all but last page with MSG_MORE */
 	page_chain_for_each(page) {
 	page_chain_for_each(page) {
 		unsigned l = min_t(unsigned, len, PAGE_SIZE);
 		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;
 			return 0;
 		len -= l;
 		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);
 	p.dp_flags = cpu_to_be32(dp_flags);
 	set_bit(UNPLUG_REMOTE, &mdev->flags);
 	set_bit(UNPLUG_REMOTE, &mdev->flags);
 	ok = (sizeof(p) ==
 	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) {
 	if (ok && dgs) {
 		dgb = mdev->int_dig_out;
 		dgb = mdev->int_dig_out;
 		drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb);
 		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 (ok) {
 		if (mdev->net_conf->wire_protocol == DRBD_PROT_A)
 		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;
 		return 0;
 
 
 	ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
 	ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
-					sizeof(p), MSG_MORE);
+					sizeof(p), dgs ? MSG_MORE : 0);
 	if (ok && dgs) {
 	if (ok && dgs) {
 		dgb = mdev->int_dig_out;
 		dgb = mdev->int_dig_out;
 		drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb);
 		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)
 	if (ok)
 		ok = _drbd_send_zc_ee(mdev, e);
 		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->net_cnt, 0);
 	atomic_set(&mdev->packet_seq, 0);
 	atomic_set(&mdev->packet_seq, 0);
 	atomic_set(&mdev->pp_in_use, 0);
 	atomic_set(&mdev->pp_in_use, 0);
-	atomic_set(&mdev->new_c_uuid, 0);
 
 
 	mutex_init(&mdev->md_io_mutex);
 	mutex_init(&mdev->md_io_mutex);
 	mutex_init(&mdev->data.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->bm_io_work.w.list);
 	INIT_LIST_HEAD(&mdev->delay_probes);
 	INIT_LIST_HEAD(&mdev->delay_probes);
 	INIT_LIST_HEAD(&mdev->delay_probe_work.list);
 	INIT_LIST_HEAD(&mdev->delay_probe_work.list);
-	INIT_LIST_HEAD(&mdev->uuid_work.list);
 
 
 	mdev->resync_work.cb  = w_resync_inactive;
 	mdev->resync_work.cb  = w_resync_inactive;
 	mdev->unplug_work.cb  = w_send_write_hint;
 	mdev->unplug_work.cb  = w_send_write_hint;
 	mdev->md_sync_work.cb = w_md_sync;
 	mdev->md_sync_work.cb = w_md_sync;
 	mdev->bm_io_work.w.cb = w_bitmap_io;
 	mdev->bm_io_work.w.cb = w_bitmap_io;
 	mdev->delay_probe_work.cb = w_delay_probes;
 	mdev->delay_probe_work.cb = w_delay_probes;
-	mdev->uuid_work.cb = w_new_current_uuid;
 	init_timer(&mdev->resync_timer);
 	init_timer(&mdev->resync_timer);
 	init_timer(&mdev->md_sync_timer);
 	init_timer(&mdev->md_sync_timer);
 	init_timer(&mdev->delay_probe_timer);
 	init_timer(&mdev->delay_probe_timer);
@@ -3799,7 +3783,7 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
 	if (ret) {
 	if (ret) {
 		fault_count++;
 		fault_count++;
 
 
-		if (printk_ratelimit())
+		if (__ratelimit(&drbd_ratelimit_state))
 			dev_warn(DEV, "***Simulating %s failure\n",
 			dev_warn(DEV, "***Simulating %s failure\n",
 				_drbd_fault_str(type));
 				_drbd_fault_str(type));
 	}
 	}

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

@@ -42,7 +42,6 @@
 #include <linux/unistd.h>
 #include <linux/unistd.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/random.h>
 #include <linux/random.h>
-#include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include "drbd_int.h"
 #include "drbd_int.h"
@@ -571,6 +570,25 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size)
 	return rv;
 	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)
 static struct socket *drbd_try_connect(struct drbd_conf *mdev)
 {
 {
 	const char *what;
 	const char *what;
@@ -592,6 +610,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev)
 
 
 	sock->sk->sk_rcvtimeo =
 	sock->sk->sk_rcvtimeo =
 	sock->sk->sk_sndtimeo =  mdev->net_conf->try_connect_int*HZ;
 	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
        /* explicitly bind to the configured IP as source IP
 	*  for the outgoing connections.
 	*  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_reuse    = 1; /* SO_REUSEADDR */
 	s_listen->sk->sk_rcvtimeo = timeo;
 	s_listen->sk->sk_rcvtimeo = timeo;
 	s_listen->sk->sk_sndtimeo = 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";
 	what = "bind before listen";
 	err = s_listen->ops->bind(s_listen,
 	err = s_listen->ops->bind(s_listen,
@@ -856,16 +878,6 @@ retry:
 	sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
 	sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
 	msock->sk->sk_priority = TC_PRIO_INTERACTIVE;
 	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 ...
 	/* NOT YET ...
 	 * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
 	 * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
 	 * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
 	 * 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 n_bios = 0;
 	unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT;
 	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
 	/* 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
 	 * level restrictions happen to be different at this offset on this
 	 * side than those of the sending peer, we may need to submit the
 	 * 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)
 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_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 		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);
 		__drbd_chk_io_error(mdev, FALSE);
 		_req_may_be_done(req, m);
 		_req_may_be_done(req, m);
 		put_ldev(mdev);
 		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_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 		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));
 		D_ASSERT(!(req->rq_state & RQ_NET_MASK));
-		req->rq_state |= RQ_NET_PENDING;
-		inc_ap_pending(mdev);
 
 
 		__drbd_chk_io_error(mdev, FALSE);
 		__drbd_chk_io_error(mdev, FALSE);
 		put_ldev(mdev);
 		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); */
 		/* fall through: _req_mod(req,queue_for_net_read); */
 
 
 	case 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);
 		_req_may_be_done(req, m);
 		break;
 		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:
 	case connection_lost_while_pending:
 		/* transfer log cleanup after connection loss */
 		/* transfer log cleanup after connection loss */
 		/* assert something? */
 		/* assert something? */

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

@@ -91,6 +91,7 @@ enum drbd_req_event {
 	send_failed,
 	send_failed,
 	handed_over_to_network,
 	handed_over_to_network,
 	connection_lost_while_pending,
 	connection_lost_while_pending,
+	read_retry_remote_canceled,
 	recv_acked_by_peer,
 	recv_acked_by_peer,
 	write_acked_by_peer,
 	write_acked_by_peer,
 	write_acked_by_peer_and_sis, /* and set_in_sync */
 	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;
 	enum drbd_req_event what;
 	int uptodate = bio_flagged(bio, BIO_UPTODATE);
 	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) {
 	if (!error && !uptodate) {
 		dev_warn(DEV, "p %s: setting error to -EIO\n",
 		dev_warn(DEV, "p %s: setting error to -EIO\n",
 			 bio_data_dir(bio) == WRITE ? "write" : "read");
 			 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);
 		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)
 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);
 	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 */
 	 * to give the disk the chance to relocate that block */
 
 
 	spin_lock_irq(&mdev->req_lock);
 	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);
 		spin_unlock_irq(&mdev->req_lock);
-		dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n");
 		return 1;
 		return 1;
 	}
 	}
 	spin_unlock_irq(&mdev->req_lock);
 	spin_unlock_irq(&mdev->req_lock);

+ 1 - 0
drivers/char/Kconfig

@@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig"
 
 
 config RAMOOPS
 config RAMOOPS
 	tristate "Log panic/oops to a RAM buffer"
 	tristate "Log panic/oops to a RAM buffer"
+	depends on HAS_IOMEM
 	default n
 	default n
 	help
 	help
 	  This enables panic and oops messages to be logged to a circular
 	  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;
 	int len;
 	/* Priority ordering: We should do priority with RR of the groups */
 	/* Priority ordering: We should do priority with RR of the groups */
 	int i = 1;
 	int i = 1;
-	unsigned long flags;
 
 
-	spin_lock_irqsave(&gsm->tx_lock, flags);
 	while (i < NUM_DLCI) {
 	while (i < NUM_DLCI) {
 		struct gsm_dlci *dlci;
 		struct gsm_dlci *dlci;
 
 
@@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
 		if (len == 0)
 		if (len == 0)
 			i++;
 			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)
 static void gsmld_write_wakeup(struct tty_struct *tty)
 {
 {
 	struct gsm_mux *gsm = tty->disc_data;
 	struct gsm_mux *gsm = tty->disc_data;
+	unsigned long flags;
 
 
 	/* Queue poll */
 	/* Queue poll */
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	gsm_data_kick(gsm);
 	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);
 		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);
 	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 	scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
 	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);
 		    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)
 		if (!perm)
 			goto eperm;
 			goto eperm;
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-		if (!ret)
+		if (ret)
+			ret = -EFAULT;
+		else
 			con_clear_unimap(vc, &ui);
 			con_clear_unimap(vc, &ui);
 		break;
 		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)
 static int sh_cmt_clocksource_enable(struct clocksource *cs)
 {
 {
 	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
 	struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
-	int ret;
 
 
 	p->total_cycles = 0;
 	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)
 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->resume = sh_cmt_clocksource_resume;
 	cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
 	cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 	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");
 	dev_info(&p->pdev->dev, "used as clock source\n");
+
 	clocksource_register(cs);
 	clocksource_register(cs);
+
 	return 0;
 	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)
 static int sh_tmu_clocksource_enable(struct clocksource *cs)
 {
 {
 	struct sh_tmu_priv *p = cs_to_sh_tmu(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)
 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->disable = sh_tmu_clocksource_disable;
 	cs->mask = CLOCKSOURCE_MASK(32);
 	cs->mask = CLOCKSOURCE_MASK(32);
 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 	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");
 	dev_info(&p->pdev->dev, "used as clock source\n");
 	clocksource_register(cs);
 	clocksource_register(cs);
 	return 0;
 	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
 	  occurred so that a particular failing memory module can be
 	  replaced.  If unsure, select 'Y'.
 	  replaced.  If unsure, select 'Y'.
 
 
+config EDAC_MCE
+	bool
+
 config EDAC_AMD64
 config EDAC_AMD64
 	tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
 	tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
 	depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
 	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
 	  Support for error detection and correction the Intel
 	  i5400 MCH chipset (Seaburg).
 	  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
 config EDAC_I82860
 	tristate "Intel 82860"
 	tristate "Intel 82860"
 	depends on EDAC_MM_EDAC && PCI && X86_32
 	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)			:= edac_stub.o
 obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.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_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
 edac_core-objs	+= edac_module.o edac_device_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_I5000)		+= i5000_edac.o
 obj-$(CONFIG_EDAC_I5100)		+= i5100_edac.o
 obj-$(CONFIG_EDAC_I5100)		+= i5100_edac.o
 obj-$(CONFIG_EDAC_I5400)		+= i5400_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_E7XXX)		+= e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
 obj-$(CONFIG_EDAC_I82443BXGX)		+= i82443bxgx_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 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
 /* mcidev_sysfs_attribute structure
  *	used for driver sysfs attributes and in mem_ctl_info
  *	used for driver sysfs attributes and in mem_ctl_info
  * 	sysfs top level entries
  * 	sysfs top level entries
  */
  */
 struct mcidev_sysfs_attribute {
 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 (*show)(struct mem_ctl_info *,char *);
         ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
         ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
 };
 };
@@ -424,6 +442,9 @@ struct mem_ctl_info {
 	/* edac sysfs device control */
 	/* edac sysfs device control */
 	struct kobject edac_mci_kobj;
 	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
 	/* Additional top controller level attributes, but specified
 	 * by the low level driver.
 	 * 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 mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
 	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)
 	if (mcidev_attr->show)
 		return mcidev_attr->show(mem_ctl_info, buffer);
 		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 mem_ctl_info *mem_ctl_info = to_mci(kobj);
 	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
 	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)
 	if (mcidev_attr->store)
 		return mcidev_attr->store(mem_ctl_info, buffer, count);
 		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 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
  * 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;
 	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) {
 		if (err) {
 			return err;
 			return err;
 		}
 		}
-
 		sysfs_attrib++;
 		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
  *	remove MC driver specific attributes at the topmost level
  *	directory of this mci instance.
  *	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++;
 		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);
 	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
 
 
+	INIT_LIST_HEAD(&mci->grp_kobj_list);
+
 	/* create a symlink for the device */
 	/* create a symlink for the device */
 	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
 	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
 				EDAC_DEVICE_SYMLINK);
 				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.
 	 * then create them now for the driver.
 	 */
 	 */
 	if (mci->mc_driver_sysfs_attributes) {
 	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) {
 		if (err) {
 			debugf1("%s() failure to create mci attributes\n",
 			debugf1("%s() failure to create mci attributes\n",
 				__func__);
 				__func__);
@@ -841,7 +962,8 @@ fail1:
 	}
 	}
 
 
 	/* remove the mci instance's attributes, if any */
 	/* 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 */
 	/* remove the symlink */
 	sysfs_remove_link(kobj_mci, EDAC_DEVICE_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__);
 	debugf0("%s()  remove_mci_instance\n", __func__);
 
 
 	/* remove this mci instance's attribtes */
 	/* 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__);
 	debugf0("%s()  unregister this mci kobj\n", __func__);
 
 
 	/* unregister this instance's kobject */
 	/* 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) {
 	list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) {
 		spin_unlock_irqrestore(&qib_devs_lock, flags);
 		spin_unlock_irqrestore(&qib_devs_lock, flags);
 		ret = add_cntr_files(sb, dd);
 		ret = add_cntr_files(sb, dd);
-		if (ret) {
-			deactivate_super(sb);
+		if (ret)
 			goto bail;
 			goto bail;
-		}
 		spin_lock_irqsave(&qib_devs_lock, flags);
 		spin_lock_irqsave(&qib_devs_lock, flags);
 	}
 	}
 
 

+ 2 - 1
drivers/input/serio/Kconfig

@@ -21,7 +21,8 @@ if SERIO
 config SERIO_I8042
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
 	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
 	help
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,
 	  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;
 			goto fail3;
 	}
 	}
 
 
-	input_dev->name = wacom_wac->name;
 	input_dev->name = wacom_wac->name;
 	input_dev->name = wacom_wac->name;
 	input_dev->dev.parent = &intf->dev;
 	input_dev->dev.parent = &intf->dev;
 	input_dev->open = wacom_open;
 	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 0x823: /* Intuos3 Grip Pen */
 		case 0x813: /* Intuos3 Classic Pen */
 		case 0x813: /* Intuos3 Classic Pen */
 		case 0x885: /* Intuos3 Marker Pen */
 		case 0x885: /* Intuos3 Marker Pen */
-		case 0x802: /* Intuos4 Grip Pen Eraser */
+		case 0x802: /* Intuos4 General Pen */
 		case 0x804: /* Intuos4 Marker Pen */
 		case 0x804: /* Intuos4 Marker Pen */
 		case 0x40802: /* Intuos4 Classic Pen */
 		case 0x40802: /* Intuos4 Classic Pen */
 		case 0x022:
 		case 0x022:
@@ -335,7 +335,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 		case 0x81b: /* Intuos3 Classic Pen Eraser */
 		case 0x81b: /* Intuos3 Classic Pen Eraser */
 		case 0x91b: /* Intuos3 Airbrush Eraser */
 		case 0x91b: /* Intuos3 Airbrush Eraser */
 		case 0x80c: /* Intuos4 Marker Pen 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 0x4080a: /* Intuos4 Classic Pen Eraser */
 		case 0x90a: /* Intuos4 Airbrush Eraser */
 		case 0x90a: /* Intuos4 Airbrush Eraser */
 			wacom->tool[idx] = BTN_TOOL_RUBBER;
 			wacom->tool[idx] = BTN_TOOL_RUBBER;
@@ -356,6 +356,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 		return 1;
 		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 */
 	/* Exit report */
 	if ((data[1] & 0xfe) == 0x80) {
 	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);
 				input_report_abs(input, ABS_MISC, 0);
 			}
 			}
 		} else {
 		} 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_RX, ((data[1] & 0x1f) << 8) | data[2]);
 			input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
 			input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
 
 
 			if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
 			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_key(input, wacom->tool[1], 1);
 				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
 				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
 			} else {
 			} else {
@@ -640,7 +667,7 @@ static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
 	if (!idx)
 	if (!idx)
 		input_report_key(input, BTN_TOUCH, 1);
 		input_report_key(input, BTN_TOUCH, 1);
 	input_event(input, EV_MSC, MSC_SERIAL, finger);
 	input_event(input, EV_MSC, MSC_SERIAL, finger);
-	input_sync(wacom->input);
+	input_sync(input);
 
 
 	wacom->last_finger = finger;
 	wacom->last_finger = finger;
 }
 }
@@ -826,6 +853,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 	case INTUOS4L:
 	case INTUOS4L:
 	case CINTIQ:
 	case CINTIQ:
 	case WACOM_BEE:
 	case WACOM_BEE:
+	case WACOM_21UX2:
 		sync = wacom_intuos_irq(wacom_wac);
 		sync = wacom_intuos_irq(wacom_wac);
 		break;
 		break;
 
 
@@ -921,6 +949,17 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 		__set_bit(BTN_STYLUS2, input_dev->keybit);
 		__set_bit(BTN_STYLUS2, input_dev->keybit);
 		break;
 		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:
 	case WACOM_BEE:
 		__set_bit(BTN_8, input_dev->keybit);
 		__set_bit(BTN_8, input_dev->keybit);
 		__set_bit(BTN_9, 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 };
 	{ "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L };
 static const struct wacom_features wacom_features_0xBB =
 static const struct wacom_features wacom_features_0xBB =
 	{ "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L };
 	{ "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 =
 static const struct wacom_features wacom_features_0x3F =
 	{ "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ };
 	{ "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ };
 static const struct wacom_features wacom_features_0xC5 =
 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 };
 	{ "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
 static const struct wacom_features wacom_features_0xC7 =
 static const struct wacom_features wacom_features_0xC7 =
 	{ "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
 	{ "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 =
 static const struct wacom_features wacom_features_0x90 =
 	{ "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
 	{ "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
 static const struct wacom_features wacom_features_0x93 =
 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(0xB9) },
 	{ USB_DEVICE_WACOM(0xBA) },
 	{ USB_DEVICE_WACOM(0xBA) },
 	{ USB_DEVICE_WACOM(0xBB) },
 	{ USB_DEVICE_WACOM(0xBB) },
+	{ USB_DEVICE_WACOM(0xBC) },
 	{ USB_DEVICE_WACOM(0x3F) },
 	{ USB_DEVICE_WACOM(0x3F) },
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC6) },
 	{ USB_DEVICE_WACOM(0xC6) },
 	{ USB_DEVICE_WACOM(0xC7) },
 	{ USB_DEVICE_WACOM(0xC7) },
+	{ USB_DEVICE_WACOM(0xCC) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x93) },
 	{ USB_DEVICE_WACOM(0x93) },
 	{ USB_DEVICE_WACOM(0x9A) },
 	{ USB_DEVICE_WACOM(0x9A) },

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

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

+ 1 - 1
drivers/input/touchscreen/Kconfig

@@ -156,7 +156,7 @@ config TOUCHSCREEN_FUJITSU
 config TOUCHSCREEN_S3C2410
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
 	depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
-	select S3C24XX_ADC
+	select S3C_ADC
 	help
 	help
 	  Say Y here if you have the s3c2410 touchscreen.
 	  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");
 	ts->reg = regulator_get(&spi->dev, "vcc");
 	if (IS_ERR(ts->reg)) {
 	if (IS_ERR(ts->reg)) {
 		err = PTR_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;
 		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)
 	if (down)
 		s3c_adc_start(ts.client, 0, 1 << ts.shift);
 		s3c_adc_start(ts.client, 0, 1 << ts.shift);
 	else
 	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) {
 	if (ts.features & FEAT_PEN_IRQ) {
 		/* Clear pen down/up interrupt */
 		/* Clear pen down/up interrupt */

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

@@ -221,7 +221,7 @@ done:
 
 
 	if (poll) {
 	if (poll) {
 		schd = queue_delayed_work(tsc->wq, &tsc->work,
 		schd = queue_delayed_work(tsc->wq, &tsc->work,
-					  tsc->poll_period * HZ / 1000);
+					  msecs_to_jiffies(tsc->poll_period));
 		if (schd)
 		if (schd)
 			tsc->polling = 1;
 			tsc->polling = 1;
 		else {
 		else {
@@ -326,7 +326,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
 		goto err2;
 		goto err2;
 
 
 	schd = queue_delayed_work(tsc->wq, &tsc->work,
 	schd = queue_delayed_work(tsc->wq, &tsc->work,
-				  tsc->poll_period * HZ / 1000);
+				  msecs_to_jiffies(tsc->poll_period));
 
 
 	if (schd)
 	if (schd)
 		tsc->polling = 1;
 		tsc->polling = 1;
@@ -339,10 +339,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
 err2:
 err2:
-	cancel_delayed_work(&tsc->work);
-	flush_workqueue(tsc->wq);
+	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
 	destroy_workqueue(tsc->wq);
-	tsc->wq = 0;
 	input_free_device(input_dev);
 	input_free_device(input_dev);
 err1:
 err1:
 	kfree(tsc);
 	kfree(tsc);
@@ -360,10 +358,8 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
 	if (!tsc)
 	if (!tsc)
 		return 0;
 		return 0;
 
 
-	cancel_delayed_work(&tsc->work);
-	flush_workqueue(tsc->wq);
+	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
 	destroy_workqueue(tsc->wq);
-	tsc->wq = 0;
 
 
 	input_free_device(input_dev);
 	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
 config IR_NEC_DECODER
 	tristate "Enable IR raw decoder for the NEC protocol"
 	tristate "Enable IR raw decoder for the NEC protocol"
 	depends on IR_CORE
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 	default y
 
 
 	---help---
 	---help---
@@ -22,6 +23,7 @@ config IR_NEC_DECODER
 config IR_RC5_DECODER
 config IR_RC5_DECODER
 	tristate "Enable IR raw decoder for the RC-5 protocol"
 	tristate "Enable IR raw decoder for the RC-5 protocol"
 	depends on IR_CORE
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 	default y
 
 
 	---help---
 	---help---

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

@@ -94,6 +94,7 @@ struct imon_context {
 
 
 	bool display_supported;		/* not all controllers do */
 	bool display_supported;		/* not all controllers do */
 	bool display_isopen;		/* display port has been opened */
 	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 rf_isassociating;		/* RF remote associating */
 	bool dev_present_intf0;		/* USB device presence, interface 0 */
 	bool dev_present_intf0;		/* USB device presence, interface 0 */
 	bool dev_present_intf1;		/* USB device presence, interface 1 */
 	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__);
 		err("%s: display port is already open", __func__);
 		retval = -EBUSY;
 		retval = -EBUSY;
 	} else {
 	} else {
-		ictx->display_isopen = 1;
+		ictx->display_isopen = true;
 		file->private_data = ictx;
 		file->private_data = ictx;
 		dev_dbg(ictx->dev, "display port opened\n");
 		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__);
 		err("%s: display is not open", __func__);
 		retval = -EIO;
 		retval = -EIO;
 	} else {
 	} else {
-		ictx->display_isopen = 0;
+		ictx->display_isopen = false;
 		dev_dbg(ictx->dev, "display port closed\n");
 		dev_dbg(ictx->dev, "display port closed\n");
 		if (!ictx->dev_present_intf0) {
 		if (!ictx->dev_present_intf0) {
 			/*
 			/*
@@ -491,12 +492,12 @@ static int send_packet(struct imon_context *ictx)
 	}
 	}
 
 
 	init_completion(&ictx->tx.finished);
 	init_completion(&ictx->tx.finished);
-	ictx->tx.busy = 1;
+	ictx->tx.busy = true;
 	smp_rmb(); /* ensure later readers know we're busy */
 	smp_rmb(); /* ensure later readers know we're busy */
 
 
 	retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
 	retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
 	if (retval) {
 	if (retval) {
-		ictx->tx.busy = 0;
+		ictx->tx.busy = false;
 		smp_rmb(); /* ensure later readers know we're not busy */
 		smp_rmb(); /* ensure later readers know we're not busy */
 		err("%s: error submitting urb(%d)", __func__, retval);
 		err("%s: error submitting urb(%d)", __func__, retval);
 	} else {
 	} else {
@@ -682,7 +683,7 @@ static ssize_t store_associate_remote(struct device *d,
 		return -ENODEV;
 		return -ENODEV;
 
 
 	mutex_lock(&ictx->lock);
 	mutex_lock(&ictx->lock);
-	ictx->rf_isassociating = 1;
+	ictx->rf_isassociating = true;
 	send_associate_24g(ictx);
 	send_associate_24g(ictx);
 	mutex_unlock(&ictx->lock);
 	mutex_unlock(&ictx->lock);
 
 
@@ -950,7 +951,7 @@ static void usb_tx_callback(struct urb *urb)
 	ictx->tx.status = urb->status;
 	ictx->tx.status = urb->status;
 
 
 	/* notify waiters that write has finished */
 	/* notify waiters that write has finished */
-	ictx->tx.busy = 0;
+	ictx->tx.busy = false;
 	smp_rmb(); /* ensure later readers know we're not busy */
 	smp_rmb(); /* ensure later readers know we're not busy */
 	complete(&ictx->tx.finished);
 	complete(&ictx->tx.finished);
 }
 }
@@ -1215,7 +1216,7 @@ static bool imon_mouse_event(struct imon_context *ictx,
 {
 {
 	char rel_x = 0x00, rel_y = 0x00;
 	char rel_x = 0x00, rel_y = 0x00;
 	u8 right_shift = 1;
 	u8 right_shift = 1;
-	bool mouse_input = 1;
+	bool mouse_input = true;
 	int dir = 0;
 	int dir = 0;
 
 
 	/* newer iMON device PAD or mouse button */
 	/* 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) {
 	} else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
 		dir = -1;
 		dir = -1;
 	} else
 	} else
-		mouse_input = 0;
+		mouse_input = false;
 
 
 	if (mouse_input) {
 	if (mouse_input) {
 		dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
 		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;
 	unsigned char *buf = urb->transfer_buffer;
 	struct device *dev = ictx->dev;
 	struct device *dev = ictx->dev;
 	u32 kc;
 	u32 kc;
-	bool norelease = 0;
+	bool norelease = false;
 	int i;
 	int i;
 	u64 temp_key;
 	u64 temp_key;
 	u64 panel_key = 0;
 	u64 panel_key = 0;
@@ -1465,7 +1466,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
 	idev = ictx->idev;
 	idev = ictx->idev;
 
 
 	/* filter out junk data on the older 0xffdc imon devices */
 	/* 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;
 		return;
 
 
 	/* Figure out what key was pressed */
 	/* 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))) {
 	     !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
 		len = 8;
 		len = 8;
 		imon_pad_to_keys(ictx, buf);
 		imon_pad_to_keys(ictx, buf);
-		norelease = 1;
+		norelease = true;
 	}
 	}
 
 
 	if (debug) {
 	if (debug) {
@@ -1580,7 +1581,7 @@ not_input_data:
 	    (buf[6] == 0x5E && buf[7] == 0xDF))) {	/* DT */
 	    (buf[6] == 0x5E && buf[7] == 0xDF))) {	/* DT */
 		dev_warn(dev, "%s: remote associated refid=%02X\n",
 		dev_warn(dev, "%s: remote associated refid=%02X\n",
 			 __func__, buf[1]);
 			 __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 ifnum = iface_desc->desc.bInterfaceNumber;
 	int num_endpts = iface_desc->desc.bNumEndpoints;
 	int num_endpts = iface_desc->desc.bNumEndpoints;
 	int i, ep_dir, ep_type;
 	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:
 	 * 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) {
 		    ep_type == USB_ENDPOINT_XFER_INT) {
 
 
 			rx_endpoint = ep;
 			rx_endpoint = ep;
-			ir_ep_found = 1;
+			ir_ep_found = true;
 			dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
 			dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
 
 
 		} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
 		} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
 			   ep_type == USB_ENDPOINT_XFER_INT) {
 			   ep_type == USB_ENDPOINT_XFER_INT) {
 			tx_endpoint = ep;
 			tx_endpoint = ep;
-			display_ep_found = 1;
+			display_ep_found = true;
 			dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
 			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
 	 * newer iMON devices that use control urb instead of interrupt
 	 */
 	 */
 	if (!display_ep_found) {
 	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 "
 		dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
 			"interface OUT endpoint\n", __func__);
 			"interface OUT endpoint\n", __func__);
 	}
 	}
@@ -1847,7 +1848,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
 	 * and without... :\
 	 * and without... :\
 	 */
 	 */
 	if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
 	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__);
 		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).
 	 * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
 	 */
 	 */
 	if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
 	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__);
 		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->dev = dev;
 	ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
 	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->rx_urb_intf0 = rx_urb;
 	ictx->tx_urb = tx_urb;
 	ictx->tx_urb = tx_urb;
+	ictx->rf_device = false;
 
 
 	ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
 	ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
 	ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
 	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->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;
 	ictx->rx_urb_intf1 = rx_urb;
 
 
 	ret = -ENODEV;
 	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");
 		dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
 		ictx->display_supported = false;
 		ictx->display_supported = false;
 		break;
 		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) */
 	/* iMON VFD, no IR (does have vol knob tho) */
 	case 0x35:
 	case 0x35:
 		dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
 		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;
 			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 {
 	} else {
 	/* this is the secondary interface on the device */
 	/* this is the secondary interface on the device */
 		ictx = imon_init_intf1(interface, first_if_ctx);
 		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);
 		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)
 		if (ictx->display_supported)
 			imon_init_display(ictx, interface);
 			imon_init_display(ictx, interface);
 	}
 	}
@@ -2297,7 +2304,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
 	}
 	}
 
 
 	if (ifnum == 0) {
 	if (ifnum == 0) {
-		ictx->dev_present_intf0 = 0;
+		ictx->dev_present_intf0 = false;
 		usb_kill_urb(ictx->rx_urb_intf0);
 		usb_kill_urb(ictx->rx_urb_intf0);
 		input_unregister_device(ictx->idev);
 		input_unregister_device(ictx->idev);
 		if (ictx->display_supported) {
 		if (ictx->display_supported) {
@@ -2307,7 +2314,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
 				usb_deregister_dev(interface, &imon_vfd_class);
 				usb_deregister_dev(interface, &imon_vfd_class);
 		}
 		}
 	} else {
 	} else {
-		ictx->dev_present_intf1 = 0;
+		ictx->dev_present_intf1 = false;
 		usb_kill_urb(ictx->rx_urb_intf1);
 		usb_kill_urb(ictx->rx_urb_intf1);
 		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
 		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
 			input_unregister_device(ictx->touch);
 			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)
 	if (rc < 0)
 		goto out_table;
 		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",
 	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
 		   driver_name, rc_tab->name);
 		   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");
 	IR_dprintk(1, "Freed keycode table\n");
 
 
 	del_timer_sync(&ir_dev->timer_keyup);
 	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 = &ir_dev->rc_tab;
 	rc_tab->size = 0;
 	rc_tab->size = 0;
 	kfree(rc_tab->scan);
 	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))
 	if (unlikely(devno < 0))
 		return devno;
 		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.type = &ir_raw_dev_type;
 
 
 	ir_dev->dev.class = &ir_input_class;
 	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.o \
 			rc-avermedia-cardbus.o \
 			rc-avermedia-cardbus.o \
 			rc-avermedia-dvbt.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-avertv-303.o \
 			rc-behold.o \
 			rc-behold.o \
 			rc-behold-columbus.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)
 int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
 {
 {
 	struct input_dev *input_dev;
 	struct input_dev *input_dev;
-	char *ir_codes = NULL;
+	char *ir_codes = RC_MAP_DM1105_NEC;
 	int err = -ENOMEM;
 	int err = -ENOMEM;
 
 
 	input_dev = input_allocate_device();
 	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;
 	const u8 *ts, *ts_end, *from_where = NULL;
 	u8 ts_remain = 0, how_much = 0, new_ts = 1;
 	u8 ts_remain = 0, how_much = 0, new_ts = 1;
 	struct ethhdr *ethh = NULL;
 	struct ethhdr *ethh = NULL;
+	bool error = false;
 
 
 #ifdef ULE_DEBUG
 #ifdef ULE_DEBUG
 	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
 	/* 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. */
 						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 						if (priv->ule_skb) {
 						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_errors++;
 							dev->stats.rx_frame_errors++;
 							dev->stats.rx_frame_errors++;
+							error = false;
 						}
 						}
+
 						reset_ule(priv);
 						reset_ule(priv);
 						priv->need_pusi = 1;
 						priv->need_pusi = 1;
 						continue;
 						continue;
@@ -535,6 +542,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				from_where += 2;
 				from_where += 2;
 			}
 			}
 
 
+			priv->ule_sndu_remain = priv->ule_sndu_len + 2;
 			/*
 			/*
 			 * State of current TS:
 			 * State of current TS:
 			 *   ts_remain (remaining bytes in the current TS cell)
 			 *   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) {
 			switch (ts_remain) {
 				case 1:
 				case 1:
+					priv->ule_sndu_remain--;
 					priv->ule_sndu_type = from_where[0] << 8;
 					priv->ule_sndu_type = from_where[0] << 8;
 					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
 					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
 					ts_remain -= 1; from_where += 1;
 					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. */
 				default: /* complete ULE header is present in current TS. */
 					/* Extract ULE type field. */
 					/* Extract ULE type field. */
 					if (priv->ule_sndu_type_1) {
 					if (priv->ule_sndu_type_1) {
+						priv->ule_sndu_type_1 = 0;
 						priv->ule_sndu_type |= from_where[0];
 						priv->ule_sndu_type |= from_where[0];
 						from_where += 1; /* points to payload start. */
 						from_where += 1; /* points to payload start. */
 						ts_remain -= 1;
 						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_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_DIB0070 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_MT2060 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_XC2028 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 DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
 	help
 	help
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Currently, only devices with a product id of
 	  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_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX 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_MT312 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
 	select DVB_DS3000 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);
 	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
 
 
 	if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
 	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;
 		return -ENODEV;
+	}
 
 
 	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
 	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
 			      &cxusb_dualdig4_rev2_config);
 			      &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_A850				0x850a
 #define USB_PID_AVERMEDIA_A805				0xa805
 #define USB_PID_AVERMEDIA_A805				0xa805
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #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	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
 #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 "tda826x.h"
 #include "tda10086.h"
 #include "tda10086.h"
+#include "tda1002x.h"
+#include "tda827x.h"
 #include "lnbp21.h"
 #include "lnbp21.h"
 
 
 /* debug */
 /* debug */
@@ -150,7 +152,17 @@ static struct tda10086_config tda10086_config = {
 	.xtal_freq = TDA10086_XTAL_16M,
 	.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)
 	if (usb_set_interface(adap->dev->udev,0,3) < 0)
 		err("set interface to alts=3 failed");
 		err("set interface to alts=3 failed");
@@ -163,7 +175,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
 	return 0;
 	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) {
 	if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
 		deb_info("TDA8263 attach failed\n");
 		deb_info("TDA8263 attach failed\n");
@@ -180,6 +212,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
 /* DVB USB Driver stuff */
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties ttusb2_properties;
 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_s2400;
+static struct dvb_usb_device_properties ttusb2_properties_ct3650;
 
 
 static int ttusb2_probe(struct usb_interface *intf,
 static int ttusb2_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 		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,
 	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
 	    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))
 				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
 		return 0;
 	return -ENODEV;
 	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_PINNACLE, USB_PID_PCTV_450E) },
 	{ USB_DEVICE(USB_VID_TECHNOTREND,
 	{ USB_DEVICE(USB_VID_TECHNOTREND,
 		USB_PID_TECHNOTREND_CONNECT_S2400) },
 		USB_PID_TECHNOTREND_CONNECT_S2400) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND,
+		USB_PID_TECHNOTREND_CONNECT_CT3650) },
 	{}		/* Terminating entry */
 	{}		/* Terminating entry */
 };
 };
 MODULE_DEVICE_TABLE (usb, ttusb2_table);
 MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -214,8 +251,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
 		{
 		{
 			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
 			.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 */
 			/* parameter for the MPEG2-data transfer */
 			.stream = {
 			.stream = {
@@ -266,8 +303,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
 		{
 		{
 			.streaming_ctrl   = NULL,
 			.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 */
 			/* parameter for the MPEG2-data transfer */
 			.stream = {
 			.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 = {
 static struct usb_driver ttusb2_driver = {
 	.name		= "dvb_usb_ttusb2",
 	.name		= "dvb_usb_ttusb2",
 	.probe		= ttusb2_probe,
 	.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);
 	num = hpsb_iso_n_ready(iso);
 
 
 	if (!fdtv) {
 	if (!fdtv) {
-		dev_err(fdtv->device, "received at unknown iso channel\n");
+		pr_err("received at unknown iso channel\n");
 		goto out;
 		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
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int au8522_g_register(struct v4l2_subdev *sd,
 static int au8522_g_register(struct v4l2_subdev *sd,
 			     struct v4l2_dbg_register *reg)
 			     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 = {
 static const struct v4l2_subdev_video_ops au8522_video_ops = {
 	.s_routing = au8522_s_video_routing,
 	.s_routing = au8522_s_video_routing,
-	.g_fmt = au8522_g_fmt,
-	.s_fmt = au8522_s_fmt,
 	.s_stream = au8522_s_stream,
 	.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__);
 	dprintk("%s\n", __func__);
 
 
 	/* allocate memory for the internal state */
 	/* 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) {
 	if (state == NULL) {
 		printk(KERN_ERR "Unable to kmalloc\n");
 		printk(KERN_ERR "Unable to kmalloc\n");
 		goto error2;
 		goto error2;
 	}
 	}
 
 
-	/* setup the state */
-	memset(state, 0, sizeof(struct ds3000_state));
-
 	state->config = config;
 	state->config = config;
 	state->i2c = i2c;
 	state->i2c = i2c;
 	state->prevUCBS2 = 0;
 	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)
 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)
 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,
 	.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 = {
 static struct ngene_info ngene_info_m780 = {
 	.type           = NGENE_APP,
 	.type           = NGENE_APP,
 	.name           = "Aver M780 ATSC/QAM-B",
 	.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, 0xdb01, ngene_info_satixS2),
 	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
 	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
 	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
 	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),
 	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
 	{0}
 	{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);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
-#define COMMAND_TIMEOUT_WORKAROUND
-
 #define dprintk	if (debug) printk
 #define dprintk	if (debug) printk
 
 
 #define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
 #define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
@@ -147,24 +145,24 @@ static void demux_tasklet(unsigned long data)
 		} else {
 		} else {
 			if (chan->HWState == HWSTATE_RUN) {
 			if (chan->HWState == HWSTATE_RUN) {
 				u32 Flags = 0;
 				u32 Flags = 0;
+				IBufferExchange *exch1 = chan->pBufferExchange;
+				IBufferExchange *exch2 = chan->pBufferExchange2;
 				if (Cur->ngeneBuffer.SR.Flags & 0x01)
 				if (Cur->ngeneBuffer.SR.Flags & 0x01)
 					Flags |= BEF_EVEN_FIELD;
 					Flags |= BEF_EVEN_FIELD;
 				if (Cur->ngeneBuffer.SR.Flags & 0x20)
 				if (Cur->ngeneBuffer.SR.Flags & 0x20)
 					Flags |= BEF_OVERFLOW;
 					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)
 			} else if (chan->HWState != HWSTATE_STOP)
 				chan->HWState = HWSTATE_RUN;
 				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 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
 	u16 BsSDO = 0x9B00;
 	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));
 	memset(&com, 0, sizeof(com));
 	com.cmd.hdr.Opcode = CMD_CONTROL;
 	com.cmd.hdr.Opcode = CMD_CONTROL;
 	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
 	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
@@ -1252,14 +1246,17 @@ static int ngene_load_firm(struct ngene *dev)
 		version = 15;
 		version = 15;
 		size = 23466;
 		size = 23466;
 		fw_name = "ngene_15.fw";
 		fw_name = "ngene_15.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 		break;
 	case 16:
 	case 16:
 		size = 23498;
 		size = 23498;
 		fw_name = "ngene_16.fw";
 		fw_name = "ngene_16.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 		break;
 	case 17:
 	case 17:
 		size = 24446;
 		size = 24446;
 		fw_name = "ngene_17.fw";
 		fw_name = "ngene_17.fw";
+		dev->cmd_timeout_workaround = true;
 		break;
 		break;
 	}
 	}
 
 
@@ -1299,11 +1296,16 @@ static void ngene_stop(struct ngene *dev)
 	ngwritel(0, NGENE_EVENT);
 	ngwritel(0, NGENE_EVENT);
 	ngwritel(0, NGENE_EVENT_HI);
 	ngwritel(0, NGENE_EVENT_HI);
 	free_irq(dev->pci_dev->irq, dev);
 	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)
 static int ngene_start(struct ngene *dev)
 {
 {
 	int stat;
 	int stat;
+	unsigned long flags;
 	int i;
 	int i;
 
 
 	pci_set_master(dev->pci_dev);
 	pci_set_master(dev->pci_dev);
@@ -1333,6 +1335,28 @@ static int ngene_start(struct ngene *dev)
 	if (stat < 0)
 	if (stat < 0)
 		goto fail;
 		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);
 	stat = ngene_i2c_init(dev, 0);
 	if (stat < 0)
 	if (stat < 0)
 		goto fail;
 		goto fail;
@@ -1358,10 +1382,18 @@ static int ngene_start(struct ngene *dev)
 			bconf = BUFFER_CONFIG_3333;
 			bconf = BUFFER_CONFIG_3333;
 		stat = ngene_command_config_buf(dev, bconf);
 		stat = ngene_command_config_buf(dev, bconf);
 	}
 	}
-	return stat;
+	if (!stat)
+		return stat;
+
+	/* otherwise error: fall through */
 fail:
 fail:
 	ngwritel(0, NGENE_INT_ENABLE);
 	ngwritel(0, NGENE_INT_ENABLE);
 	free_irq(dev->pci_dev->irq, dev);
 	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;
 	return stat;
 }
 }
 
 
@@ -1379,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan)
 	struct ngene_info *ni = dev->card_info;
 	struct ngene_info *ni = dev->card_info;
 	int io = ni->io_type[chan->number];
 	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);
 		set_transfer(chan, 0);
-#endif
 
 
 	tasklet_kill(&chan->demux_tasklet);
 	tasklet_kill(&chan->demux_tasklet);
 
 

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

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

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

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

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

@@ -725,6 +725,8 @@ struct ngene {
 	u32                   device_version;
 	u32                   device_version;
 	u32                   fw_interface_version;
 	u32                   fw_interface_version;
 	u32                   icounts;
 	u32                   icounts;
+	bool                  msi_enabled;
+	bool                  cmd_timeout_workaround;
 
 
 	u8                   *CmdDoneByte;
 	u8                   *CmdDoneByte;
 	int                   BootFirmware;
 	int                   BootFirmware;
@@ -797,6 +799,7 @@ struct ngene_info {
 #define NGENE_VBOX_V2	 7
 #define NGENE_VBOX_V2	 7
 
 
 	int   fw_version;
 	int   fw_version;
+	bool  msi_supported;
 	char *name;
 	char *name;
 
 
 	int   io_type[MAX_STREAM];
 	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_VES1820 if !DVB_FE_CUSTOMISE
 	select DVB_L64781 if !DVB_FE_CUSTOMISE
 	select DVB_L64781 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 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_S5H1420 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X 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
 	help
 	  Support for simple SAA7146 based DVB cards (so called Budget-
 	  Support for simple SAA7146 based DVB cards (so called Budget-
 	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
 	  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;
 		break;
 	case 0x1010:
 	case 0x1010:
 	case 0x1017:
 	case 0x1017:
+	case 0x1019:
 	case 0x101a:
 	case 0x101a:
 		/* for the Technotrend 1500 bundled remote */
 		/* for the Technotrend 1500 bundled remote */
 		ir_codes = RC_MAP_TT_1500;
 		ir_codes = RC_MAP_TT_1500;

+ 2 - 2
drivers/media/video/Kconfig

@@ -646,7 +646,7 @@ config VIDEO_PMS
 
 
 config VIDEO_BWQCAM
 config VIDEO_BWQCAM
 	tristate "Quickcam BW Video For Linux"
 	tristate "Quickcam BW Video For Linux"
-	depends on PARPORT && VIDEO_V4L1
+	depends on PARPORT && VIDEO_V4L2
 	help
 	help
 	  Say Y have if you the black and white version of the QuickCam
 	  Say Y have if you the black and white version of the QuickCam
 	  camera. See the next option for the color version.
 	  camera. See the next option for the color version.
@@ -656,7 +656,7 @@ config VIDEO_BWQCAM
 
 
 config VIDEO_CQCAM
 config VIDEO_CQCAM
 	tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
 	tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1
+	depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
 	help
 	help
 	  This is the video4linux driver for the colour version of the
 	  This is the video4linux driver for the colour version of the
 	  Connectix QuickCam.  If you have one of these cameras, say Y here,
 	  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/i2c.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/videodev2.h>
 
 
 #include <media/ak881x.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);
 	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)
 				enum v4l2_mbus_pixelcode *code)
 {
 {
 	if (index)
 	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/delay.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/parport.h>
 #include <linux/parport.h>
 #include <linux/sched.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 <linux/mutex.h>
 #include <asm/uaccess.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 maxpoll = 250;   /* Maximum busy-loop count for qcam I/O */
 static unsigned int yieldlines = 4;  /* Yield after this many during capture */
 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 */
  * immediately attempt to initialize qcam */
 module_param(force_init, int, 0);
 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);
 	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);
 	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);
 	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) {
 	if (d & 0x20) {
 		/* Set bidirectional mode to reverse (data in) */
 		/* 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);
 	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.
 /* qc_waithand busy-waits for a handshake signal from the QuickCam.
  * Almost all communication with the camera requires handshaking. */
  * 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 status;
 	int runs = 0;
 	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,
  * (bit 3 of status register).  It also returns the last value read,
  * since this data is useful. */
  * 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;
 	unsigned int status;
 	int runs = 0;
 	int runs = 0;
@@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
 	return status;
 	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
 /* 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
    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
    almost completely safe, while their method screws up my printer if
    I plug it in before the camera. */
    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 reg, lastreg;
 	int count = 0;
 	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
 /* Decide which scan mode to use.  There's no real requirement that
  * the scanmode match the resolution in q->height and q-> width -- the
  * the scanmode match the resolution in q->height and q-> width -- the
  * camera takes the picture at the resolution specified in 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.  If the scan is smaller, then the rest of the image
  * returned contains garbage. */
  * returned contains garbage. */
 
 
-static int qc_setscanmode(struct qcam_device *q)
+static int qc_setscanmode(struct qcam *q)
 {
 {
 	int old_mode = q->mode;
 	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,
 /* Reset the QuickCam and program for brightness, contrast,
  * white-balance, and resolution. */
  * white-balance, and resolution. */
 
 
-static void qc_set(struct qcam_device *q)
+static void qc_set(struct qcam *q)
 {
 {
 	int val;
 	int val;
 	int val2;
 	int val2;
@@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q)
    the supplied buffer.  It returns the number of bytes read,
    the supplied buffer.  It returns the number of bytes read,
    or -1 on error. */
    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;
 	int ret = 1;
 	unsigned int hi, lo;
 	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
  * n=2^(bit depth)-1.  Ask me for more details if you don't understand
  * this. */
  * 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 i, j, k, yield;
 	int bytes;
 	int bytes;
@@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
  *	Video4linux interfacing
  *	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:
 	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;
 	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,
 static ssize_t qcam_read(struct file *file, char __user *buf,
 		size_t count, loff_t *ppos)
 		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;
 	int len;
 	parport_claim_or_block(qcam->pdev);
 	parport_claim_or_block(qcam->pdev);
 
 
@@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 	return len;
 	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)
 static int init_bwqcam(struct parport *port)
 {
 {
-	struct qcam_device *qcam;
+	struct qcam *qcam;
 
 
 	if (num_cams == MAX_CAMS) {
 	if (num_cams == MAX_CAMS) {
 		printk(KERN_ERR "Too many Quickcams (max %d)\n", 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);
 	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) {
 	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		parport_unregister_device(qcam->pdev);
 		parport_unregister_device(qcam->pdev);
@@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port)
 	return 0;
 	return 0;
 }
 }
 
 
-static void close_bwqcam(struct qcam_device *qcam)
+static void close_bwqcam(struct qcam *qcam)
 {
 {
 	video_unregister_device(&qcam->vdev);
 	video_unregister_device(&qcam->vdev);
 	parport_unregister_device(qcam->pdev);
 	parport_unregister_device(qcam->pdev);
@@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port)
 {
 {
 	int i;
 	int i;
 	for (i = 0; i < num_cams; 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) {
 		if (qcam && qcam->pdev->port == port) {
 			qcams[i] = NULL;
 			qcams[i] = NULL;
 			close_bwqcam(qcam);
 			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/mm.h>
 #include <linux/parport.h>
 #include <linux/parport.h>
 #include <linux/sched.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/mutex.h>
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
-
+#include <linux/version.h>
+#include <linux/videodev2.h>
 #include <asm/uaccess.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 video_device vdev;
 	struct pardevice *pdev;
 	struct pardevice *pdev;
 	struct parport *pport;
 	struct parport *pport;
@@ -51,7 +53,6 @@ struct qcam_device {
 	int contrast, brightness, whitebal;
 	int contrast, brightness, whitebal;
 	int top, left;
 	int top, left;
 	unsigned int bidirectional;
 	unsigned int bidirectional;
-	unsigned long in_use;
 	struct mutex lock;
 	struct mutex lock;
 };
 };
 
 
@@ -68,33 +69,45 @@ struct qcam_device {
 #define QC_DECIMATION_2		2
 #define QC_DECIMATION_2		2
 #define QC_DECIMATION_4		4
 #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 parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 static int probe = 2;
 static int probe = 2;
 static int force_rgb;
 static int force_rgb;
 static int video_nr = -1;
 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
 	/* note: the QC specs refer to the PCAck pin by voltage, not
 	   software level.  PC ports have builtin inverters. */
 	   software level.  PC ports have builtin inverters. */
 	parport_frob_control(qcam->pport, 8, i ? 8 : 0);
 	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;
 	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;
 	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 long oldjiffies = jiffies;
 	unsigned int i;
 	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. */
 	/* 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_status(qcam->pport),
 	       parport_read_control(qcam->pport));
 	       parport_read_control(qcam->pport));
 	return 1;
 	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 long oldjiffies = jiffies;
 	unsigned int i;
 	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. */
 	/* 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_status(qcam->pport),
 	       parport_read_control(qcam->pport),
 	       parport_read_control(qcam->pport),
 	       parport_read_data(qcam->pport));
 	       parport_read_data(qcam->pport));
 	return 1;
 	return 1;
 }
 }
 
 
-static int qcam_read_data(struct qcam_device *qcam)
+static int qcam_read_data(struct qcam *qcam)
 {
 {
 	unsigned int idata;
 	unsigned int idata;
 
 
@@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam)
 	return idata;
 	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;
 	unsigned int idata;
 
 
 	parport_write_data(qcam->pport, data);
 	parport_write_data(qcam->pport, data);
 	idata = qcam_read_data(qcam);
 	idata = qcam_read_data(qcam);
 	if (data != idata) {
 	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);
 		       idata);
 		return 1;
 		return 1;
 	}
 	}
 	return 0;
 	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))
 	if (qcam_write_data(qcam, cmd))
 		return -1;
 		return -1;
@@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned
 	return 0;
 	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))
 	if (qcam_write_data(qcam, cmd))
 		return -1;
 		return -1;
 	return qcam_read_data(qcam);
 	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;
 	unsigned int stat, ostat, i, count = 0;
 
 
@@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam)
 	return 0;
 	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, 0xc);
 	parport_write_control(qcam->pport, 0x8);
 	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,
 /* Reset the QuickCam and program for brightness, contrast,
  * white-balance, and resolution. */
  * 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. */
 	/* 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
 	/* Set the height and width.  These refer to the actual
 	   CCD area *before* applying the selected decimation.  */
 	   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.  */
 	/* 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.  */
 	/* 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.  */
 	/* 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.
 /* Read some bytes from the camera and put them in the buffer.
    nbytes should be a multiple of 3, because bidirectional mode gives
    nbytes should be a multiple of 3, because bidirectional mode gives
    us three bytes at a time.  */
    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;
 	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 */
 		/* It's a bidirectional port */
 		while (bytes < nbytes) {
 		while (bytes < nbytes) {
 			unsigned int lo1, hi1, lo2, hi2;
 			unsigned int lo1, hi1, lo2, hi2;
 			unsigned char r, g, b;
 			unsigned char r, g, b;
 
 
-			if (qcam_await_ready2(q, 1))
+			if (qcam_await_ready2(qcam, 1))
 				return bytes;
 				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;
 				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);
 			r = lo1 | ((hi1 & 1) << 7);
 			g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
 			g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
 			b = lo2 | ((hi2 & 1) << 7);
 			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) {
 		while (bytes < nbytes) {
 			unsigned int hi, lo;
 			unsigned int hi, lo;
 
 
-			if (qcam_await_ready1(q, 1))
+			if (qcam_await_ready1(qcam, 1))
 				return bytes;
 				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;
 				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 */
 			/* flip some bits */
 			rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
 			rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
 			if (i >= 2) {
 			if (i >= 2) {
@@ -361,10 +376,11 @@ get_fragment:
 
 
 #define BUFSZ	150
 #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 lines, pixelsperline, bitsperxfer;
-	unsigned int is_bi_dir = q->bidirectional;
+	unsigned int is_bi_dir = qcam->bidirectional;
 	size_t wantlen, outptr = 0;
 	size_t wantlen, outptr = 0;
 	char tmpbuf[BUFSZ];
 	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 */
 	/* Wait for camera to become ready */
 	for (;;) {
 	for (;;) {
-		int i = qcam_get(q, 41);
+		int i = qcam_get(qcam, 41);
 
 
 		if (i == -1) {
 		if (i == -1) {
-			qc_setup(q);
+			qc_setup(qcam);
 			return -EIO;
 			return -EIO;
 		}
 		}
 		if ((i & 0x80) == 0)
 		if ((i & 0x80) == 0)
@@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		schedule();
 		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;
 		return -EIO;
 
 
-	lines = q->height;
-	pixelsperline = q->width;
+	lines = qcam->height;
+	pixelsperline = qcam->width;
 	bitsperxfer = (is_bi_dir) ? 24 : 8;
 	bitsperxfer = (is_bi_dir) ? 24 : 8;
 
 
 	if (is_bi_dir) {
 	if (is_bi_dir) {
 		/* Turn the port around */
 		/* Turn the port around */
-		parport_data_reverse(q->pport);
+		parport_data_reverse(qcam->pport);
 		mdelay(3);
 		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;
 			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;
 			return -EIO;
 		}
 		}
 	}
 	}
@@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		size_t t, s;
 		size_t t, s;
 
 
 		s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
 		s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
-		t = qcam_read_bytes(q, tmpbuf, s);
+		t = qcam_read_bytes(qcam, tmpbuf, s);
 		if (outptr < len) {
 		if (outptr < len) {
 			size_t sz = len - outptr;
 			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;
 	len = outptr;
 
 
 	if (wantlen) {
 	if (wantlen) {
-		printk(KERN_ERR "qcam: short read.\n");
+		v4l2_err(v4l2_dev, "short read.\n");
 		if (is_bi_dir)
 		if (is_bi_dir)
-			parport_data_forward(q->pport);
-		qc_setup(q);
+			parport_data_forward(qcam->pport);
+		qc_setup(qcam);
 		return len;
 		return len;
 	}
 	}
 
 
@@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 		int l;
 		int l;
 
 
 		do {
 		do {
-			l = qcam_read_bytes(q, tmpbuf, 3);
+			l = qcam_read_bytes(qcam, tmpbuf, 3);
 			cond_resched();
 			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
 			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 {
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
 			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;
 			return len;
 		}
 		}
-		parport_data_forward(q->pport);
+		parport_data_forward(qcam->pport);
 		mdelay(3);
 		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;
 			return len;
 		}
 		}
 	} else {
 	} else {
 		int l;
 		int l;
 
 
 		do {
 		do {
-			l = qcam_read_bytes(q, tmpbuf, 1);
+			l = qcam_read_bytes(qcam, tmpbuf, 1);
 			cond_resched();
 			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
 		} 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 (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
 			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 {
 		} else {
 			if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
 			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;
 	return len;
 }
 }
 
 
@@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
  *	Video4linux interfacing
  *	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);
 		parport_claim_or_block(qcam->pdev);
 		qc_setup(qcam);
 		qc_setup(qcam);
 		parport_release(qcam->pdev);
 		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:
 	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;
 	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,
 static ssize_t qcam_read(struct file *file, char __user *buf,
 			 size_t count, loff_t *ppos)
 			 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;
 	int len;
 
 
 	mutex_lock(&qcam->lock);
 	mutex_lock(&qcam->lock);
@@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 	return len;
 	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 = {
 static const struct v4l2_file_operations qcam_fops = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
-	.open           = qcam_exclusive_open,
-	.release        = qcam_exclusive_release,
-	.ioctl          = qcam_ioctl,
+	.ioctl		= video_ioctl2,
 	.read		= qcam_read,
 	.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. */
 /* 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;
 		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);
 					  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;
 		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)
 static int init_cqcam(struct parport *port)
 {
 {
-	struct qcam_device *qcam;
+	struct qcam *qcam;
+	struct v4l2_device *v4l2_dev;
 
 
 	if (parport[0] != -1) {
 	if (parport[0] != -1) {
 		/* The user gave specific instructions */
 		/* The user gave specific instructions */
@@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port)
 	if (qcam == NULL)
 	if (qcam == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	v4l2_dev = &qcam->v4l2_dev;
+
 	parport_claim_or_block(qcam->pdev);
 	parport_claim_or_block(qcam->pdev);
 
 
 	qc_reset(qcam);
 	qc_reset(qcam);
@@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port)
 	parport_release(qcam->pdev);
 	parport_release(qcam->pdev);
 
 
 	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 	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);
 		       qcam->pport->name);
 		parport_unregister_device(qcam->pdev);
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
 		kfree(qcam);
 		return -ENODEV;
 		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);
 	       video_device_node_name(&qcam->vdev), qcam->pport->name);
 
 
 	qcams[num_cams++] = qcam;
 	qcams[num_cams++] = qcam;
@@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port)
 	return 0;
 	return 0;
 }
 }
 
 
-static void close_cqcam(struct qcam_device *qcam)
+static void close_cqcam(struct qcam *qcam)
 {
 {
 	video_unregister_device(&qcam->vdev);
 	video_unregister_device(&qcam->vdev);
 	parport_unregister_device(qcam->pdev);
 	parport_unregister_device(qcam->pdev);
@@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = {
 
 
 static int __init cqcam_init(void)
 static int __init cqcam_init(void)
 {
 {
-	printk(BANNER "\n");
+	printk(KERN_INFO BANNER "\n");
 
 
 	return parport_register_driver(&cqcam_driver);
 	return parport_register_driver(&cqcam_driver);
 }
 }
@@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
 MODULE_DESCRIPTION(BANNER);
 MODULE_DESCRIPTION(BANNER);
 MODULE_LICENSE("GPL");
 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_init(cqcam_init);
 module_exit(cqcam_cleanup);
 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
  *  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>
  *  Copyright (C) 2009  Devin Heitmueller <dheitmueller@kernellabs.com>
  *
  *
  *  Portions of this work were sponsored by ONELAN Limited.
  *  Portions of this work were sponsored by ONELAN Limited.

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