1
0
Fork 0

Merge branch 'master' into for-linus

wifi-calibration
Chris Metcalf 2010-06-05 10:35:29 -04:00
commit cc44826a26
411 changed files with 66293 additions and 2629 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -290,6 +290,7 @@ sonixb 0c45:602e Genius VideoCam Messenger
sonixj 0c45:6040 Speed NVC 350K
sonixj 0c45:607c Sonix sn9c102p Hv7131R
sonixj 0c45:60c0 Sangha Sn535
sonixj 0c45:60ce USB-PC-Camera-168 (TALK-5067)
sonixj 0c45:60ec SN9C105+MO4000
sonixj 0c45:60fb Surfer NoName
sonixj 0c45:60fc LG-LIC300

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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");

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>");

View File

@ -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>");

View File

@ -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>");

View File

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

View File

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

View File

@ -76,6 +76,7 @@ config DVB_USB_DIB0700
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
@ -134,6 +135,7 @@ config DVB_USB_M920X
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@ -264,7 +266,7 @@ config DVB_USB_DW2102
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
select DVB_ZL10039 if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
};

View File

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

View File

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

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