mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 08:44:21 +08:00
Merge branch 'master' into for-linus
This commit is contained in:
commit
cc44826a26
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
if (!user_mode(__frame))
|
||||
goto no_context;
|
||||
pagefault_out_of_memory();
|
||||
return;
|
||||
|
||||
do_sigbus:
|
||||
up_read(&mm->mmap_sem);
|
||||
|
@ -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);
|
||||
if (!(error_code & ACE_USERMODE))
|
||||
goto no_context;
|
||||
pagefault_out_of_memory();
|
||||
return;
|
||||
|
||||
do_sigbus:
|
||||
up_read(&mm->mmap_sem);
|
||||
|
@ -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);
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
@:
|
||||
|
||||
|
@ -12,8 +12,40 @@ romstart:
|
||||
/* include board specific setup code */
|
||||
#include <mach/romimage.h>
|
||||
|
||||
#ifdef CONFIG_ROMIMAGE_MMCIF
|
||||
/* load the romImage to above the empty zero page */
|
||||
mov.l empty_zero_page_dst, r4
|
||||
mov.l empty_zero_page_dst_adj, r5
|
||||
add r5, r4
|
||||
mov.l bytes_to_load, r5
|
||||
mov.l loader_function, r7
|
||||
jsr @r7
|
||||
mov r4, r15
|
||||
|
||||
mov.l empty_zero_page_dst, r4
|
||||
mov.l empty_zero_page_dst_adj, r5
|
||||
add r5, r4
|
||||
mov.l loaded_code_offs, r5
|
||||
add r5, r4
|
||||
jmp @r4
|
||||
nop
|
||||
|
||||
.balign 4
|
||||
empty_zero_page_dst_adj:
|
||||
.long PAGE_SIZE
|
||||
bytes_to_load:
|
||||
.long end_data - romstart
|
||||
loader_function:
|
||||
.long mmcif_loader
|
||||
loaded_code_offs:
|
||||
.long loaded_code - romstart
|
||||
loaded_code:
|
||||
#endif /* CONFIG_ROMIMAGE_MMCIF */
|
||||
|
||||
/* copy the empty_zero_page contents to where vmlinux expects it */
|
||||
mova empty_zero_page_src, r0
|
||||
mova extra_data_pos, r0
|
||||
mov.l extra_data_size, r1
|
||||
add r1, r0
|
||||
mov.l empty_zero_page_dst, r1
|
||||
mov #(PAGE_SHIFT - 4), r4
|
||||
mov #1, r3
|
||||
@ -37,7 +69,9 @@ romstart:
|
||||
mov #PAGE_SHIFT, r4
|
||||
mov #1, r1
|
||||
shld r4, r1
|
||||
mova empty_zero_page_src, r0
|
||||
mova extra_data_pos, r0
|
||||
add r1, r0
|
||||
mov.l extra_data_size, r1
|
||||
add r1, r0
|
||||
jmp @r0
|
||||
nop
|
||||
@ -45,4 +79,6 @@ romstart:
|
||||
.align 2
|
||||
empty_zero_page_dst:
|
||||
.long _text
|
||||
empty_zero_page_src:
|
||||
extra_data_pos:
|
||||
extra_data_size:
|
||||
.long zero_page_pos - extra_data_pos
|
||||
|
72
arch/sh/boot/romimage/mmcif-sh7724.c
Normal file
72
arch/sh/boot/romimage/mmcif-sh7724.c
Normal 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);
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
zero_page_pos = .;
|
||||
*(.data)
|
||||
end_data = .;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -1 +1,11 @@
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
/* do nothing here by default */
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
extern inline void mmcif_update_progress(int nr)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
@ -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__ */
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -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);
|
||||
if (!user_mode(regs))
|
||||
bad_page_fault(regs, address, SIGKILL);
|
||||
else
|
||||
pagefault_out_of_memory();
|
||||
return;
|
||||
|
||||
do_sigbus:
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
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? */
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
/* 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.
|
||||
*
|
||||
|
@ -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 */
|
||||
|
61
drivers/edac/edac_mce.c
Normal file
61
drivers/edac/edac_mce.c
Normal 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");
|
2078
drivers/edac/i7core_edac.c
Normal file
2078
drivers/edac/i7core_edac.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
/*
|
||||
@ -473,6 +478,26 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
input_report_key(input, wacom->tool[1], 0);
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
@ -484,11 +509,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
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) },
|
||||
|
@ -50,6 +50,7 @@ enum {
|
||||
INTUOS4S,
|
||||
INTUOS4,
|
||||
INTUOS4L,
|
||||
WACOM_21UX2,
|
||||
CINTIQ,
|
||||
WACOM_BEE,
|
||||
WACOM_MO,
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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---
|
||||
|
@ -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);
|
||||
|
@ -490,6 +490,7 @@ int __ir_input_register(struct input_dev *input_dev,
|
||||
if (rc < 0)
|
||||
goto out_table;
|
||||
|
||||
if (ir_dev->props)
|
||||
if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
|
||||
rc = ir_raw_event_register(input_dev);
|
||||
if (rc < 0)
|
||||
@ -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)
|
||||
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);
|
||||
|
@ -221,9 +221,10 @@ int ir_register_class(struct input_dev *input_dev)
|
||||
if (unlikely(devno < 0))
|
||||
return devno;
|
||||
|
||||
if (ir_dev->props) {
|
||||
if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
|
||||
ir_dev->dev.type = &rc_dev_type;
|
||||
else
|
||||
} else
|
||||
ir_dev->dev.type = &ir_raw_dev_type;
|
||||
|
||||
ir_dev->dev.class = &ir_input_class;
|
||||
|
@ -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 \
|
||||
|
@ -1,90 +0,0 @@
|
||||
/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller
|
||||
*
|
||||
* keymap imported from ir-keymaps.c
|
||||
*
|
||||
* Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <media/rc-map.h>
|
||||
|
||||
/*
|
||||
* Avermedia M135A with IR model RM-JX
|
||||
* The same codes exist on both Positivo (BR) and original IR
|
||||
* Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
*/
|
||||
|
||||
static struct ir_scancode avermedia_m135a_rm_jx[] = {
|
||||
{ 0x0200, KEY_POWER2 },
|
||||
{ 0x022e, KEY_DOT }, /* '.' */
|
||||
{ 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
|
||||
|
||||
{ 0x0205, KEY_1 },
|
||||
{ 0x0206, KEY_2 },
|
||||
{ 0x0207, KEY_3 },
|
||||
{ 0x0209, KEY_4 },
|
||||
{ 0x020a, KEY_5 },
|
||||
{ 0x020b, KEY_6 },
|
||||
{ 0x020d, KEY_7 },
|
||||
{ 0x020e, KEY_8 },
|
||||
{ 0x020f, KEY_9 },
|
||||
{ 0x0211, KEY_0 },
|
||||
|
||||
{ 0x0213, KEY_RIGHT }, /* -> or L */
|
||||
{ 0x0212, KEY_LEFT }, /* <- or R */
|
||||
|
||||
{ 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
|
||||
{ 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
|
||||
|
||||
{ 0x0303, KEY_CHANNELUP },
|
||||
{ 0x0302, KEY_CHANNELDOWN },
|
||||
{ 0x021f, KEY_VOLUMEUP },
|
||||
{ 0x021e, KEY_VOLUMEDOWN },
|
||||
{ 0x020c, KEY_ENTER }, /* Full Screen */
|
||||
|
||||
{ 0x0214, KEY_MUTE },
|
||||
{ 0x0208, KEY_AUDIO },
|
||||
|
||||
{ 0x0203, KEY_TEXT }, /* Teletext */
|
||||
{ 0x0204, KEY_EPG },
|
||||
{ 0x022b, KEY_TV2 }, /* TV2 or PIP */
|
||||
|
||||
{ 0x021d, KEY_RED },
|
||||
{ 0x021c, KEY_YELLOW },
|
||||
{ 0x0301, KEY_GREEN },
|
||||
{ 0x0300, KEY_BLUE },
|
||||
|
||||
{ 0x021a, KEY_PLAYPAUSE },
|
||||
{ 0x0219, KEY_RECORD },
|
||||
{ 0x0218, KEY_PLAY },
|
||||
{ 0x021b, KEY_STOP },
|
||||
};
|
||||
|
||||
static struct rc_keymap avermedia_m135a_rm_jx_map = {
|
||||
.map = {
|
||||
.scan = avermedia_m135a_rm_jx,
|
||||
.size = ARRAY_SIZE(avermedia_m135a_rm_jx),
|
||||
.ir_type = IR_TYPE_NEC,
|
||||
.name = RC_MAP_AVERMEDIA_M135A_RM_JX,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init init_rc_map_avermedia_m135a_rm_jx(void)
|
||||
{
|
||||
return ir_register_map(&avermedia_m135a_rm_jx_map);
|
||||
}
|
||||
|
||||
static void __exit exit_rc_map_avermedia_m135a_rm_jx(void)
|
||||
{
|
||||
ir_unregister_map(&avermedia_m135a_rm_jx_map);
|
||||
}
|
||||
|
||||
module_init(init_rc_map_avermedia_m135a_rm_jx)
|
||||
module_exit(exit_rc_map_avermedia_m135a_rm_jx)
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
|
147
drivers/media/IR/keymaps/rc-avermedia-m135a.c
Normal file
147
drivers/media/IR/keymaps/rc-avermedia-m135a.c
Normal 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>");
|
95
drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
Normal file
95
drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
Normal 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>");
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
if (fe->tuner_priv)
|
||||
return stv6110x_set_mode(fe, TUNER_SLEEP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
if (!chan->dev->cmd_timeout_workaround)
|
||||
set_transfer(chan, 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user