auto merge with /home/aegl/GIT/linus
This commit is contained in:
commit
26abd53d8e
|
@ -14,7 +14,7 @@
|
|||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2003</year>
|
||||
<year>2003-2005</year>
|
||||
<holder>Jeff Garzik</holder>
|
||||
</copyright>
|
||||
|
||||
|
@ -44,30 +44,38 @@
|
|||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="libataThanks">
|
||||
<title>Thanks</title>
|
||||
<chapter id="libataIntroduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The bulk of the ATA knowledge comes thanks to long conversations with
|
||||
Andre Hedrick (www.linux-ide.org).
|
||||
libATA is a library used inside the Linux kernel to support ATA host
|
||||
controllers and devices. libATA provides an ATA driver API, class
|
||||
transports for ATA and ATAPI devices, and SCSI<->ATA translation
|
||||
for ATA devices according to the T10 SAT specification.
|
||||
</para>
|
||||
<para>
|
||||
Thanks to Alan Cox for pointing out similarities
|
||||
between SATA and SCSI, and in general for motivation to hack on
|
||||
libata.
|
||||
</para>
|
||||
<para>
|
||||
libata's device detection
|
||||
method, ata_pio_devchk, and in general all the early probing was
|
||||
based on extensive study of Hale Landis's probe/reset code in his
|
||||
ATADRVR driver (www.ata-atapi.com).
|
||||
This Guide documents the libATA driver API, library functions, library
|
||||
internals, and a couple sample ATA low-level drivers.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="libataDriverApi">
|
||||
<title>libata Driver API</title>
|
||||
<para>
|
||||
struct ata_port_operations is defined for every low-level libata
|
||||
hardware driver, and it controls how the low-level driver
|
||||
interfaces with the ATA and SCSI layers.
|
||||
</para>
|
||||
<para>
|
||||
FIS-based drivers will hook into the system with ->qc_prep() and
|
||||
->qc_issue() high-level hooks. Hardware which behaves in a manner
|
||||
similar to PCI IDE hardware may utilize several generic helpers,
|
||||
defining at a bare minimum the bus I/O addresses of the ATA shadow
|
||||
register blocks.
|
||||
</para>
|
||||
<sect1>
|
||||
<title>struct ata_port_operations</title>
|
||||
|
||||
<sect2><title>Disable ATA port</title>
|
||||
<programlisting>
|
||||
void (*port_disable) (struct ata_port *);
|
||||
</programlisting>
|
||||
|
@ -78,6 +86,9 @@ void (*port_disable) (struct ata_port *);
|
|||
unplug).
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Post-IDENTIFY device configuration</title>
|
||||
<programlisting>
|
||||
void (*dev_config) (struct ata_port *, struct ata_device *);
|
||||
</programlisting>
|
||||
|
@ -88,6 +99,9 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
|
|||
issue of SET FEATURES - XFER MODE, and prior to operation.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Set PIO/DMA mode</title>
|
||||
<programlisting>
|
||||
void (*set_piomode) (struct ata_port *, struct ata_device *);
|
||||
void (*set_dmamode) (struct ata_port *, struct ata_device *);
|
||||
|
@ -108,6 +122,9 @@ void (*post_set_mode) (struct ata_port *ap);
|
|||
->set_dma_mode() is only called if DMA is possible.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Taskfile read/write</title>
|
||||
<programlisting>
|
||||
void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
|
||||
void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
|
||||
|
@ -120,6 +137,9 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
|
|||
taskfile register values.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>ATA command execute</title>
|
||||
<programlisting>
|
||||
void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
|
||||
</programlisting>
|
||||
|
@ -129,17 +149,37 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
|
|||
->tf_load(), to be initiated in hardware.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Per-cmd ATAPI DMA capabilities filter</title>
|
||||
<programlisting>
|
||||
u8 (*check_status)(struct ata_port *ap);
|
||||
void (*dev_select)(struct ata_port *ap, unsigned int device);
|
||||
int (*check_atapi_dma) (struct ata_queued_cmd *qc);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
Reads the Status ATA shadow register from hardware. On some
|
||||
hardware, this has the side effect of clearing the interrupt
|
||||
condition.
|
||||
Allow low-level driver to filter ATA PACKET commands, returning a status
|
||||
indicating whether or not it is OK to use DMA for the supplied PACKET
|
||||
command.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Read specific ATA shadow registers</title>
|
||||
<programlisting>
|
||||
u8 (*check_status)(struct ata_port *ap);
|
||||
u8 (*check_altstatus)(struct ata_port *ap);
|
||||
u8 (*check_err)(struct ata_port *ap);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
Reads the Status/AltStatus/Error ATA shadow register from
|
||||
hardware. On some hardware, reading the Status register has
|
||||
the side effect of clearing the interrupt condition.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Select ATA device on bus</title>
|
||||
<programlisting>
|
||||
void (*dev_select)(struct ata_port *ap, unsigned int device);
|
||||
</programlisting>
|
||||
|
@ -147,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
|
|||
<para>
|
||||
Issues the low-level hardware command(s) that causes one of N
|
||||
hardware devices to be considered 'selected' (active and
|
||||
available for use) on the ATA bus.
|
||||
available for use) on the ATA bus. This generally has no
|
||||
meaning on FIS-based devices.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Reset ATA bus</title>
|
||||
<programlisting>
|
||||
void (*phy_reset) (struct ata_port *ap);
|
||||
</programlisting>
|
||||
|
@ -162,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap);
|
|||
functions ata_bus_reset() or sata_phy_reset() for this hook.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Control PCI IDE BMDMA engine</title>
|
||||
<programlisting>
|
||||
void (*bmdma_setup) (struct ata_queued_cmd *qc);
|
||||
void (*bmdma_start) (struct ata_queued_cmd *qc);
|
||||
void (*bmdma_stop) (struct ata_port *ap);
|
||||
u8 (*bmdma_status) (struct ata_port *ap);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
When setting up an IDE BMDMA transaction, these hooks arm
|
||||
(->bmdma_setup) and fire (->bmdma_start) the hardware's DMA
|
||||
engine.
|
||||
When setting up an IDE BMDMA transaction, these hooks arm
|
||||
(->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop)
|
||||
the hardware's DMA engine. ->bmdma_status is used to read the standard
|
||||
PCI IDE DMA Status register.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These hooks are typically either no-ops, or simply not implemented, in
|
||||
FIS-based drivers.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>High-level taskfile hooks</title>
|
||||
<programlisting>
|
||||
void (*qc_prep) (struct ata_queued_cmd *qc);
|
||||
int (*qc_issue) (struct ata_queued_cmd *qc);
|
||||
|
@ -190,20 +248,26 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
|
|||
->qc_issue is used to make a command active, once the hardware
|
||||
and S/G tables have been prepared. IDE BMDMA drivers use the
|
||||
helper function ata_qc_issue_prot() for taskfile protocol-based
|
||||
dispatch. More advanced drivers roll their own ->qc_issue
|
||||
implementation, using this as the "issue new ATA command to
|
||||
hardware" hook.
|
||||
dispatch. More advanced drivers implement their own ->qc_issue.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Timeout (error) handling</title>
|
||||
<programlisting>
|
||||
void (*eng_timeout) (struct ata_port *ap);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
This is a high level error handling function, called from the
|
||||
error handling thread, when a command times out.
|
||||
This is a high level error handling function, called from the
|
||||
error handling thread, when a command times out. Most newer
|
||||
hardware will implement its own error handling code here. IDE BMDMA
|
||||
drivers may use the helper function ata_eng_timeout().
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Hardware interrupt handling</title>
|
||||
<programlisting>
|
||||
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
|
||||
void (*irq_clear) (struct ata_port *);
|
||||
|
@ -216,6 +280,9 @@ void (*irq_clear) (struct ata_port *);
|
|||
is quiet.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>SATA phy read/write</title>
|
||||
<programlisting>
|
||||
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
|
||||
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
|
||||
|
@ -227,6 +294,9 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
|
|||
if ->phy_reset hook called the sata_phy_reset() helper function.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2><title>Init and shutdown</title>
|
||||
<programlisting>
|
||||
int (*port_start) (struct ata_port *ap);
|
||||
void (*port_stop) (struct ata_port *ap);
|
||||
|
@ -240,15 +310,17 @@ void (*host_stop) (struct ata_host_set *host_set);
|
|||
tasks.
|
||||
</para>
|
||||
<para>
|
||||
->host_stop() is called when the rmmod or hot unplug process
|
||||
begins. The hook must stop all hardware interrupts, DMA
|
||||
engines, etc.
|
||||
</para>
|
||||
<para>
|
||||
->port_stop() is called after ->host_stop(). It's sole function
|
||||
is to release DMA/memory resources, now that they are no longer
|
||||
actively being used.
|
||||
</para>
|
||||
<para>
|
||||
->host_stop() is called after all ->port_stop() calls
|
||||
have completed. The hook must finalize hardware shutdown, release DMA
|
||||
and other resources, etc.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
@ -279,4 +351,24 @@ void (*host_stop) (struct ata_host_set *host_set);
|
|||
!Idrivers/scsi/sata_sil.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="libataThanks">
|
||||
<title>Thanks</title>
|
||||
<para>
|
||||
The bulk of the ATA knowledge comes thanks to long conversations with
|
||||
Andre Hedrick (www.linux-ide.org), and long hours pondering the ATA
|
||||
and SCSI specifications.
|
||||
</para>
|
||||
<para>
|
||||
Thanks to Alan Cox for pointing out similarities
|
||||
between SATA and SCSI, and in general for motivation to hack on
|
||||
libata.
|
||||
</para>
|
||||
<para>
|
||||
libata's device detection
|
||||
method, ata_pio_devchk, and in general all the early probing was
|
||||
based on extensive study of Hale Landis's probe/reset code in his
|
||||
ATADRVR driver (www.ata-atapi.com).
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
</book>
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 2
|
||||
PATCHLEVEL = 6
|
||||
SUBLEVEL = 12
|
||||
EXTRAVERSION =-rc5
|
||||
EXTRAVERSION =-rc6
|
||||
NAME=Woozy Numbat
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void);
|
|||
*/
|
||||
void default_idle(void)
|
||||
{
|
||||
while(1) {
|
||||
if (need_resched())
|
||||
__asm__("stop #0x2000" : : : "cc");
|
||||
schedule();
|
||||
local_irq_disable();
|
||||
while (!need_resched()) {
|
||||
/* This stop will re-enable interrupts */
|
||||
__asm__("stop #0x2000" : : : "cc");
|
||||
local_irq_disable();
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
void (*idle)(void) = default_idle;
|
||||
|
@ -63,7 +65,12 @@ void (*idle)(void) = default_idle;
|
|||
void cpu_idle(void)
|
||||
{
|
||||
/* endless idle loop with no priority at all */
|
||||
idle();
|
||||
while (1) {
|
||||
idle();
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void machine_restart(char * __unused)
|
||||
|
|
|
@ -619,7 +619,7 @@ _GLOBAL(flush_instruction_cache)
|
|||
_GLOBAL(flush_icache_range)
|
||||
BEGIN_FTR_SECTION
|
||||
blr /* for 601, do nothing */
|
||||
END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
|
||||
li r5,L1_CACHE_LINE_SIZE-1
|
||||
andc r3,r3,r5
|
||||
subf r4,r3,r4
|
||||
|
@ -736,7 +736,7 @@ _GLOBAL(flush_dcache_all)
|
|||
_GLOBAL(__flush_dcache_icache)
|
||||
BEGIN_FTR_SECTION
|
||||
blr /* for 601, do nothing */
|
||||
END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
|
||||
rlwinm r3,r3,0,0,19 /* Get page base address */
|
||||
li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */
|
||||
mtctr r4
|
||||
|
@ -764,7 +764,7 @@ END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
|
|||
_GLOBAL(__flush_dcache_icache_phys)
|
||||
BEGIN_FTR_SECTION
|
||||
blr /* for 601, do nothing */
|
||||
END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
|
||||
mfmsr r10
|
||||
rlwinm r0,r10,0,28,26 /* clear DR */
|
||||
mtmsr r0
|
||||
|
|
|
@ -1370,7 +1370,7 @@ static int __init prom_find_machine_type(void)
|
|||
}
|
||||
/* Default to pSeries. We need to know if we are running LPAR */
|
||||
rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
|
||||
if (!PHANDLE_VALID(rtas)) {
|
||||
if (PHANDLE_VALID(rtas)) {
|
||||
int x = prom_getproplen(rtas, "ibm,hypertas-functions");
|
||||
if (x != PROM_ERROR) {
|
||||
prom_printf("Hypertas detected, assuming LPAR !\n");
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
//#include <linux/kernel_stat.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "appldata.h"
|
||||
|
||||
|
@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL;
|
|||
static int appldata_timer_active;
|
||||
|
||||
/*
|
||||
* Tasklet
|
||||
* Work queue
|
||||
*/
|
||||
static struct tasklet_struct appldata_tasklet_struct;
|
||||
static struct workqueue_struct *appldata_wq;
|
||||
static void appldata_work_fn(void *data);
|
||||
static DECLARE_WORK(appldata_work, appldata_work_fn, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* Ops list
|
||||
|
@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock);
|
|||
static LIST_HEAD(appldata_ops_list);
|
||||
|
||||
|
||||
/************************* timer, tasklet, DIAG ******************************/
|
||||
/*************************** timer, work, DIAG *******************************/
|
||||
/*
|
||||
* appldata_timer_function()
|
||||
*
|
||||
* schedule tasklet and reschedule timer
|
||||
* schedule work and reschedule timer
|
||||
*/
|
||||
static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
|
||||
{
|
||||
|
@ -157,22 +161,22 @@ static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
|
|||
atomic_read(&appldata_expire_count));
|
||||
if (atomic_dec_and_test(&appldata_expire_count)) {
|
||||
atomic_set(&appldata_expire_count, num_online_cpus());
|
||||
tasklet_schedule((struct tasklet_struct *) data);
|
||||
queue_work(appldata_wq, (struct work_struct *) data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* appldata_tasklet_function()
|
||||
* appldata_work_fn()
|
||||
*
|
||||
* call data gathering function for each (active) module
|
||||
*/
|
||||
static void appldata_tasklet_function(unsigned long data)
|
||||
static void appldata_work_fn(void *data)
|
||||
{
|
||||
struct list_head *lh;
|
||||
struct appldata_ops *ops;
|
||||
int i;
|
||||
|
||||
P_DEBUG(" -= Tasklet =-\n");
|
||||
P_DEBUG(" -= Work Queue =-\n");
|
||||
i = 0;
|
||||
spin_lock(&appldata_ops_lock);
|
||||
list_for_each(lh, &appldata_ops_list) {
|
||||
|
@ -231,7 +235,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
|
|||
: "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
|
||||
return (int) ry;
|
||||
}
|
||||
/********************** timer, tasklet, DIAG <END> ***************************/
|
||||
/************************ timer, work, DIAG <END> ****************************/
|
||||
|
||||
|
||||
/****************************** /proc stuff **********************************/
|
||||
|
@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
|
|||
struct list_head *lh;
|
||||
|
||||
found = 0;
|
||||
spin_lock_bh(&appldata_ops_lock);
|
||||
spin_lock(&appldata_ops_lock);
|
||||
list_for_each(lh, &appldata_ops_list) {
|
||||
tmp_ops = list_entry(lh, struct appldata_ops, list);
|
||||
if (&tmp_ops->ctl_table[2] == ctl) {
|
||||
|
@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
|
|||
}
|
||||
}
|
||||
if (!found) {
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = ctl->data;
|
||||
if (!try_module_get(ops->owner)) { // protect this function
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
|
||||
if (!*lenp || *ppos) {
|
||||
*lenp = 0;
|
||||
|
@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock_bh(&appldata_ops_lock);
|
||||
spin_lock(&appldata_ops_lock);
|
||||
if ((buf[0] == '1') && (ops->active == 0)) {
|
||||
if (!try_module_get(ops->owner)) { // protect tasklet
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
// protect work queue callback
|
||||
if (!try_module_get(ops->owner)) {
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
module_put(ops->owner);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
|
|||
}
|
||||
module_put(ops->owner);
|
||||
}
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
out:
|
||||
*lenp = len;
|
||||
*ppos += len;
|
||||
|
@ -529,7 +534,7 @@ int appldata_register_ops(struct appldata_ops *ops)
|
|||
}
|
||||
memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
|
||||
|
||||
spin_lock_bh(&appldata_ops_lock);
|
||||
spin_lock(&appldata_ops_lock);
|
||||
list_for_each(lh, &appldata_ops_list) {
|
||||
tmp_ops = list_entry(lh, struct appldata_ops, list);
|
||||
P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
|
||||
|
@ -541,18 +546,18 @@ int appldata_register_ops(struct appldata_ops *ops)
|
|||
APPLDATA_PROC_NAME_LENGTH) == 0) {
|
||||
P_ERROR("Name \"%s\" already registered!\n", ops->name);
|
||||
kfree(ops->ctl_table);
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (tmp_ops->ctl_nr == ops->ctl_nr) {
|
||||
P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
|
||||
kfree(ops->ctl_table);
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
list_add(&ops->list, &appldata_ops_list);
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
|
||||
ops->ctl_table[0].ctl_name = CTL_APPLDATA;
|
||||
ops->ctl_table[0].procname = appldata_proc_name;
|
||||
|
@ -583,12 +588,12 @@ int appldata_register_ops(struct appldata_ops *ops)
|
|||
*/
|
||||
void appldata_unregister_ops(struct appldata_ops *ops)
|
||||
{
|
||||
spin_lock_bh(&appldata_ops_lock);
|
||||
spin_lock(&appldata_ops_lock);
|
||||
unregister_sysctl_table(ops->sysctl_header);
|
||||
list_del(&ops->list);
|
||||
kfree(ops->ctl_table);
|
||||
ops->ctl_table = NULL;
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
P_INFO("%s-ops unregistered!\n", ops->name);
|
||||
}
|
||||
/********************** module-ops management <END> **************************/
|
||||
|
@ -602,7 +607,7 @@ appldata_online_cpu(int cpu)
|
|||
init_virt_timer(&per_cpu(appldata_timer, cpu));
|
||||
per_cpu(appldata_timer, cpu).function = appldata_timer_function;
|
||||
per_cpu(appldata_timer, cpu).data = (unsigned long)
|
||||
&appldata_tasklet_struct;
|
||||
&appldata_work;
|
||||
atomic_inc(&appldata_expire_count);
|
||||
spin_lock(&appldata_timer_lock);
|
||||
__appldata_vtimer_setup(APPLDATA_MOD_TIMER);
|
||||
|
@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu)
|
|||
del_virt_timer(&per_cpu(appldata_timer, cpu));
|
||||
if (atomic_dec_and_test(&appldata_expire_count)) {
|
||||
atomic_set(&appldata_expire_count, num_online_cpus());
|
||||
tasklet_schedule(&appldata_tasklet_struct);
|
||||
queue_work(appldata_wq, &appldata_work);
|
||||
}
|
||||
spin_lock(&appldata_timer_lock);
|
||||
__appldata_vtimer_setup(APPLDATA_MOD_TIMER);
|
||||
|
@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = {
|
|||
/*
|
||||
* appldata_init()
|
||||
*
|
||||
* init timer and tasklet, register /proc entries
|
||||
* init timer, register /proc entries
|
||||
*/
|
||||
static int __init appldata_init(void)
|
||||
{
|
||||
|
@ -657,6 +662,12 @@ static int __init appldata_init(void)
|
|||
P_DEBUG("sizeof(parameter_list) = %lu\n",
|
||||
sizeof(struct appldata_parameter_list));
|
||||
|
||||
appldata_wq = create_singlethread_workqueue("appldata");
|
||||
if (!appldata_wq) {
|
||||
P_ERROR("Could not create work queue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for_each_online_cpu(i)
|
||||
appldata_online_cpu(i);
|
||||
|
||||
|
@ -670,7 +681,6 @@ static int __init appldata_init(void)
|
|||
appldata_table[1].de->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
|
||||
P_DEBUG("Base interface initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -678,7 +688,7 @@ static int __init appldata_init(void)
|
|||
/*
|
||||
* appldata_exit()
|
||||
*
|
||||
* stop timer and tasklet, unregister /proc entries
|
||||
* stop timer, unregister /proc entries
|
||||
*/
|
||||
static void __exit appldata_exit(void)
|
||||
{
|
||||
|
@ -690,7 +700,7 @@ static void __exit appldata_exit(void)
|
|||
/*
|
||||
* ops list should be empty, but just in case something went wrong...
|
||||
*/
|
||||
spin_lock_bh(&appldata_ops_lock);
|
||||
spin_lock(&appldata_ops_lock);
|
||||
list_for_each(lh, &appldata_ops_list) {
|
||||
ops = list_entry(lh, struct appldata_ops, list);
|
||||
rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
|
||||
|
@ -700,7 +710,7 @@ static void __exit appldata_exit(void)
|
|||
"return code: %d\n", ops->name, rc);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&appldata_ops_lock);
|
||||
spin_unlock(&appldata_ops_lock);
|
||||
|
||||
for_each_online_cpu(i)
|
||||
appldata_offline_cpu(i);
|
||||
|
@ -709,7 +719,7 @@ static void __exit appldata_exit(void)
|
|||
|
||||
unregister_sysctl_table(appldata_sysctl_header);
|
||||
|
||||
tasklet_kill(&appldata_tasklet_struct);
|
||||
destroy_workqueue(appldata_wq);
|
||||
P_DEBUG("... module unloaded!\n");
|
||||
}
|
||||
/**************************** init / exit <END> ******************************/
|
||||
|
|
|
@ -68,7 +68,7 @@ struct appldata_mem_data {
|
|||
u64 pgmajfault; /* page faults (major only) */
|
||||
// <-- New in 2.6
|
||||
|
||||
} appldata_mem_data;
|
||||
} __attribute__((packed)) appldata_mem_data;
|
||||
|
||||
|
||||
static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
|
||||
|
|
|
@ -57,7 +57,7 @@ struct appldata_net_sum_data {
|
|||
u64 rx_dropped; /* no space in linux buffers */
|
||||
u64 tx_dropped; /* no space available in linux */
|
||||
u64 collisions; /* collisions while transmitting */
|
||||
} appldata_net_sum_data;
|
||||
} __attribute__((packed)) appldata_net_sum_data;
|
||||
|
||||
|
||||
static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
|
||||
|
|
|
@ -49,7 +49,7 @@ struct appldata_os_per_cpu {
|
|||
u32 per_cpu_softirq; /* ... spent in softirqs */
|
||||
u32 per_cpu_iowait; /* ... spent while waiting for I/O */
|
||||
// <-- New in 2.6
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
struct appldata_os_data {
|
||||
u64 timestamp;
|
||||
|
@ -75,7 +75,7 @@ struct appldata_os_data {
|
|||
|
||||
/* per cpu data */
|
||||
struct appldata_os_per_cpu os_cpu[0];
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct appldata_os_data *appldata_os_data;
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <asm/pgalloc.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#ifdef CONFIG_S390_SUPPORT
|
||||
#include "compat_ptrace.h"
|
||||
|
@ -130,13 +131,19 @@ static int
|
|||
peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||
{
|
||||
struct user *dummy = NULL;
|
||||
addr_t offset, tmp;
|
||||
addr_t offset, tmp, mask;
|
||||
|
||||
/*
|
||||
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
||||
* an alignment of 4. Programmers from hell...
|
||||
*/
|
||||
if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||
mask = __ADDR_MASK;
|
||||
#ifdef CONFIG_ARCH_S390X
|
||||
if (addr >= (addr_t) &dummy->regs.acrs &&
|
||||
addr < (addr_t) &dummy->regs.orig_gpr2)
|
||||
mask = 3;
|
||||
#endif
|
||||
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||
return -EIO;
|
||||
|
||||
if (addr < (addr_t) &dummy->regs.acrs) {
|
||||
|
@ -153,6 +160,16 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
|||
* access registers are stored in the thread structure
|
||||
*/
|
||||
offset = addr - (addr_t) &dummy->regs.acrs;
|
||||
#ifdef CONFIG_ARCH_S390X
|
||||
/*
|
||||
* Very special case: old & broken 64 bit gdb reading
|
||||
* from acrs[15]. Result is a 64 bit value. Read the
|
||||
* 32 bit acrs[15] value and shift it by 32. Sick...
|
||||
*/
|
||||
if (addr == (addr_t) &dummy->regs.acrs[15])
|
||||
tmp = ((unsigned long) child->thread.acrs[15]) << 32;
|
||||
else
|
||||
#endif
|
||||
tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
|
||||
|
||||
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
|
||||
|
@ -167,6 +184,9 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
|||
*/
|
||||
offset = addr - (addr_t) &dummy->regs.fp_regs;
|
||||
tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
|
||||
if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
|
||||
tmp &= (unsigned long) FPC_VALID_MASK
|
||||
<< (BITS_PER_LONG - 32);
|
||||
|
||||
} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
|
||||
/*
|
||||
|
@ -191,13 +211,19 @@ static int
|
|||
poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||
{
|
||||
struct user *dummy = NULL;
|
||||
addr_t offset;
|
||||
addr_t offset, mask;
|
||||
|
||||
/*
|
||||
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
||||
* an alignment of 4. Programmers from hell indeed...
|
||||
*/
|
||||
if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||
mask = __ADDR_MASK;
|
||||
#ifdef CONFIG_ARCH_S390X
|
||||
if (addr >= (addr_t) &dummy->regs.acrs &&
|
||||
addr < (addr_t) &dummy->regs.orig_gpr2)
|
||||
mask = 3;
|
||||
#endif
|
||||
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||
return -EIO;
|
||||
|
||||
if (addr < (addr_t) &dummy->regs.acrs) {
|
||||
|
@ -224,6 +250,17 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
|||
* access registers are stored in the thread structure
|
||||
*/
|
||||
offset = addr - (addr_t) &dummy->regs.acrs;
|
||||
#ifdef CONFIG_ARCH_S390X
|
||||
/*
|
||||
* Very special case: old & broken 64 bit gdb writing
|
||||
* to acrs[15] with a 64 bit value. Ignore the lower
|
||||
* half of the value and write the upper 32 bit to
|
||||
* acrs[15]. Sick...
|
||||
*/
|
||||
if (addr == (addr_t) &dummy->regs.acrs[15])
|
||||
child->thread.acrs[15] = (unsigned int) (data >> 32);
|
||||
else
|
||||
#endif
|
||||
*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
|
||||
|
||||
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
|
||||
|
@ -237,7 +274,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
|||
* floating point regs. are stored in the thread structure
|
||||
*/
|
||||
if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
|
||||
(data & ~FPC_VALID_MASK) != 0)
|
||||
(data & ~((unsigned long) FPC_VALID_MASK
|
||||
<< (BITS_PER_LONG - 32))) != 0)
|
||||
return -EINVAL;
|
||||
offset = addr - (addr_t) &dummy->regs.fp_regs;
|
||||
*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
|
||||
|
@ -722,6 +760,13 @@ syscall_trace(struct pt_regs *regs, int entryexit)
|
|||
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
|
||||
? 0x80 : 0));
|
||||
|
||||
/*
|
||||
* If the debuffer has set an invalid system call number,
|
||||
* we prepare to skip the system call restart handling.
|
||||
*/
|
||||
if (!entryexit && regs->gprs[2] >= NR_syscalls)
|
||||
regs->trap = -1;
|
||||
|
||||
/*
|
||||
* this isn't the same as continuing with a signal, but it will do
|
||||
* for normal use. strace only continues with a signal if the
|
||||
|
|
|
@ -207,7 +207,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
|
|||
* we are not in an interrupt and that there is a
|
||||
* user context.
|
||||
*/
|
||||
if (user_address == 0 || in_interrupt() || !mm)
|
||||
if (user_address == 0 || in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
/*
|
||||
|
|
|
@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
|
|||
fore_200e-objs += fore200e_pca_fw.o
|
||||
# guess the target endianess to choose the right PCA-200E firmware image
|
||||
ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
|
||||
CONFIG_ATM_FORE200E_PCA_FW = $(shell if test -n "`$(CC) -E -dM $(src)/../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo $(obj)/pca200e.bin; else echo $(obj)/pca200e_ecd.bin2; fi)
|
||||
byteorder.h := include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h
|
||||
CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -383,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore200e)
|
|||
switch(fore200e->state) {
|
||||
|
||||
case FORE200E_STATE_COMPLETE:
|
||||
if (fore200e->stats)
|
||||
kfree(fore200e->stats);
|
||||
kfree(fore200e->stats);
|
||||
|
||||
case FORE200E_STATE_IRQ:
|
||||
free_irq(fore200e->irq, fore200e->atm_dev);
|
||||
|
@ -963,8 +962,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
|
|||
entry, txq->tail, entry->vc_map, entry->skb);
|
||||
|
||||
/* free copy of misaligned data */
|
||||
if (entry->data)
|
||||
kfree(entry->data);
|
||||
kfree(entry->data);
|
||||
|
||||
/* remove DMA mapping */
|
||||
fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
|
||||
|
|
|
@ -412,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
|
|||
init_one_failure:
|
||||
if (atm_dev)
|
||||
atm_dev_deregister(atm_dev);
|
||||
if (he_dev)
|
||||
kfree(he_dev);
|
||||
kfree(he_dev);
|
||||
pci_disable_device(pci_dev);
|
||||
return err;
|
||||
}
|
||||
|
@ -2534,8 +2533,7 @@ he_open(struct atm_vcc *vcc)
|
|||
open_failed:
|
||||
|
||||
if (err) {
|
||||
if (he_vcc)
|
||||
kfree(he_vcc);
|
||||
kfree(he_vcc);
|
||||
clear_bit(ATM_VF_ADDR, &vcc->flags);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -676,10 +676,10 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
|
|||
PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
|
||||
|
||||
/* Initialize SCQ0, the only VBR SCQ used */
|
||||
card->scq1 = (scq_info *) NULL;
|
||||
card->scq2 = (scq_info *) NULL;
|
||||
card->scq1 = NULL;
|
||||
card->scq2 = NULL;
|
||||
card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
|
||||
if (card->scq0 == (scq_info *) NULL)
|
||||
if (card->scq0 == NULL)
|
||||
{
|
||||
printk("nicstar%d: can't get SCQ0.\n", i);
|
||||
error = 12;
|
||||
|
@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 scd)
|
|||
int i;
|
||||
|
||||
if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
|
||||
return (scq_info *) NULL;
|
||||
return NULL;
|
||||
|
||||
scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
|
||||
if (scq == (scq_info *) NULL)
|
||||
return (scq_info *) NULL;
|
||||
if (scq == NULL)
|
||||
return NULL;
|
||||
scq->org = kmalloc(2 * size, GFP_KERNEL);
|
||||
if (scq->org == NULL)
|
||||
{
|
||||
kfree(scq);
|
||||
return (scq_info *) NULL;
|
||||
return NULL;
|
||||
}
|
||||
scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
|
||||
(size / NS_SCQE_SIZE), GFP_KERNEL);
|
||||
if (scq->skb == (struct sk_buff **) NULL)
|
||||
if (scq->skb == NULL)
|
||||
{
|
||||
kfree(scq->org);
|
||||
kfree(scq);
|
||||
return (scq_info *) NULL;
|
||||
return NULL;
|
||||
}
|
||||
scq->num_entries = size / NS_SCQE_SIZE;
|
||||
scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
|
||||
|
@ -1498,7 +1498,7 @@ static int ns_open(struct atm_vcc *vcc)
|
|||
vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
|
||||
|
||||
scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
|
||||
if (scq == (scq_info *) NULL)
|
||||
if (scq == NULL)
|
||||
{
|
||||
PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
|
||||
card->scd2vc[frscdi] = NULL;
|
||||
|
|
|
@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc)
|
|||
zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
|
||||
dealloc_shaper(vcc->dev,zatm_vcc->shaper);
|
||||
}
|
||||
if (zatm_vcc->ring) kfree(zatm_vcc->ring);
|
||||
kfree(zatm_vcc->ring);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1339,12 +1339,9 @@ static int __init zatm_start(struct atm_dev *dev)
|
|||
return 0;
|
||||
out:
|
||||
for (i = 0; i < NR_MBX; i++)
|
||||
if (zatm_dev->mbx_start[i] != 0)
|
||||
kfree((void *) zatm_dev->mbx_start[i]);
|
||||
if (zatm_dev->rx_map != NULL)
|
||||
kfree(zatm_dev->rx_map);
|
||||
if (zatm_dev->tx_map != NULL)
|
||||
kfree(zatm_dev->tx_map);
|
||||
kfree(zatm_dev->mbx_start[i]);
|
||||
kfree(zatm_dev->rx_map);
|
||||
kfree(zatm_dev->tx_map);
|
||||
free_irq(zatm_dev->irq, dev);
|
||||
return error;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1995,9 +1995,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
|
|||
unsigned char ch, gdl;
|
||||
int ignored = 0;
|
||||
int cnt = 0;
|
||||
unsigned char *cp;
|
||||
char *fp;
|
||||
int count;
|
||||
int recv_room;
|
||||
int max = 256;
|
||||
unsigned long flags;
|
||||
|
@ -2011,10 +2008,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
|
|||
//return;
|
||||
}
|
||||
|
||||
cp = tty->flip.char_buf;
|
||||
fp = tty->flip.flag_buf;
|
||||
count = 0;
|
||||
|
||||
// following add by Victor Yu. 09-02-2002
|
||||
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
|
||||
|
||||
|
@ -2041,12 +2034,10 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
|
|||
}
|
||||
while (gdl--) {
|
||||
ch = inb(info->base + UART_RX);
|
||||
count++;
|
||||
*cp++ = ch;
|
||||
*fp++ = 0;
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
cnt++;
|
||||
/*
|
||||
if((count>=HI_WATER) && (info->stop_rx==0)){
|
||||
if((cnt>=HI_WATER) && (info->stop_rx==0)){
|
||||
mxser_stoprx(tty);
|
||||
info->stop_rx=1;
|
||||
break;
|
||||
|
@ -2061,7 +2052,7 @@ intr_old:
|
|||
if (max-- < 0)
|
||||
break;
|
||||
/*
|
||||
if((count>=HI_WATER) && (info->stop_rx==0)){
|
||||
if((cnt>=HI_WATER) && (info->stop_rx==0)){
|
||||
mxser_stoprx(tty);
|
||||
info->stop_rx=1;
|
||||
break;
|
||||
|
@ -2078,36 +2069,33 @@ intr_old:
|
|||
if (++ignored > 100)
|
||||
break;
|
||||
} else {
|
||||
count++;
|
||||
char flag = 0;
|
||||
if (*status & UART_LSR_SPECIAL) {
|
||||
if (*status & UART_LSR_BI) {
|
||||
*fp++ = TTY_BREAK;
|
||||
flag = TTY_BREAK;
|
||||
/* added by casper 1/11/2000 */
|
||||
info->icount.brk++;
|
||||
|
||||
/* */
|
||||
if (info->flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
} else if (*status & UART_LSR_PE) {
|
||||
*fp++ = TTY_PARITY;
|
||||
flag = TTY_PARITY;
|
||||
/* added by casper 1/11/2000 */
|
||||
info->icount.parity++;
|
||||
/* */
|
||||
} else if (*status & UART_LSR_FE) {
|
||||
*fp++ = TTY_FRAME;
|
||||
flag = TTY_FRAME;
|
||||
/* added by casper 1/11/2000 */
|
||||
info->icount.frame++;
|
||||
/* */
|
||||
} else if (*status & UART_LSR_OE) {
|
||||
*fp++ = TTY_OVERRUN;
|
||||
flag = TTY_OVERRUN;
|
||||
/* added by casper 1/11/2000 */
|
||||
info->icount.overrun++;
|
||||
/* */
|
||||
} else
|
||||
*fp++ = 0;
|
||||
} else
|
||||
*fp++ = 0;
|
||||
*cp++ = ch;
|
||||
}
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
cnt++;
|
||||
if (cnt >= recv_room) {
|
||||
if (!info->ldisc_stop_rx) {
|
||||
|
@ -2132,13 +2120,13 @@ intr_old:
|
|||
// above add by Victor Yu. 09-02-2002
|
||||
} while (*status & UART_LSR_DR);
|
||||
|
||||
end_intr: // add by Victor Yu. 09-02-2002
|
||||
end_intr: // add by Victor Yu. 09-02-2002
|
||||
|
||||
mxvar_log.rxcnt[info->port] += cnt;
|
||||
info->mon_data.rxcnt += cnt;
|
||||
info->mon_data.up_rxcnt += cnt;
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
|
||||
|
|
|
@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *dev)
|
|||
spin_lock_irqsave(&lp->window_lock, flags);
|
||||
update_stats(dev);
|
||||
spin_unlock_irqrestore(&lp->window_lock, flags);
|
||||
|
||||
/* force interrupts off */
|
||||
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
|
||||
}
|
||||
|
||||
link->open--;
|
||||
|
|
|
@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
|
|||
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
|
||||
RTL_W8(EarlyTxThres, EarlyTxThld);
|
||||
|
||||
/* For gigabit rtl8169, MTU + header + CRC + VLAN */
|
||||
RTL_W16(RxMaxSize, tp->rx_buf_sz);
|
||||
/* Low hurts. Let's disable the filtering. */
|
||||
RTL_W16(RxMaxSize, 16383);
|
||||
|
||||
/* Set Rx Config register */
|
||||
i = rtl8169_rx_config |
|
||||
|
@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
|
|||
}
|
||||
}
|
||||
|
||||
static inline int rtl8169_fragmented_frame(u32 status)
|
||||
{
|
||||
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
|
||||
}
|
||||
|
||||
static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
|
||||
{
|
||||
u32 opts1 = le32_to_cpu(desc->opts1);
|
||||
|
@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
|
|||
|
||||
while (rx_left > 0) {
|
||||
unsigned int entry = cur_rx % NUM_RX_DESC;
|
||||
struct RxDesc *desc = tp->RxDescArray + entry;
|
||||
u32 status;
|
||||
|
||||
rmb();
|
||||
status = le32_to_cpu(tp->RxDescArray[entry].opts1);
|
||||
status = le32_to_cpu(desc->opts1);
|
||||
|
||||
if (status & DescOwn)
|
||||
break;
|
||||
if (status & RxRES) {
|
||||
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
|
||||
printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
|
||||
dev->name, status);
|
||||
tp->stats.rx_errors++;
|
||||
if (status & (RxRWT | RxRUNT))
|
||||
tp->stats.rx_length_errors++;
|
||||
if (status & RxCRC)
|
||||
tp->stats.rx_crc_errors++;
|
||||
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
|
||||
} else {
|
||||
struct RxDesc *desc = tp->RxDescArray + entry;
|
||||
struct sk_buff *skb = tp->Rx_skbuff[entry];
|
||||
int pkt_size = (status & 0x00001FFF) - 4;
|
||||
void (*pci_action)(struct pci_dev *, dma_addr_t,
|
||||
size_t, int) = pci_dma_sync_single_for_device;
|
||||
|
||||
/*
|
||||
* The driver does not support incoming fragmented
|
||||
* frames. They are seen as a symptom of over-mtu
|
||||
* sized frames.
|
||||
*/
|
||||
if (unlikely(rtl8169_fragmented_frame(status))) {
|
||||
tp->stats.rx_dropped++;
|
||||
tp->stats.rx_length_errors++;
|
||||
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
|
||||
goto move_on;
|
||||
}
|
||||
|
||||
rtl8169_rx_csum(skb, desc);
|
||||
|
||||
pci_dma_sync_single_for_cpu(tp->pci_dev,
|
||||
|
@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
|
|||
tp->stats.rx_bytes += pkt_size;
|
||||
tp->stats.rx_packets++;
|
||||
}
|
||||
|
||||
move_on:
|
||||
cur_rx++;
|
||||
rx_left--;
|
||||
}
|
||||
|
|
|
@ -100,35 +100,8 @@ static int sh_debug; /* Debug flag */
|
|||
|
||||
#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
|
||||
|
||||
/*
|
||||
* Locking
|
||||
*/
|
||||
|
||||
static int shaper_lock(struct shaper *sh)
|
||||
{
|
||||
/*
|
||||
* Lock in an interrupt must fail
|
||||
*/
|
||||
while (test_and_set_bit(0, &sh->locked))
|
||||
{
|
||||
if (!in_interrupt())
|
||||
sleep_on(&sh->wait_queue);
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shaper_kick(struct shaper *sh);
|
||||
|
||||
static void shaper_unlock(struct shaper *sh)
|
||||
{
|
||||
clear_bit(0, &sh->locked);
|
||||
wake_up(&sh->wait_queue);
|
||||
shaper_kick(sh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute clocks on a buffer
|
||||
*/
|
||||
|
@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
|
|||
* Throw a frame at a shaper.
|
||||
*/
|
||||
|
||||
static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
|
||||
|
||||
static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct shaper *shaper = dev->priv;
|
||||
struct sk_buff *ptr;
|
||||
|
||||
/*
|
||||
* Get ready to work on this shaper. Lock may fail if its
|
||||
* an interrupt and locked.
|
||||
*/
|
||||
|
||||
if(!shaper_lock(shaper))
|
||||
return -1;
|
||||
if (down_trylock(&shaper->sem))
|
||||
return -1;
|
||||
|
||||
ptr=shaper->sendq.prev;
|
||||
|
||||
/*
|
||||
|
@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
|
|||
dev_kfree_skb(ptr);
|
||||
shaper->stats.collisions++;
|
||||
}
|
||||
shaper_unlock(shaper);
|
||||
shaper_kick(shaper);
|
||||
up(&shaper->sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
|
|||
|
||||
static void shaper_timer(unsigned long data)
|
||||
{
|
||||
struct shaper *sh=(struct shaper *)data;
|
||||
shaper_kick(sh);
|
||||
struct shaper *shaper = (struct shaper *)data;
|
||||
|
||||
if (!down_trylock(&shaper->sem)) {
|
||||
shaper_kick(shaper);
|
||||
up(&shaper->sem);
|
||||
} else
|
||||
mod_timer(&shaper->timer, jiffies);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -310,19 +287,6 @@ static void shaper_kick(struct shaper *shaper)
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/*
|
||||
* Shaper unlock will kick
|
||||
*/
|
||||
|
||||
if (test_and_set_bit(0, &shaper->locked))
|
||||
{
|
||||
if(sh_debug)
|
||||
printk("Shaper locked.\n");
|
||||
mod_timer(&shaper->timer, jiffies);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Walk the list (may be empty)
|
||||
*/
|
||||
|
@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper)
|
|||
|
||||
if(skb!=NULL)
|
||||
mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
|
||||
|
||||
clear_bit(0, &shaper->locked);
|
||||
}
|
||||
|
||||
|
||||
|
@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *shaper)
|
|||
static void shaper_flush(struct shaper *shaper)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
if(!shaper_lock(shaper))
|
||||
{
|
||||
printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
down(&shaper->sem);
|
||||
while((skb=skb_dequeue(&shaper->sendq))!=NULL)
|
||||
dev_kfree_skb(skb);
|
||||
shaper_unlock(shaper);
|
||||
shaper_kick(shaper);
|
||||
up(&shaper->sem);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -426,13 +386,6 @@ static int shaper_close(struct net_device *dev)
|
|||
* ARP and other resolutions and not before.
|
||||
*/
|
||||
|
||||
|
||||
static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct shaper *sh=dev->priv;
|
||||
return shaper_qframe(sh, skb);
|
||||
}
|
||||
|
||||
static struct net_device_stats *shaper_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct shaper *sh=dev->priv;
|
||||
|
@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev)
|
|||
init_timer(&sh->timer);
|
||||
sh->timer.function=shaper_timer;
|
||||
sh->timer.data=(unsigned long)sh;
|
||||
init_waitqueue_head(&sh->wait_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -665,15 +665,6 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
return ata_pci_init_one(pdev, port_info, n_ports);
|
||||
}
|
||||
|
||||
/**
|
||||
* piix_init -
|
||||
*
|
||||
* LOCKING:
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
*/
|
||||
|
||||
static int __init piix_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
@ -689,13 +680,6 @@ static int __init piix_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* piix_exit -
|
||||
*
|
||||
* LOCKING:
|
||||
*
|
||||
*/
|
||||
|
||||
static void __exit piix_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&piix_pci_driver);
|
||||
|
|
|
@ -186,6 +186,28 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
ata_wait_idle(ap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_tf_load - send taskfile registers to host controller
|
||||
* @ap: Port to which output is sent
|
||||
* @tf: ATA taskfile register set
|
||||
*
|
||||
* Outputs ATA taskfile to standard ATA host controller using MMIO
|
||||
* or PIO as indicated by the ATA_FLAG_MMIO flag.
|
||||
* Writes the control, feature, nsect, lbal, lbam, and lbah registers.
|
||||
* Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
|
||||
* hob_lbal, hob_lbam, and hob_lbah.
|
||||
*
|
||||
* This function waits for idle (!BUSY and !DRQ) after writing
|
||||
* registers. If the control register has a new value, this
|
||||
* function also waits for idle after writing control and before
|
||||
* writing the remaining registers.
|
||||
*
|
||||
* May be used as the tf_load() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -195,11 +217,11 @@ void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_exec_command - issue ATA command to host controller
|
||||
* ata_exec_command_pio - issue ATA command to host controller
|
||||
* @ap: port to which command is being issued
|
||||
* @tf: ATA taskfile register set
|
||||
*
|
||||
* Issues PIO/MMIO write to ATA command register, with proper
|
||||
* Issues PIO write to ATA command register, with proper
|
||||
* synchronization with interrupt handler / other threads.
|
||||
*
|
||||
* LOCKING:
|
||||
|
@ -235,6 +257,18 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
ata_pause(ap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_exec_command - issue ATA command to host controller
|
||||
* @ap: port to which command is being issued
|
||||
* @tf: ATA taskfile register set
|
||||
*
|
||||
* Issues PIO/MMIO write to ATA command register, with proper
|
||||
* synchronization with interrupt handler / other threads.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -305,7 +339,7 @@ void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_tf_read - input device's ATA taskfile shadow registers
|
||||
* ata_tf_read_pio - input device's ATA taskfile shadow registers
|
||||
* @ap: Port from which input is read
|
||||
* @tf: ATA taskfile register set for storing input
|
||||
*
|
||||
|
@ -368,6 +402,23 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_tf_read - input device's ATA taskfile shadow registers
|
||||
* @ap: Port from which input is read
|
||||
* @tf: ATA taskfile register set for storing input
|
||||
*
|
||||
* Reads ATA taskfile registers for currently-selected device
|
||||
* into @tf.
|
||||
*
|
||||
* Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
|
||||
* is set, also reads the hob registers.
|
||||
*
|
||||
* May be used as the tf_read() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -381,7 +432,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
|||
* @ap: port where the device is
|
||||
*
|
||||
* Reads ATA taskfile status register for currently-selected device
|
||||
* and return it's value. This also clears pending interrupts
|
||||
* and return its value. This also clears pending interrupts
|
||||
* from this device
|
||||
*
|
||||
* LOCKING:
|
||||
|
@ -397,7 +448,7 @@ static u8 ata_check_status_pio(struct ata_port *ap)
|
|||
* @ap: port where the device is
|
||||
*
|
||||
* Reads ATA taskfile status register for currently-selected device
|
||||
* via MMIO and return it's value. This also clears pending interrupts
|
||||
* via MMIO and return its value. This also clears pending interrupts
|
||||
* from this device
|
||||
*
|
||||
* LOCKING:
|
||||
|
@ -408,6 +459,20 @@ static u8 ata_check_status_mmio(struct ata_port *ap)
|
|||
return readb((void __iomem *) ap->ioaddr.status_addr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_check_status - Read device status reg & clear interrupt
|
||||
* @ap: port where the device is
|
||||
*
|
||||
* Reads ATA taskfile status register for currently-selected device
|
||||
* and return its value. This also clears pending interrupts
|
||||
* from this device
|
||||
*
|
||||
* May be used as the check_status() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
u8 ata_check_status(struct ata_port *ap)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -415,6 +480,20 @@ u8 ata_check_status(struct ata_port *ap)
|
|||
return ata_check_status_pio(ap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_altstatus - Read device alternate status reg
|
||||
* @ap: port where the device is
|
||||
*
|
||||
* Reads ATA taskfile alternate status register for
|
||||
* currently-selected device and return its value.
|
||||
*
|
||||
* Note: may NOT be used as the check_altstatus() entry in
|
||||
* ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
u8 ata_altstatus(struct ata_port *ap)
|
||||
{
|
||||
if (ap->ops->check_altstatus)
|
||||
|
@ -425,6 +504,20 @@ u8 ata_altstatus(struct ata_port *ap)
|
|||
return inb(ap->ioaddr.altstatus_addr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_chk_err - Read device error reg
|
||||
* @ap: port where the device is
|
||||
*
|
||||
* Reads ATA taskfile error register for
|
||||
* currently-selected device and return its value.
|
||||
*
|
||||
* Note: may NOT be used as the check_err() entry in
|
||||
* ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
u8 ata_chk_err(struct ata_port *ap)
|
||||
{
|
||||
if (ap->ops->check_err)
|
||||
|
@ -873,10 +966,24 @@ void ata_dev_id_string(u16 *id, unsigned char *s,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_noop_dev_select - Select device 0/1 on ATA bus
|
||||
* @ap: ATA channel to manipulate
|
||||
* @device: ATA device (numbered from zero) to select
|
||||
*
|
||||
* This function performs no actual function.
|
||||
*
|
||||
* May be used as the dev_select() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* caller.
|
||||
*/
|
||||
void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_std_dev_select - Select device 0/1 on ATA bus
|
||||
* @ap: ATA channel to manipulate
|
||||
|
@ -884,7 +991,9 @@ void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
|
|||
*
|
||||
* Use the method defined in the ATA specification to
|
||||
* make either device 0, or device 1, active on the
|
||||
* ATA channel.
|
||||
* ATA channel. Works with both PIO and MMIO.
|
||||
*
|
||||
* May be used as the dev_select() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* caller.
|
||||
|
@ -1190,7 +1299,12 @@ err_out:
|
|||
* ata_bus_probe - Reset and probe ATA bus
|
||||
* @ap: Bus to probe
|
||||
*
|
||||
* Master ATA bus probing function. Initiates a hardware-dependent
|
||||
* bus reset, then attempts to identify any devices found on
|
||||
* the bus.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, non-zero on error.
|
||||
|
@ -1229,10 +1343,14 @@ err_out:
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_port_probe -
|
||||
* @ap:
|
||||
* ata_port_probe - Mark port as enabled
|
||||
* @ap: Port for which we indicate enablement
|
||||
*
|
||||
* LOCKING:
|
||||
* Modify @ap data structure such that the system
|
||||
* thinks that the entire port is enabled.
|
||||
*
|
||||
* LOCKING: host_set lock, or some other form of
|
||||
* serialization.
|
||||
*/
|
||||
|
||||
void ata_port_probe(struct ata_port *ap)
|
||||
|
@ -1241,10 +1359,15 @@ void ata_port_probe(struct ata_port *ap)
|
|||
}
|
||||
|
||||
/**
|
||||
* __sata_phy_reset -
|
||||
* @ap:
|
||||
* __sata_phy_reset - Wake/reset a low-level SATA PHY
|
||||
* @ap: SATA port associated with target SATA PHY.
|
||||
*
|
||||
* This function issues commands to standard SATA Sxxx
|
||||
* PHY registers, to wake up the phy (and device), and
|
||||
* clear any reset condition.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
*/
|
||||
void __sata_phy_reset(struct ata_port *ap)
|
||||
|
@ -1289,10 +1412,14 @@ void __sata_phy_reset(struct ata_port *ap)
|
|||
}
|
||||
|
||||
/**
|
||||
* __sata_phy_reset -
|
||||
* @ap:
|
||||
* sata_phy_reset - Reset SATA bus.
|
||||
* @ap: SATA port associated with target SATA PHY.
|
||||
*
|
||||
* This function resets the SATA bus, and then probes
|
||||
* the bus for devices.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
*/
|
||||
void sata_phy_reset(struct ata_port *ap)
|
||||
|
@ -1304,10 +1431,16 @@ void sata_phy_reset(struct ata_port *ap)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_port_disable -
|
||||
* @ap:
|
||||
* ata_port_disable - Disable port.
|
||||
* @ap: Port to be disabled.
|
||||
*
|
||||
* LOCKING:
|
||||
* Modify @ap data structure such that the system
|
||||
* thinks that the entire port is disabled, and should
|
||||
* never attempt to probe or communicate with devices
|
||||
* on this port.
|
||||
*
|
||||
* LOCKING: host_set lock, or some other form of
|
||||
* serialization.
|
||||
*/
|
||||
|
||||
void ata_port_disable(struct ata_port *ap)
|
||||
|
@ -1416,7 +1549,10 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
|
|||
* ata_set_mode - Program timings and issue SET FEATURES - XFER
|
||||
* @ap: port on which timings will be programmed
|
||||
*
|
||||
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
*/
|
||||
static void ata_set_mode(struct ata_port *ap)
|
||||
|
@ -1467,7 +1603,10 @@ err_out:
|
|||
* @tmout_pat: impatience timeout
|
||||
* @tmout: overall timeout
|
||||
*
|
||||
* LOCKING:
|
||||
* Sleep until ATA Status register bit BSY clears,
|
||||
* or a timeout occurs.
|
||||
*
|
||||
* LOCKING: None.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -1553,10 +1692,14 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_bus_edd -
|
||||
* @ap:
|
||||
* ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
|
||||
* @ap: Port to reset and probe
|
||||
*
|
||||
* Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
|
||||
* probe the bus. Not often used these days.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -1633,8 +1776,8 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
|
|||
* the device is ATA or ATAPI.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller. Some functions called by this function
|
||||
* obtain the host_set lock.
|
||||
* PCI/etc. bus probe sem.
|
||||
* Obtains host_set lock.
|
||||
*
|
||||
* SIDE EFFECTS:
|
||||
* Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
|
||||
|
@ -1876,7 +2019,11 @@ static int fgb(u32 bitmap)
|
|||
* @xfer_mode_out: (output) SET FEATURES - XFER MODE code
|
||||
* @xfer_shift_out: (output) bit shift that selects this mode
|
||||
*
|
||||
* Based on host and device capabilities, determine the
|
||||
* maximum transfer mode that is amenable to all.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, negative on error.
|
||||
|
@ -1909,7 +2056,11 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
|
|||
* @ap: Port associated with device @dev
|
||||
* @dev: Device to which command will be sent
|
||||
*
|
||||
* Issue SET FEATURES - XFER MODE command to device @dev
|
||||
* on port @ap.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*/
|
||||
|
||||
static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
|
||||
|
@ -1947,10 +2098,13 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_sg_clean -
|
||||
* @qc:
|
||||
* ata_sg_clean - Unmap DMA memory associated with command
|
||||
* @qc: Command containing DMA memory to be released
|
||||
*
|
||||
* Unmap all mapped DMA memory associated with this command.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
static void ata_sg_clean(struct ata_queued_cmd *qc)
|
||||
|
@ -1981,7 +2135,11 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
|
|||
* ata_fill_sg - Fill PCI IDE PRD table
|
||||
* @qc: Metadata associated with taskfile to be transferred
|
||||
*
|
||||
* Fill PCI IDE PRD (scatter-gather) table with segments
|
||||
* associated with the current disk command.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
*/
|
||||
static void ata_fill_sg(struct ata_queued_cmd *qc)
|
||||
|
@ -2028,7 +2186,13 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
|
|||
* ata_check_atapi_dma - Check whether ATAPI DMA can be supported
|
||||
* @qc: Metadata associated with taskfile to check
|
||||
*
|
||||
* Allow low-level driver to filter ATA PACKET commands, returning
|
||||
* a status indicating whether or not it is OK to use DMA for the
|
||||
* supplied PACKET command.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
* RETURNS: 0 when ATAPI DMA can be used
|
||||
* nonzero otherwise
|
||||
*/
|
||||
|
@ -2046,6 +2210,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
|
|||
* ata_qc_prep - Prepare taskfile for submission
|
||||
* @qc: Metadata associated with taskfile to be prepared
|
||||
*
|
||||
* Prepare ATA taskfile for submission.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
@ -2057,6 +2223,32 @@ void ata_qc_prep(struct ata_queued_cmd *qc)
|
|||
ata_fill_sg(qc);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_sg_init_one - Associate command with memory buffer
|
||||
* @qc: Command to be associated
|
||||
* @buf: Memory buffer
|
||||
* @buflen: Length of memory buffer, in bytes.
|
||||
*
|
||||
* Initialize the data-related elements of queued_cmd @qc
|
||||
* to point to a single memory buffer, @buf of byte length @buflen.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ata_sg_init_one - Prepare a one-entry scatter-gather list.
|
||||
* @qc: Queued command
|
||||
* @buf: transfer buffer
|
||||
* @buflen: length of buf
|
||||
*
|
||||
* Builds a single-entry scatter-gather list to initiate a
|
||||
* transfer utilizing the specified buffer.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
|
@ -2074,6 +2266,32 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
|
|||
sg->length = buflen;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_sg_init - Associate command with scatter-gather table.
|
||||
* @qc: Command to be associated
|
||||
* @sg: Scatter-gather table.
|
||||
* @n_elem: Number of elements in s/g table.
|
||||
*
|
||||
* Initialize the data-related elements of queued_cmd @qc
|
||||
* to point to a scatter-gather table @sg, containing @n_elem
|
||||
* elements.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* ata_sg_init - Assign a scatter gather list to a queued command
|
||||
* @qc: Queued command
|
||||
* @sg: Scatter-gather list
|
||||
* @n_elem: length of sg list
|
||||
*
|
||||
* Attaches a scatter-gather list to a queued command.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
|
||||
unsigned int n_elem)
|
||||
{
|
||||
|
@ -2083,14 +2301,16 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_sg_setup_one -
|
||||
* @qc:
|
||||
* ata_sg_setup_one - DMA-map the memory buffer associated with a command.
|
||||
* @qc: Command with memory buffer to be mapped.
|
||||
*
|
||||
* DMA-map the memory buffer associated with queued_cmd @qc.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Zero on success, negative on error.
|
||||
*/
|
||||
|
||||
static int ata_sg_setup_one(struct ata_queued_cmd *qc)
|
||||
|
@ -2115,13 +2335,16 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_sg_setup -
|
||||
* @qc:
|
||||
* ata_sg_setup - DMA-map the scatter-gather table associated with a command.
|
||||
* @qc: Command with scatter-gather table to be mapped.
|
||||
*
|
||||
* DMA-map the scatter-gather table associated with queued_cmd @qc.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, negative on error.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -2151,6 +2374,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|||
* @ap:
|
||||
*
|
||||
* LOCKING:
|
||||
* None. (executing in kernel thread context)
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
|
@ -2198,6 +2422,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
|
|||
* @ap:
|
||||
*
|
||||
* LOCKING:
|
||||
* None. (executing in kernel thread context)
|
||||
*/
|
||||
|
||||
static void ata_pio_complete (struct ata_port *ap)
|
||||
|
@ -2240,6 +2465,18 @@ static void ata_pio_complete (struct ata_port *ap)
|
|||
ata_qc_complete(qc, drv_stat);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* swap_buf_le16 -
|
||||
* @buf: Buffer to swap
|
||||
* @buf_words: Number of 16-bit words in buffer.
|
||||
*
|
||||
* Swap halves of 16-bit words if needed to convert from
|
||||
* little-endian byte order to native cpu byte order, or
|
||||
* vice-versa.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
void swap_buf_le16(u16 *buf, unsigned int buf_words)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
|
@ -2415,6 +2652,7 @@ err_out:
|
|||
* @ap:
|
||||
*
|
||||
* LOCKING:
|
||||
* None. (executing in kernel thread context)
|
||||
*/
|
||||
|
||||
static void ata_pio_block(struct ata_port *ap)
|
||||
|
@ -2583,6 +2821,7 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
|
|||
* transaction completed successfully.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from SCSI layer (none, can sleep)
|
||||
*/
|
||||
|
||||
static void ata_qc_timeout(struct ata_queued_cmd *qc)
|
||||
|
@ -2692,6 +2931,7 @@ out:
|
|||
* @dev: Device from whom we request an available command structure
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*/
|
||||
|
||||
static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
|
||||
|
@ -2717,6 +2957,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
|
|||
* @dev: Device from whom we request an available command structure
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*/
|
||||
|
||||
struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
|
||||
|
@ -2781,6 +3022,7 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc)
|
|||
* in case something prevents using it.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
*/
|
||||
void ata_qc_free(struct ata_queued_cmd *qc)
|
||||
|
@ -2794,9 +3036,13 @@ void ata_qc_free(struct ata_queued_cmd *qc)
|
|||
/**
|
||||
* ata_qc_complete - Complete an active ATA command
|
||||
* @qc: Command to complete
|
||||
* @drv_stat: ATA status register contents
|
||||
* @drv_stat: ATA Status register contents
|
||||
*
|
||||
* Indicate to the mid and upper layers that an ATA
|
||||
* command has completed, with either an ok or not-ok status.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -2892,6 +3138,7 @@ err_out:
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
|
||||
* @qc: command to issue to device
|
||||
|
@ -2901,6 +3148,8 @@ err_out:
|
|||
* classes called "protocols", and issuing each type of protocol
|
||||
* is slightly different.
|
||||
*
|
||||
* May be used as the qc_issue() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
|
@ -2958,7 +3207,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_bmdma_setup - Set up PCI IDE BMDMA transaction
|
||||
* ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
|
||||
* @qc: Info associated with this ATA transaction.
|
||||
*
|
||||
* LOCKING:
|
||||
|
@ -3065,6 +3314,18 @@ static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
|
|||
ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_bmdma_start - Start a PCI IDE BMDMA transaction
|
||||
* @qc: Info associated with this ATA transaction.
|
||||
*
|
||||
* Writes the ATA_DMA_START flag to the DMA command register.
|
||||
*
|
||||
* May be used as the bmdma_start() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
void ata_bmdma_start(struct ata_queued_cmd *qc)
|
||||
{
|
||||
if (qc->ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -3073,6 +3334,20 @@ void ata_bmdma_start(struct ata_queued_cmd *qc)
|
|||
ata_bmdma_start_pio(qc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_bmdma_setup - Set up PCI IDE BMDMA transaction
|
||||
* @qc: Info associated with this ATA transaction.
|
||||
*
|
||||
* Writes address of PRD table to device's PRD Table Address
|
||||
* register, sets the DMA control register, and calls
|
||||
* ops->exec_command() to start the transfer.
|
||||
*
|
||||
* May be used as the bmdma_setup() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
void ata_bmdma_setup(struct ata_queued_cmd *qc)
|
||||
{
|
||||
if (qc->ap->flags & ATA_FLAG_MMIO)
|
||||
|
@ -3081,6 +3356,19 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
|
|||
ata_bmdma_setup_pio(qc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
|
||||
* @ap: Port associated with this ATA transaction.
|
||||
*
|
||||
* Clear interrupt and error flags in DMA status register.
|
||||
*
|
||||
* May be used as the irq_clear() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
void ata_bmdma_irq_clear(struct ata_port *ap)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO) {
|
||||
|
@ -3093,6 +3381,19 @@ void ata_bmdma_irq_clear(struct ata_port *ap)
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_bmdma_status - Read PCI IDE BMDMA status
|
||||
* @ap: Port associated with this ATA transaction.
|
||||
*
|
||||
* Read and return BMDMA status register.
|
||||
*
|
||||
* May be used as the bmdma_status() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
u8 ata_bmdma_status(struct ata_port *ap)
|
||||
{
|
||||
u8 host_stat;
|
||||
|
@ -3104,6 +3405,19 @@ u8 ata_bmdma_status(struct ata_port *ap)
|
|||
return host_stat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
|
||||
* @ap: Port associated with this ATA transaction.
|
||||
*
|
||||
* Clears the ATA_DMA_START flag in the dma control register
|
||||
*
|
||||
* May be used as the bmdma_stop() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
void ata_bmdma_stop(struct ata_port *ap)
|
||||
{
|
||||
if (ap->flags & ATA_FLAG_MMIO) {
|
||||
|
@ -3203,13 +3517,18 @@ idle_irq:
|
|||
|
||||
/**
|
||||
* ata_interrupt - Default ATA host interrupt handler
|
||||
* @irq: irq line
|
||||
* @dev_instance: pointer to our host information structure
|
||||
* @irq: irq line (unused)
|
||||
* @dev_instance: pointer to our ata_host_set information structure
|
||||
* @regs: unused
|
||||
*
|
||||
* Default interrupt handler for PCI IDE devices. Calls
|
||||
* ata_host_intr() for each port that is not disabled.
|
||||
*
|
||||
* LOCKING:
|
||||
* Obtains host_set lock during operation.
|
||||
*
|
||||
* RETURNS:
|
||||
* IRQ_NONE or IRQ_HANDLED.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -3302,6 +3621,19 @@ err_out:
|
|||
ata_qc_complete(qc, ATA_ERR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_port_start - Set port up for dma.
|
||||
* @ap: Port to initialize
|
||||
*
|
||||
* Called just after data structures for each port are
|
||||
* initialized. Allocates space for PRD table.
|
||||
*
|
||||
* May be used as the port_start() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
int ata_port_start (struct ata_port *ap)
|
||||
{
|
||||
struct device *dev = ap->host_set->dev;
|
||||
|
@ -3315,6 +3647,18 @@ int ata_port_start (struct ata_port *ap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_port_stop - Undo ata_port_start()
|
||||
* @ap: Port to shut down
|
||||
*
|
||||
* Frees the PRD table.
|
||||
*
|
||||
* May be used as the port_stop() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
void ata_port_stop (struct ata_port *ap)
|
||||
{
|
||||
struct device *dev = ap->host_set->dev;
|
||||
|
@ -3357,7 +3701,11 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
|
|||
* @ent: Probe information provided by low-level driver
|
||||
* @port_no: Port number associated with this ata_port
|
||||
*
|
||||
* Initialize a new ata_port structure, and its associated
|
||||
* scsi_host.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -3412,9 +3760,13 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
|
|||
* @host_set: Collections of ports to which we add
|
||||
* @port_no: Port number associated with this host
|
||||
*
|
||||
* Attach low-level ATA driver to system.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
* RETURNS:
|
||||
* New ata_port on success, for NULL on error.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -3447,12 +3799,22 @@ err_out:
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_device_add -
|
||||
* @ent:
|
||||
* ata_device_add - Register hardware device with ATA and SCSI layers
|
||||
* @ent: Probe information describing hardware device to be registered
|
||||
*
|
||||
* This function processes the information provided in the probe
|
||||
* information struct @ent, allocates the necessary ATA and SCSI
|
||||
* host information structures, initializes them, and registers
|
||||
* everything with requisite kernel subsystems.
|
||||
*
|
||||
* This function requests irqs, probes the ATA bus, and probes
|
||||
* the SCSI bus.
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
* RETURNS:
|
||||
* Number of ports registered. Zero on error (no ports registered).
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -3604,7 +3966,15 @@ int ata_scsi_release(struct Scsi_Host *host)
|
|||
/**
|
||||
* ata_std_ports - initialize ioaddr with standard port offsets.
|
||||
* @ioaddr: IO address structure to be initialized
|
||||
*
|
||||
* Utility function which initializes data_addr, error_addr,
|
||||
* feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
|
||||
* device_addr, status_addr, and command_addr to standard offsets
|
||||
* relative to cmd_addr.
|
||||
*
|
||||
* Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
|
||||
*/
|
||||
|
||||
void ata_std_ports(struct ata_ioports *ioaddr)
|
||||
{
|
||||
ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
|
||||
|
@ -3646,6 +4016,20 @@ ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
|
|||
return probe_ent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ata_pci_init_native_mode - Initialize native-mode driver
|
||||
* @pdev: pci device to be initialized
|
||||
* @port: array[2] of pointers to port info structures.
|
||||
*
|
||||
* Utility function which allocates and initializes an
|
||||
* ata_probe_ent structure for a standard dual-port
|
||||
* PIO-based IDE controller. The returned ata_probe_ent
|
||||
* structure can be passed to ata_device_add(). The returned
|
||||
* ata_probe_ent structure should then be freed with kfree().
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
struct ata_probe_ent *
|
||||
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
|
||||
|
@ -3727,10 +4111,19 @@ ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port,
|
|||
* @port_info: Information from low-level host driver
|
||||
* @n_ports: Number of ports attached to host controller
|
||||
*
|
||||
* This is a helper function which can be called from a driver's
|
||||
* xxx_init_one() probe function if the hardware uses traditional
|
||||
* IDE taskfile registers.
|
||||
*
|
||||
* This function calls pci_enable_device(), reserves its register
|
||||
* regions, sets the dma mask, enables bus master mode, and calls
|
||||
* ata_device_add()
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from PCI layer (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, negative on errno-based value on error.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -3949,15 +4342,6 @@ int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits)
|
|||
#endif /* CONFIG_PCI */
|
||||
|
||||
|
||||
/**
|
||||
* ata_init -
|
||||
*
|
||||
* LOCKING:
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
*/
|
||||
|
||||
static int __init ata_init(void)
|
||||
{
|
||||
ata_wq = create_workqueue("ata");
|
||||
|
|
|
@ -947,7 +947,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
|
|||
}
|
||||
|
||||
/**
|
||||
* ata_scsiop_noop -
|
||||
* ata_scsiop_noop - Command handler that simply returns success.
|
||||
* @args: device IDENTIFY data / SCSI command of interest.
|
||||
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
|
||||
* @buflen: Response buffer length.
|
||||
|
|
|
@ -507,6 +507,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||
int ret, i;
|
||||
unsigned int id, lun;
|
||||
unsigned long serial;
|
||||
unsigned long flags;
|
||||
|
||||
if (!CMD_SP(cmd))
|
||||
return FAILED;
|
||||
|
@ -519,7 +520,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||
|
||||
/* Check active list for command command. */
|
||||
spin_unlock_irq(ha->host->host_lock);
|
||||
spin_lock(&ha->hardware_lock);
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
|
||||
sp = ha->outstanding_cmds[i];
|
||||
|
||||
|
@ -534,7 +535,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||
sp->state));
|
||||
DEBUG3(qla2x00_print_scsi_cmd(cmd);)
|
||||
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if (qla2x00_abort_command(ha, sp)) {
|
||||
DEBUG2(printk("%s(%ld): abort_command "
|
||||
"mbx failed.\n", __func__, ha->host_no));
|
||||
|
@ -543,20 +544,19 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||
"mbx success.\n", __func__, ha->host_no));
|
||||
ret = SUCCESS;
|
||||
}
|
||||
spin_lock(&ha->hardware_lock);
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
/* Wait for the command to be returned. */
|
||||
if (ret == SUCCESS) {
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
|
||||
qla_printk(KERN_ERR, ha,
|
||||
"scsi(%ld:%d:%d): Abort handler timed out -- %lx "
|
||||
"%x.\n", ha->host_no, id, lun, serial, ret);
|
||||
}
|
||||
spin_lock(&ha->hardware_lock);
|
||||
}
|
||||
spin_lock_irq(ha->host->host_lock);
|
||||
|
||||
|
@ -588,6 +588,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
|
|||
int status;
|
||||
srb_t *sp;
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned long flags;
|
||||
|
||||
status = 0;
|
||||
|
||||
|
@ -596,11 +597,11 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
|
|||
* array
|
||||
*/
|
||||
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
|
||||
spin_lock(&ha->hardware_lock);
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
sp = ha->outstanding_cmds[cnt];
|
||||
if (sp) {
|
||||
cmd = sp->cmd;
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if (cmd->device->id == t) {
|
||||
if (!qla2x00_eh_wait_on_command(ha, cmd)) {
|
||||
status = 1;
|
||||
|
@ -608,7 +609,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
}
|
||||
return (status);
|
||||
|
@ -740,6 +741,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
|
|||
int status;
|
||||
srb_t *sp;
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned long flags;
|
||||
|
||||
status = 1;
|
||||
|
||||
|
@ -748,17 +750,17 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
|
|||
* array
|
||||
*/
|
||||
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
|
||||
spin_lock(&ha->hardware_lock);
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
sp = ha->outstanding_cmds[cnt];
|
||||
if (sp) {
|
||||
cmd = sp->cmd;
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
status = qla2x00_eh_wait_on_command(ha, cmd);
|
||||
if (status == 0)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
spin_unlock(&ha->hardware_lock);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
}
|
||||
return (status);
|
||||
|
|
|
@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
|
|||
if (!starget)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
get_device(&starget->dev);
|
||||
down(&shost->scan_mutex);
|
||||
res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
|
||||
if (res != SCSI_SCAN_LUN_PRESENT)
|
||||
|
|
|
@ -234,7 +234,7 @@ static inline const char *siu_type_name(struct uart_port *port)
|
|||
return "DSIU";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int siu_tx_empty(struct uart_port *port)
|
||||
|
@ -482,9 +482,6 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
struct uart_port *port;
|
||||
uint8_t iir, lsr;
|
||||
|
||||
if (dev_id == NULL)
|
||||
return IRQ_NONE;
|
||||
|
||||
port = (struct uart_port *)dev_id;
|
||||
|
||||
iir = siu_read(port, UART_IIR);
|
||||
|
@ -507,6 +504,9 @@ static int siu_startup(struct uart_port *port)
|
|||
{
|
||||
int retval;
|
||||
|
||||
if (port->membase == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
siu_clear_fifo(port);
|
||||
|
||||
(void)siu_read(port, UART_LSR);
|
||||
|
@ -545,9 +545,6 @@ static void siu_shutdown(struct uart_port *port)
|
|||
unsigned long flags;
|
||||
uint8_t lcr;
|
||||
|
||||
if (port->membase == NULL)
|
||||
return;
|
||||
|
||||
siu_write(port, UART_IER, 0);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -802,53 +799,6 @@ static int siu_init_ports(void)
|
|||
|
||||
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
|
||||
|
||||
static void early_set_termios(struct uart_port *port, struct termios *new,
|
||||
struct termios *old)
|
||||
{
|
||||
tcflag_t c_cflag;
|
||||
uint8_t lcr;
|
||||
unsigned int baud, quot;
|
||||
|
||||
c_cflag = new->c_cflag;
|
||||
switch (c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
lcr = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
if (c_cflag & PARENB)
|
||||
lcr |= UART_LCR_PARITY;
|
||||
if ((c_cflag & PARODD) != PARODD)
|
||||
lcr |= UART_LCR_EPAR;
|
||||
if (c_cflag & CMSPAR)
|
||||
lcr |= UART_LCR_SPAR;
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
|
||||
siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
|
||||
|
||||
siu_write(port, UART_DLL, (uint8_t)quot);
|
||||
siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
|
||||
|
||||
siu_write(port, UART_LCR, lcr);
|
||||
}
|
||||
|
||||
static struct uart_ops early_uart_ops = {
|
||||
.set_termios = early_set_termios,
|
||||
};
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void wait_for_xmitr(struct uart_port *port)
|
||||
|
@ -915,7 +865,7 @@ static int siu_console_setup(struct console *con, char *options)
|
|||
if (port->membase == NULL) {
|
||||
if (port->mapbase == 0)
|
||||
return -ENODEV;
|
||||
port->membase = (unsigned char __iomem *)KSEG1ADDR(port->mapbase);
|
||||
port->membase = ioremap(port->mapbase, siu_port_size(port));
|
||||
}
|
||||
|
||||
vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
|
||||
|
@ -949,7 +899,7 @@ static int __devinit siu_console_init(void)
|
|||
|
||||
for (i = 0; i < num; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
port->ops = &early_uart_ops;
|
||||
port->ops = &siu_uart_ops;
|
||||
}
|
||||
|
||||
register_console(&siu_console);
|
||||
|
@ -994,8 +944,10 @@ static int siu_probe(struct device *dev)
|
|||
port->dev = dev;
|
||||
|
||||
retval = uart_add_one_port(&siu_uart_driver, port);
|
||||
if (retval)
|
||||
if (retval < 0) {
|
||||
port->dev = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0 && retval < 0) {
|
||||
|
|
|
@ -290,32 +290,30 @@ static ssize_t show_modalias(struct device *dev, char *buf)
|
|||
{
|
||||
struct usb_interface *intf;
|
||||
struct usb_device *udev;
|
||||
int len;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
udev = interface_to_usbdev(intf);
|
||||
if (udev->descriptor.bDeviceClass == 0) {
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
|
||||
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X\n",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct),
|
||||
le16_to_cpu(udev->descriptor.bcdDevice),
|
||||
udev->descriptor.bDeviceClass,
|
||||
udev->descriptor.bDeviceSubClass,
|
||||
udev->descriptor.bDeviceProtocol,
|
||||
alt->desc.bInterfaceClass,
|
||||
alt->desc.bInterfaceSubClass,
|
||||
alt->desc.bInterfaceProtocol);
|
||||
} else {
|
||||
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*\n",
|
||||
len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct),
|
||||
le16_to_cpu(udev->descriptor.bcdDevice),
|
||||
udev->descriptor.bDeviceClass,
|
||||
udev->descriptor.bDeviceSubClass,
|
||||
udev->descriptor.bDeviceProtocol);
|
||||
}
|
||||
buf += len;
|
||||
|
||||
if (udev->descriptor.bDeviceClass == 0) {
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
|
||||
return len + sprintf(buf, "%02Xisc%02Xip%02X\n",
|
||||
alt->desc.bInterfaceClass,
|
||||
alt->desc.bInterfaceSubClass,
|
||||
alt->desc.bInterfaceProtocol);
|
||||
} else {
|
||||
return len + sprintf(buf, "*isc*ip*\n");
|
||||
}
|
||||
}
|
||||
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
|
||||
|
||||
|
|
|
@ -1315,6 +1315,8 @@ void hid_init_reports(struct hid_device *hid)
|
|||
#define USB_DEVICE_ID_WACOM_INTUOS2 0x0040
|
||||
#define USB_DEVICE_ID_WACOM_VOLITO 0x0060
|
||||
#define USB_DEVICE_ID_WACOM_PTU 0x0003
|
||||
#define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0
|
||||
#define USB_DEVICE_ID_WACOM_CINTIQ 0x003F
|
||||
|
||||
#define USB_VENDOR_ID_KBGEAR 0x084e
|
||||
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
|
||||
|
@ -1401,6 +1403,7 @@ void hid_init_reports(struct hid_device *hid)
|
|||
|
||||
#define USB_VENDOR_ID_DELORME 0x1163
|
||||
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
||||
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
|
||||
|
||||
#define USB_VENDOR_ID_MCC 0x09db
|
||||
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
|
||||
|
@ -1412,6 +1415,12 @@ void hid_init_reports(struct hid_device *hid)
|
|||
#define USB_VENDOR_ID_BTC 0x046e
|
||||
#define USB_DEVICE_ID_BTC_KEYBOARD 0x5303
|
||||
|
||||
#define USB_VENDOR_ID_VERNIER 0x08f7
|
||||
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
|
||||
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
|
||||
#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
|
||||
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
|
||||
|
||||
|
||||
/*
|
||||
* Alphabetically sorted blacklist by quirk type.
|
||||
|
@ -1437,6 +1446,7 @@ static struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
|
||||
|
@ -1456,6 +1466,10 @@ static struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
|
||||
|
@ -1481,6 +1495,10 @@ static struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
|
||||
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
9.0.2
|
||||
|
||||
* Adding #ifdef to compile PWC before and after 2.6.5
|
||||
|
||||
9.0.1
|
||||
|
||||
9.0
|
||||
|
||||
|
||||
8.12
|
||||
|
||||
* Implement motorized pan/tilt feature for Logitech QuickCam Orbit/Spere.
|
||||
|
||||
8.11.1
|
||||
|
||||
* Fix for PCVC720/40, would not be able to set videomode
|
||||
* Fix for Samsung MPC models, appearantly they are based on a newer chipset
|
||||
|
||||
8.11
|
||||
|
||||
* 20 dev_hints (per request)
|
||||
* Hot unplugging should be better, no more dangling pointers or memory leaks
|
||||
* Added reserved Logitech webcam IDs
|
||||
* Device now remembers size & fps between close()/open()
|
||||
* Removed palette stuff altogether
|
||||
|
||||
8.10.1
|
||||
|
||||
* Added IDs for PCVC720K/40 and Creative Labs Webcam Pro
|
||||
|
||||
8.10
|
||||
|
||||
* Fixed ID for QuickCam Notebook pro
|
||||
* Added GREALSIZE ioctl() call
|
||||
* Fixed bug in case PWCX was not loaded and invalid size was set
|
||||
|
||||
8.9
|
||||
|
||||
* Merging with kernel 2.5.49
|
||||
* Adding IDs for QuickCam Zoom & QuickCam Notebook
|
||||
|
||||
8.8
|
||||
|
||||
* Fixing 'leds' parameter
|
||||
* Adding IDs for Logitech QuickCam Pro 4000
|
||||
* Making URB init/cleanup a little nicer
|
||||
|
||||
8.7
|
||||
|
||||
* Incorporating changes in ioctl() parameter passing
|
||||
* Also changes to URB mechanism
|
||||
|
||||
8.6
|
||||
|
||||
* Added ID's for Visionite VCS UM100 and UC300
|
||||
* Removed YUV420-interlaced palette altogether (was confusing)
|
||||
* Removed MIRROR stuff as it didn't work anyway
|
||||
* Fixed a problem with the 'leds' parameter (wouldn't blink)
|
||||
* Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s,
|
||||
CONTOUR, BACKLIGHT, FLICKER, DYNNOISE.
|
||||
* VIDIOCGCAP.name now contains real camera model name instead of
|
||||
'Philips xxx webcam'
|
||||
* Added PROBE ioctl (see previous point & API doc)
|
||||
|
||||
8.5
|
||||
|
||||
* Adding IDs for Creative Labs Webcam 5
|
||||
* Adding IDs for SOTEC CMS-001 webcam
|
||||
* Solving possible hang in VIDIOCSYNC when unplugging the cam
|
||||
* Forgot to return structure in VIDIOCPWCGAWB, oops
|
||||
* Time interval for the LEDs are now in milliseconds
|
||||
|
||||
8.4
|
||||
|
||||
* Fixing power_save option for Vesta range
|
||||
* Handling new error codes in ISOC callback
|
||||
* Adding dev_hint module parameter, to specify /dev/videoX device nodes
|
||||
|
||||
8.3
|
||||
|
||||
* Adding Samsung C10 and C30 cameras
|
||||
* Removing palette module parameter
|
||||
* Fixed typo in ID of QuickCam 3000 Pro
|
||||
* Adding LED settings (blinking while in use) for ToUCam cameras.
|
||||
* Turns LED off when camera is not in use.
|
||||
|
||||
8.2
|
||||
|
||||
* Making module more silent when trace = 0
|
||||
* Adding QuickCam 3000 Pro IDs
|
||||
* Chrominance control for the Vesta cameras
|
||||
* Hopefully fixed problems on machines with BIGMEM and > 1GB of RAM
|
||||
* Included Oliver Neukem's lock_kernel() patch
|
||||
* Allocates less memory for image buffers
|
||||
* Adds ioctl()s for the whitebalancing
|
||||
|
||||
8.1
|
||||
|
||||
* Adding support for 750
|
||||
* Adding V4L GAUDIO/SAUDIO/UNIT ioctl() calls
|
||||
|
||||
8.0
|
||||
* 'damage control' after inclusion in 2.4.5.
|
||||
* Changed wait-queue mechanism in read/mmap/poll according to the book.
|
||||
* Included YUV420P palette.
|
||||
* Changed interface to decompressor module.
|
||||
* Cleaned up pwc structure a bit.
|
||||
|
||||
7.0
|
||||
|
||||
* Fixed bug in vcvt_420i_yuyv; extra variables on stack were misaligned.
|
||||
* There is now a clear error message when an image size is selected that
|
||||
is only supported using the decompressor, and the decompressor isn't
|
||||
loaded.
|
||||
* When the decompressor wasn't loaded, selecting large image size
|
||||
would create skewed or double images.
|
||||
|
||||
6.3
|
||||
|
||||
* Introduced spinlocks for the buffer pointer manipulation; a number of
|
||||
reports seem to suggest the down()/up() semaphores were the cause of
|
||||
lockups, since they are not suitable for interrupt/user locking.
|
||||
* Separated decompressor and core code into 2 modules.
|
||||
|
||||
6.2
|
||||
|
||||
* Non-integral image sizes are now padded with gray or black.
|
||||
* Added SHUTTERSPEED ioctl().
|
||||
* Fixed buglet in VIDIOCPWCSAGC; the function would always return an error,
|
||||
even though the call succeeded.
|
||||
* Added hotplug support for 2.4.*.
|
||||
* Memory: the 645/646 uses less memory now.
|
||||
|
||||
6.1
|
||||
|
||||
* VIDIOCSPICT returns -EINVAL with invalid palettes.
|
||||
* Added saturation control.
|
||||
* Split decompressors from rest.
|
||||
* Fixed bug that would reset the framerate to the default framerate if
|
||||
the rate field was set to 0 (which is not what I intended, nl. do not
|
||||
change the framerate!).
|
||||
* VIDIOCPWCSCQUAL (setting compression quality) now takes effect immediately.
|
||||
* Workaround for a bug in the 730 sensor.
|
|
@ -2765,7 +2765,7 @@ static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf)
|
|||
}
|
||||
/* expect bcdVersion 1.0, ignore */
|
||||
if (memcmp(&desc->bGUID, blan_guid, 16)
|
||||
&& memcmp(&desc->bGUID, blan_guid, 16) ) {
|
||||
&& memcmp(&desc->bGUID, safe_guid, 16) ) {
|
||||
/* hey, this one might _really_ be MDLM! */
|
||||
dev_dbg (&intf->dev, "MDLM guid\n");
|
||||
goto bad_desc;
|
||||
|
|
|
@ -455,6 +455,17 @@ config USB_SERIAL_XIRCOM
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called keyspan_pda.
|
||||
|
||||
config USB_SERIAL_OPTION
|
||||
tristate "USB Option PCMCIA serial driver"
|
||||
depends on USB_SERIAL && USB_OHCI_HCD && PCCARD
|
||||
help
|
||||
Say Y here if you want to use an Option card. This is a
|
||||
GSM card, controlled by three serial ports which are connected
|
||||
via an OHCI adapter located on a PC card.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called option.
|
||||
|
||||
config USB_SERIAL_OMNINET
|
||||
tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
|
||||
depends on USB_SERIAL && EXPERIMENTAL
|
||||
|
|
|
@ -32,6 +32,7 @@ obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
|
|||
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
|
||||
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
|
||||
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
|
||||
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
|
||||
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
|
||||
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
|
||||
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Support to set flow control line levels using TIOCMGET and TIOCMSET
|
||||
* thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
|
||||
* control thanks to Munir Nassar nassarmu@real-time.com
|
||||
*
|
||||
* Outstanding Issues:
|
||||
* Buffers are not flushed when the port is opened.
|
||||
* Multiple calls to write() may fail with "Resource temporarily unavailable"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
@ -24,7 +32,7 @@
|
|||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.03"
|
||||
#define DRIVER_VERSION "v0.04"
|
||||
#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
|
||||
|
||||
/*
|
||||
|
@ -35,6 +43,9 @@ static void cp2101_cleanup(struct usb_serial_port*);
|
|||
static void cp2101_close(struct usb_serial_port*, struct file*);
|
||||
static void cp2101_get_termios(struct usb_serial_port*);
|
||||
static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
|
||||
static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
|
||||
static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
|
||||
unsigned int, unsigned int);
|
||||
static void cp2101_break_ctl(struct usb_serial_port*, int);
|
||||
static int cp2101_startup (struct usb_serial *);
|
||||
static void cp2101_shutdown(struct usb_serial*);
|
||||
|
@ -43,9 +54,10 @@ static void cp2101_shutdown(struct usb_serial*);
|
|||
static int debug;
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
{USB_DEVICE(0x10c4, 0xea60) }, /*Silicon labs factory default*/
|
||||
{USB_DEVICE(0x10ab, 0x10c5) }, /*Siemens MC60 Cable*/
|
||||
{ } /* Terminating Entry*/
|
||||
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
|
||||
{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
|
||||
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
|
@ -70,32 +82,35 @@ static struct usb_serial_device_type cp2101_device = {
|
|||
.close = cp2101_close,
|
||||
.break_ctl = cp2101_break_ctl,
|
||||
.set_termios = cp2101_set_termios,
|
||||
.tiocmget = cp2101_tiocmget,
|
||||
.tiocmset = cp2101_tiocmset,
|
||||
.attach = cp2101_startup,
|
||||
.shutdown = cp2101_shutdown,
|
||||
};
|
||||
|
||||
/*Config request types*/
|
||||
/* Config request types */
|
||||
#define REQTYPE_HOST_TO_DEVICE 0x41
|
||||
#define REQTYPE_DEVICE_TO_HOST 0xc1
|
||||
|
||||
/*Config SET requests. To GET, add 1 to the request number*/
|
||||
#define CP2101_UART 0x00 /*Enable / Disable*/
|
||||
#define CP2101_BAUDRATE 0x01 /*(BAUD_RATE_GEN_FREQ / baudrate)*/
|
||||
#define CP2101_BITS 0x03 /*0x(0)(data bits)(parity)(stop bits)*/
|
||||
#define CP2101_BREAK 0x05 /*On / Off*/
|
||||
#define CP2101_DTRRTS 0x07 /*101 / 202 ???*/
|
||||
#define CP2101_CONFIG_16 0x13 /*16 bytes of config data ???*/
|
||||
#define CP2101_CONFIG_6 0x19 /*6 bytes of config data ???*/
|
||||
/* Config SET requests. To GET, add 1 to the request number */
|
||||
#define CP2101_UART 0x00 /* Enable / Disable */
|
||||
#define CP2101_BAUDRATE 0x01 /* (BAUD_RATE_GEN_FREQ / baudrate) */
|
||||
#define CP2101_BITS 0x03 /* 0x(0)(databits)(parity)(stopbits) */
|
||||
#define CP2101_BREAK 0x05 /* On / Off */
|
||||
#define CP2101_CONTROL 0x07 /* Flow control line states */
|
||||
#define CP2101_MODEMCTL 0x13 /* Modem controls */
|
||||
#define CP2101_CONFIG_6 0x19 /* 6 bytes of config data ??? */
|
||||
|
||||
/*CP2101_UART*/
|
||||
/* CP2101_UART */
|
||||
#define UART_ENABLE 0x0001
|
||||
#define UART_DISABLE 0x0000
|
||||
|
||||
/*CP2101_BAUDRATE*/
|
||||
/* CP2101_BAUDRATE */
|
||||
#define BAUD_RATE_GEN_FREQ 0x384000
|
||||
|
||||
/*CP2101_BITS*/
|
||||
/* CP2101_BITS */
|
||||
#define BITS_DATA_MASK 0X0f00
|
||||
#define BITS_DATA_5 0X0500
|
||||
#define BITS_DATA_6 0X0600
|
||||
#define BITS_DATA_7 0X0700
|
||||
#define BITS_DATA_8 0X0800
|
||||
|
@ -112,64 +127,137 @@ static struct usb_serial_device_type cp2101_device = {
|
|||
#define BITS_STOP_1 0x0000
|
||||
#define BITS_STOP_1_5 0x0001
|
||||
#define BITS_STOP_2 0x0002
|
||||
|
||||
/* CP2101_BREAK */
|
||||
#define BREAK_ON 0x0000
|
||||
#define BREAK_OFF 0x0001
|
||||
|
||||
/* CP2101_CONTROL */
|
||||
#define CONTROL_DTR 0x0001
|
||||
#define CONTROL_RTS 0x0002
|
||||
#define CONTROL_CTS 0x0010
|
||||
#define CONTROL_DSR 0x0020
|
||||
#define CONTROL_RING 0x0040
|
||||
#define CONTROL_DCD 0x0080
|
||||
#define CONTROL_WRITE_DTR 0x0100
|
||||
#define CONTROL_WRITE_RTS 0x0200
|
||||
|
||||
static int cp2101_get_config(struct usb_serial_port* port, u8 request)
|
||||
/*
|
||||
* cp2101_get_config
|
||||
* Reads from the CP2101 configuration registers
|
||||
* 'size' is specified in bytes.
|
||||
* 'data' is a pointer to a pre-allocated array of integers large
|
||||
* enough to hold 'size' bytes (with 4 bytes to each integer)
|
||||
*/
|
||||
static int cp2101_get_config(struct usb_serial_port* port, u8 request,
|
||||
unsigned int *data, int size)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
unsigned char buf[4];
|
||||
unsigned int value;
|
||||
int result, i;
|
||||
u32 *buf;
|
||||
int result, i, length;
|
||||
|
||||
/*For get requests, the request number must be incremented*/
|
||||
/* Number of integers required to contain the array */
|
||||
length = (((size - 1) | 3) + 1)/4;
|
||||
|
||||
buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
|
||||
memset(buf, 0, length * sizeof(u32));
|
||||
|
||||
if (!buf) {
|
||||
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* For get requests, the request number must be incremented */
|
||||
request++;
|
||||
|
||||
/*Issue the request, attempting to read 4 bytes*/
|
||||
/* Issue the request, attempting to read 'size' bytes */
|
||||
result = usb_control_msg (serial->dev,usb_rcvctrlpipe (serial->dev, 0),
|
||||
request, REQTYPE_DEVICE_TO_HOST, 0x0000,
|
||||
0, buf, 4, 300);
|
||||
0, buf, size, 300);
|
||||
|
||||
if (result < 0) {
|
||||
/* Convert data into an array of integers */
|
||||
for (i=0; i<length; i++)
|
||||
data[i] = le32_to_cpu(buf[i]);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if (result != size) {
|
||||
dev_err(&port->dev, "%s - Unable to send config request, "
|
||||
"request=0x%x result=%d\n",
|
||||
__FUNCTION__, request, result);
|
||||
return result;
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
__FUNCTION__, request, size, result);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
/*Assemble each byte read into an integer value*/
|
||||
value = 0;
|
||||
for (i=0; i<4 && i<result; i++)
|
||||
value |= (buf[i] << (i * 8));
|
||||
|
||||
dbg( " %s - request=0x%x result=%d value=0x%x",
|
||||
__FUNCTION__, request, result, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int cp2101_set_config(struct usb_serial_port* port, u8 request, u16 value)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
int result;
|
||||
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
request, REQTYPE_HOST_TO_DEVICE, value,
|
||||
0, NULL, 0, 300);
|
||||
|
||||
if (result <0) {
|
||||
dev_err(&port->dev, "%s - Unable to send config request, "
|
||||
"request=0x%x value=0x%x result=%d\n",
|
||||
__FUNCTION__, request, value, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
dbg(" %s - request=0x%x value=0x%x result=%d",
|
||||
__FUNCTION__, request, value, result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cp2101_set_config
|
||||
* Writes to the CP2101 configuration registers
|
||||
* Values less than 16 bits wide are sent directly
|
||||
* 'size' is specified in bytes.
|
||||
*/
|
||||
static int cp2101_set_config(struct usb_serial_port* port, u8 request,
|
||||
unsigned int *data, int size)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
u32 *buf;
|
||||
int result, i, length;
|
||||
|
||||
/* Number of integers required to contain the array */
|
||||
length = (((size - 1) | 3) + 1)/4;
|
||||
|
||||
buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
dev_err(&port->dev, "%s - out of memory.\n",
|
||||
__FUNCTION__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Array of integers into bytes */
|
||||
for (i = 0; i < length; i++)
|
||||
buf[i] = cpu_to_le32(data[i]);
|
||||
|
||||
if (size > 2) {
|
||||
result = usb_control_msg (serial->dev,
|
||||
usb_sndctrlpipe(serial->dev, 0),
|
||||
request, REQTYPE_HOST_TO_DEVICE, 0x0000,
|
||||
0, buf, size, 300);
|
||||
} else {
|
||||
result = usb_control_msg (serial->dev,
|
||||
usb_sndctrlpipe(serial->dev, 0),
|
||||
request, REQTYPE_HOST_TO_DEVICE, data[0],
|
||||
0, NULL, 0, 300);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if ((size > 2 && result != size) || result < 0) {
|
||||
dev_err(&port->dev, "%s - Unable to send request, "
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
__FUNCTION__, request, size, result);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
/* Single data value */
|
||||
result = usb_control_msg (serial->dev,
|
||||
usb_sndctrlpipe(serial->dev, 0),
|
||||
request, REQTYPE_HOST_TO_DEVICE, data[0],
|
||||
0, NULL, 0, 300);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cp2101_set_config_single
|
||||
* Convenience function for calling cp2101_set_config on single data values
|
||||
* without requiring an integer pointer
|
||||
*/
|
||||
static inline int cp2101_set_config_single(struct usb_serial_port* port,
|
||||
u8 request, unsigned int data)
|
||||
{
|
||||
return cp2101_set_config(port, request, &data, 2);
|
||||
}
|
||||
|
||||
static int cp2101_open (struct usb_serial_port *port, struct file *filp)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
@ -177,7 +265,7 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
|
|||
|
||||
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||
|
||||
if (cp2101_set_config(port, CP2101_UART, UART_ENABLE)) {
|
||||
if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
|
||||
dev_err(&port->dev, "%s - Unable to enable UART\n",
|
||||
__FUNCTION__);
|
||||
return -EPROTO;
|
||||
|
@ -198,9 +286,12 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*Configure the termios structure*/
|
||||
/* Configure the termios structure */
|
||||
cp2101_get_termios(port);
|
||||
|
||||
/* Set the DTR and RTS pins low */
|
||||
cp2101_tiocmset(port, NULL, TIOCM_DTR | TIOCM_RTS, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,16 +319,18 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
|
|||
usb_kill_urb(port->write_urb);
|
||||
usb_kill_urb(port->read_urb);
|
||||
|
||||
cp2101_set_config(port, CP2101_UART, UART_DISABLE);
|
||||
cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
|
||||
}
|
||||
|
||||
/* cp2101_get_termios*/
|
||||
/* Reads the baud rate, data bits, parity and stop bits from the device*/
|
||||
/* Corrects any unsupported values*/
|
||||
/* Configures the termios structure to reflect the state of the device*/
|
||||
/*
|
||||
* cp2101_get_termios
|
||||
* Reads the baud rate, data bits, parity, stop bits and flow control mode
|
||||
* from the device, corrects any unsupported values, and configures the
|
||||
* termios structure to reflect the state of the device
|
||||
*/
|
||||
static void cp2101_get_termios (struct usb_serial_port *port)
|
||||
{
|
||||
unsigned int cflag;
|
||||
unsigned int cflag, modem_ctl[4];
|
||||
int baud;
|
||||
int bits;
|
||||
|
||||
|
@ -249,15 +342,16 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
}
|
||||
cflag = port->tty->termios->c_cflag;
|
||||
|
||||
baud = cp2101_get_config(port, CP2101_BAUDRATE);
|
||||
/*Convert to baudrate*/
|
||||
cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
|
||||
/* Convert to baudrate */
|
||||
if (baud)
|
||||
baud = BAUD_RATE_GEN_FREQ / baud;
|
||||
|
||||
dbg("%s - baud rate = %d", __FUNCTION__, baud);
|
||||
cflag &= ~CBAUD;
|
||||
switch (baud) {
|
||||
/* The baud rates which are commented out below
|
||||
/*
|
||||
* The baud rates which are commented out below
|
||||
* appear to be supported by the device
|
||||
* but are non-standard
|
||||
*/
|
||||
|
@ -284,14 +378,18 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
dbg("%s - Baud rate is not supported, "
|
||||
"using 9600 baud", __FUNCTION__);
|
||||
cflag |= B9600;
|
||||
cp2101_set_config(port, CP2101_BAUDRATE,
|
||||
cp2101_set_config_single(port, CP2101_BAUDRATE,
|
||||
(BAUD_RATE_GEN_FREQ/9600));
|
||||
break;
|
||||
}
|
||||
|
||||
bits = cp2101_get_config(port, CP2101_BITS);
|
||||
cp2101_get_config(port, CP2101_BITS, &bits, 2);
|
||||
cflag &= ~CSIZE;
|
||||
switch(bits & BITS_DATA_MASK) {
|
||||
case BITS_DATA_5:
|
||||
dbg("%s - data bits = 5", __FUNCTION__);
|
||||
cflag |= CS5;
|
||||
break;
|
||||
case BITS_DATA_6:
|
||||
dbg("%s - data bits = 6", __FUNCTION__);
|
||||
cflag |= CS6;
|
||||
|
@ -310,7 +408,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
cflag |= CS8;
|
||||
bits &= ~BITS_DATA_MASK;
|
||||
bits |= BITS_DATA_8;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
default:
|
||||
dbg("%s - Unknown number of data bits, "
|
||||
|
@ -318,7 +416,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
cflag |= CS8;
|
||||
bits &= ~BITS_DATA_MASK;
|
||||
bits |= BITS_DATA_8;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -341,21 +439,21 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
"disabling parity)", __FUNCTION__);
|
||||
cflag &= ~PARENB;
|
||||
bits &= ~BITS_PARITY_MASK;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
case BITS_PARITY_SPACE:
|
||||
dbg("%s - parity = SPACE (not supported, "
|
||||
"disabling parity)", __FUNCTION__);
|
||||
cflag &= ~PARENB;
|
||||
bits &= ~BITS_PARITY_MASK;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
default:
|
||||
dbg("%s - Unknown parity mode, "
|
||||
"disabling parity", __FUNCTION__);
|
||||
cflag &= ~PARENB;
|
||||
bits &= ~BITS_PARITY_MASK;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -366,9 +464,9 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
break;
|
||||
case BITS_STOP_1_5:
|
||||
dbg("%s - stop bits = 1.5 (not supported, "
|
||||
"using 1 stop bit", __FUNCTION__);
|
||||
"using 1 stop bit)", __FUNCTION__);
|
||||
bits &= ~BITS_STOP_MASK;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
case BITS_STOP_2:
|
||||
dbg("%s - stop bits = 2", __FUNCTION__);
|
||||
|
@ -378,10 +476,19 @@ static void cp2101_get_termios (struct usb_serial_port *port)
|
|||
dbg("%s - Unknown number of stop bits, "
|
||||
"using 1 stop bit", __FUNCTION__);
|
||||
bits &= ~BITS_STOP_MASK;
|
||||
cp2101_set_config(port, CP2101_BITS, bits);
|
||||
cp2101_set_config(port, CP2101_BITS, &bits, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
|
||||
if (modem_ctl[0] & 0x0008) {
|
||||
dbg("%s - flow control = CRTSCTS", __FUNCTION__);
|
||||
cflag |= CRTSCTS;
|
||||
} else {
|
||||
dbg("%s - flow control = NONE", __FUNCTION__);
|
||||
cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
port->tty->termios->c_cflag = cflag;
|
||||
}
|
||||
|
||||
|
@ -389,8 +496,8 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
struct termios *old_termios)
|
||||
{
|
||||
unsigned int cflag, old_cflag=0;
|
||||
int baud=0;
|
||||
int bits;
|
||||
int baud=0, bits;
|
||||
unsigned int modem_ctl[4];
|
||||
|
||||
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||
|
||||
|
@ -400,7 +507,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
}
|
||||
cflag = port->tty->termios->c_cflag;
|
||||
|
||||
/* check that they really want us to change something */
|
||||
/* Check that they really want us to change something */
|
||||
if (old_termios) {
|
||||
if ((cflag == old_termios->c_cflag) &&
|
||||
(RELEVANT_IFLAG(port->tty->termios->c_iflag)
|
||||
|
@ -415,7 +522,8 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
/* If the baud rate is to be updated*/
|
||||
if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
|
||||
switch (cflag & CBAUD) {
|
||||
/* The baud rates which are commented out below
|
||||
/*
|
||||
* The baud rates which are commented out below
|
||||
* appear to be supported by the device
|
||||
* but are non-standard
|
||||
*/
|
||||
|
@ -448,18 +556,22 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
if (baud) {
|
||||
dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
|
||||
baud);
|
||||
if (cp2101_set_config(port, CP2101_BAUDRATE,
|
||||
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
|
||||
(BAUD_RATE_GEN_FREQ / baud)))
|
||||
dev_err(&port->dev, "Baud rate requested not "
|
||||
"supported by device\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*If the number of data bits is to be updated*/
|
||||
/* If the number of data bits is to be updated */
|
||||
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
|
||||
bits = cp2101_get_config(port, CP2101_BITS);
|
||||
cp2101_get_config(port, CP2101_BITS, &bits, 2);
|
||||
bits &= ~BITS_DATA_MASK;
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
bits |= BITS_DATA_5;
|
||||
dbg("%s - data bits = 5", __FUNCTION__);
|
||||
break;
|
||||
case CS6:
|
||||
bits |= BITS_DATA_6;
|
||||
dbg("%s - data bits = 6", __FUNCTION__);
|
||||
|
@ -483,13 +595,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
bits |= BITS_DATA_8;
|
||||
break;
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, bits))
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Number of data bits requested "
|
||||
"not supported by device\n");
|
||||
}
|
||||
|
||||
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
|
||||
bits = cp2101_get_config(port, CP2101_BITS);
|
||||
cp2101_get_config(port, CP2101_BITS, &bits, 2);
|
||||
bits &= ~BITS_PARITY_MASK;
|
||||
if (cflag & PARENB) {
|
||||
if (cflag & PARODD) {
|
||||
|
@ -500,13 +612,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
dbg("%s - parity = EVEN", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, bits))
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Parity mode not supported "
|
||||
"by device\n");
|
||||
}
|
||||
|
||||
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
|
||||
bits = cp2101_get_config(port, CP2101_BITS);
|
||||
cp2101_get_config(port, CP2101_BITS, &bits, 2);
|
||||
bits &= ~BITS_STOP_MASK;
|
||||
if (cflag & CSTOPB) {
|
||||
bits |= BITS_STOP_2;
|
||||
|
@ -515,15 +627,90 @@ static void cp2101_set_termios (struct usb_serial_port *port,
|
|||
bits |= BITS_STOP_1;
|
||||
dbg("%s - stop bits = 1", __FUNCTION__);
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, bits))
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Number of stop bits requested "
|
||||
"not supported by device\n");
|
||||
}
|
||||
|
||||
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
|
||||
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
|
||||
dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
|
||||
__FUNCTION__, modem_ctl[0], modem_ctl[1],
|
||||
modem_ctl[2], modem_ctl[3]);
|
||||
|
||||
if (cflag & CRTSCTS) {
|
||||
modem_ctl[0] &= ~0x7B;
|
||||
modem_ctl[0] |= 0x09;
|
||||
modem_ctl[1] = 0x80;
|
||||
dbg("%s - flow control = CRTSCTS", __FUNCTION__);
|
||||
} else {
|
||||
modem_ctl[0] &= ~0x7B;
|
||||
modem_ctl[0] |= 0x01;
|
||||
modem_ctl[1] |= 0x40;
|
||||
dbg("%s - flow control = NONE", __FUNCTION__);
|
||||
}
|
||||
|
||||
dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
|
||||
__FUNCTION__, modem_ctl[0], modem_ctl[1],
|
||||
modem_ctl[2], modem_ctl[3]);
|
||||
cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
int control = 0;
|
||||
|
||||
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||
|
||||
if (set & TIOCM_RTS) {
|
||||
control |= CONTROL_RTS;
|
||||
control |= CONTROL_WRITE_RTS;
|
||||
}
|
||||
if (set & TIOCM_DTR) {
|
||||
control |= CONTROL_DTR;
|
||||
control |= CONTROL_WRITE_DTR;
|
||||
}
|
||||
if (clear & TIOCM_RTS) {
|
||||
control &= ~CONTROL_RTS;
|
||||
control |= CONTROL_WRITE_RTS;
|
||||
}
|
||||
if (clear & TIOCM_DTR) {
|
||||
control &= ~CONTROL_DTR;
|
||||
control |= CONTROL_WRITE_DTR;
|
||||
}
|
||||
|
||||
dbg("%s - control = 0x%.4x", __FUNCTION__, control);
|
||||
|
||||
return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
|
||||
|
||||
}
|
||||
|
||||
static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
|
||||
{
|
||||
int control, result;
|
||||
|
||||
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||
|
||||
cp2101_get_config(port, CP2101_CONTROL, &control, 1);
|
||||
|
||||
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
|
||||
|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
|
||||
|((control & CONTROL_CTS) ? TIOCM_CTS : 0)
|
||||
|((control & CONTROL_DSR) ? TIOCM_DSR : 0)
|
||||
|((control & CONTROL_RING)? TIOCM_RI : 0)
|
||||
|((control & CONTROL_DCD) ? TIOCM_CD : 0);
|
||||
|
||||
dbg("%s - control = 0x%.2x", __FUNCTION__, control);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
|
||||
{
|
||||
u16 state;
|
||||
int state;
|
||||
|
||||
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||
if (break_state == 0)
|
||||
|
@ -532,12 +719,12 @@ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
|
|||
state = BREAK_ON;
|
||||
dbg("%s - turning break %s", __FUNCTION__,
|
||||
state==BREAK_OFF ? "off" : "on");
|
||||
cp2101_set_config(port, CP2101_BREAK, state);
|
||||
cp2101_set_config(port, CP2101_BREAK, &state, 2);
|
||||
}
|
||||
|
||||
static int cp2101_startup (struct usb_serial *serial)
|
||||
{
|
||||
/*CP2101 buffers behave strangely unless device is reset*/
|
||||
/* CP2101 buffers behave strangely unless device is reset */
|
||||
usb_reset_device(serial->dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -548,7 +735,7 @@ static void cp2101_shutdown (struct usb_serial *serial)
|
|||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
/* stop reads and writes on all ports */
|
||||
/* Stop reads and writes on all ports */
|
||||
for (i=0; i < serial->num_ports; ++i) {
|
||||
cp2101_cleanup(serial->port[i]);
|
||||
}
|
||||
|
@ -560,16 +747,16 @@ static int __init cp2101_init (void)
|
|||
|
||||
retval = usb_serial_register(&cp2101_device);
|
||||
if (retval)
|
||||
return retval; /*Failed to register*/
|
||||
return retval; /* Failed to register */
|
||||
|
||||
retval = usb_register(&cp2101_driver);
|
||||
if (retval) {
|
||||
/*Failed to register*/
|
||||
/* Failed to register */
|
||||
usb_serial_deregister(&cp2101_device);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*Success*/
|
||||
/* Success */
|
||||
info(DRIVER_DESC " " DRIVER_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,729 @@
|
|||
/*
|
||||
Option Card (PCMCIA to) USB to Serial Driver
|
||||
|
||||
Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
|
||||
|
||||
This driver is free software; you can redistribute it and/or modify
|
||||
it under the terms of Version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
|
||||
|
||||
History:
|
||||
|
||||
2005-05-19 v0.1 Initial version, based on incomplete docs
|
||||
and analysis of misbehavior of the standard driver
|
||||
2005-05-20 v0.2 Extended the input buffer to avoid losing
|
||||
random 64-byte chunks of data
|
||||
2005-05-21 v0.3 implemented chars_in_buffer()
|
||||
turned on low_latency
|
||||
simplified the code somewhat
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.3"
|
||||
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
|
||||
#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include "usb-serial.h"
|
||||
|
||||
/* Function prototypes */
|
||||
static int option_open (struct usb_serial_port *port, struct file *filp);
|
||||
static void option_close (struct usb_serial_port *port, struct file *filp);
|
||||
static int option_startup (struct usb_serial *serial);
|
||||
static void option_shutdown (struct usb_serial *serial);
|
||||
static void option_rx_throttle (struct usb_serial_port *port);
|
||||
static void option_rx_unthrottle (struct usb_serial_port *port);
|
||||
static int option_write_room (struct usb_serial_port *port);
|
||||
|
||||
static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
|
||||
|
||||
|
||||
static int option_write (struct usb_serial_port *port,
|
||||
const unsigned char *buf, int count);
|
||||
|
||||
static int option_chars_in_buffer (struct usb_serial_port *port);
|
||||
static int option_ioctl (struct usb_serial_port *port, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static void option_set_termios (struct usb_serial_port *port,
|
||||
struct termios *old);
|
||||
static void option_break_ctl (struct usb_serial_port *port, int break_state);
|
||||
static int option_tiocmget (struct usb_serial_port *port, struct file *file);
|
||||
static int option_tiocmset (struct usb_serial_port *port, struct file *file,
|
||||
unsigned int set, unsigned int clear);
|
||||
static int option_send_setup (struct usb_serial_port *port);
|
||||
|
||||
/* Vendor and product IDs */
|
||||
#define OPTION_VENDOR_ID 0x0AF0
|
||||
|
||||
#define OPTION_PRODUCT_OLD 0x5000
|
||||
#define OPTION_PRODUCT_WLAN 0x6000
|
||||
|
||||
static struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_WLAN) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, option_ids);
|
||||
|
||||
static struct usb_driver option_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "option",
|
||||
.probe = usb_serial_probe,
|
||||
.disconnect = usb_serial_disconnect,
|
||||
.id_table = option_ids,
|
||||
};
|
||||
|
||||
/* The card has three separate interfaces, wich the serial driver
|
||||
* recognizes separately, thus num_port=1.
|
||||
*/
|
||||
static struct usb_serial_device_type option_3port_device = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Option 3-port card",
|
||||
.short_name = "option",
|
||||
.id_table = option_ids,
|
||||
.num_interrupt_in = NUM_DONT_CARE,
|
||||
.num_bulk_in = NUM_DONT_CARE,
|
||||
.num_bulk_out = NUM_DONT_CARE,
|
||||
.num_ports = 1, /* 3 */
|
||||
.open = option_open,
|
||||
.close = option_close,
|
||||
.write = option_write,
|
||||
.write_room = option_write_room,
|
||||
.chars_in_buffer = option_chars_in_buffer,
|
||||
.throttle = option_rx_throttle,
|
||||
.unthrottle = option_rx_unthrottle,
|
||||
.ioctl = option_ioctl,
|
||||
.set_termios = option_set_termios,
|
||||
.break_ctl = option_break_ctl,
|
||||
.tiocmget = option_tiocmget,
|
||||
.tiocmset = option_tiocmset,
|
||||
.attach = option_startup,
|
||||
.shutdown = option_shutdown,
|
||||
.read_int_callback = option_instat_callback,
|
||||
};
|
||||
|
||||
static int debug;
|
||||
|
||||
/* per port private data */
|
||||
|
||||
#define N_IN_URB 4
|
||||
#define N_OUT_URB 1
|
||||
#define IN_BUFLEN 1024
|
||||
#define OUT_BUFLEN 1024
|
||||
|
||||
struct option_port_private {
|
||||
/* Input endpoints and buffer for this port */
|
||||
struct urb *in_urbs[N_IN_URB];
|
||||
char in_buffer[N_IN_URB][IN_BUFLEN];
|
||||
/* Output endpoints and buffer for this port */
|
||||
struct urb *out_urbs[N_OUT_URB];
|
||||
char out_buffer[N_OUT_URB][OUT_BUFLEN];
|
||||
|
||||
/* Settings for the port */
|
||||
int rts_state; /* Handshaking pins (outputs) */
|
||||
int dtr_state;
|
||||
int cts_state; /* Handshaking pins (inputs) */
|
||||
int dsr_state;
|
||||
int dcd_state;
|
||||
int ri_state;
|
||||
// int break_on;
|
||||
|
||||
unsigned long tx_start_time[N_OUT_URB];
|
||||
};
|
||||
|
||||
|
||||
/* Functions used by new usb-serial code. */
|
||||
static int __init
|
||||
option_init (void)
|
||||
{
|
||||
int retval;
|
||||
retval = usb_serial_register(&option_3port_device);
|
||||
if (retval)
|
||||
goto failed_3port_device_register;
|
||||
retval = usb_register(&option_driver);
|
||||
if (retval)
|
||||
goto failed_driver_register;
|
||||
|
||||
info(DRIVER_DESC ": " DRIVER_VERSION);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_driver_register:
|
||||
usb_serial_deregister (&option_3port_device);
|
||||
failed_3port_device_register:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
option_exit (void)
|
||||
{
|
||||
usb_deregister (&option_driver);
|
||||
usb_serial_deregister (&option_3port_device);
|
||||
}
|
||||
|
||||
module_init(option_init);
|
||||
module_exit(option_exit);
|
||||
|
||||
static void
|
||||
option_rx_throttle (struct usb_serial_port *port)
|
||||
{
|
||||
dbg("%s", __FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
option_rx_unthrottle (struct usb_serial_port *port)
|
||||
{
|
||||
dbg("%s", __FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
option_break_ctl (struct usb_serial_port *port, int break_state)
|
||||
{
|
||||
/* Unfortunately, I don't know how to send a break */
|
||||
dbg("%s", __FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
option_set_termios (struct usb_serial_port *port,
|
||||
struct termios *old_termios)
|
||||
{
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
option_send_setup(port);
|
||||
}
|
||||
|
||||
static int
|
||||
option_tiocmget(struct usb_serial_port *port, struct file *file)
|
||||
{
|
||||
unsigned int value;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
|
||||
((portdata->dtr_state) ? TIOCM_DTR : 0) |
|
||||
((portdata->cts_state) ? TIOCM_CTS : 0) |
|
||||
((portdata->dsr_state) ? TIOCM_DSR : 0) |
|
||||
((portdata->dcd_state) ? TIOCM_CAR : 0) |
|
||||
((portdata->ri_state) ? TIOCM_RNG : 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int
|
||||
option_tiocmset (struct usb_serial_port *port, struct file *file,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
struct option_port_private *portdata;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
if (set & TIOCM_RTS)
|
||||
portdata->rts_state = 1;
|
||||
if (set & TIOCM_DTR)
|
||||
portdata->dtr_state = 1;
|
||||
|
||||
if (clear & TIOCM_RTS)
|
||||
portdata->rts_state = 0;
|
||||
if (clear & TIOCM_DTR)
|
||||
portdata->dtr_state = 0;
|
||||
return option_send_setup(port);
|
||||
}
|
||||
|
||||
static int
|
||||
option_ioctl (struct usb_serial_port *port, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
/* Write */
|
||||
static int
|
||||
option_write(struct usb_serial_port *port,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
struct option_port_private *portdata;
|
||||
int i;
|
||||
int left, todo;
|
||||
struct urb *this_urb = NULL; /* spurious */
|
||||
int err;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
dbg("%s: write (%d chars)", __FUNCTION__, count);
|
||||
|
||||
#if 0
|
||||
spin_lock(&port->lock);
|
||||
if (port->write_urb_busy) {
|
||||
spin_unlock(&port->lock);
|
||||
dbg("%s: already writing", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
port->write_urb_busy = 1;
|
||||
spin_unlock(&port->lock);
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
left = count;
|
||||
while (left>0) {
|
||||
todo = left;
|
||||
if (todo > OUT_BUFLEN)
|
||||
todo = OUT_BUFLEN;
|
||||
|
||||
for (;i < N_OUT_URB; i++) {
|
||||
/* Check we have a valid urb/endpoint before we use it... */
|
||||
this_urb = portdata->out_urbs[i];
|
||||
if (this_urb->status != -EINPROGRESS)
|
||||
break;
|
||||
if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
|
||||
continue;
|
||||
if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
|
||||
continue;
|
||||
this_urb->transfer_flags |= URB_ASYNC_UNLINK;
|
||||
usb_unlink_urb(this_urb);
|
||||
}
|
||||
|
||||
if (i == N_OUT_URB) {
|
||||
/* no bulk out free! */
|
||||
dbg("%s: no output urb -- left %d", __FUNCTION__,count-left);
|
||||
#if 0
|
||||
port->write_urb_busy = 0;
|
||||
#endif
|
||||
return count-left;
|
||||
}
|
||||
|
||||
dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
|
||||
|
||||
memcpy (this_urb->transfer_buffer, buf, todo);
|
||||
|
||||
/* send the data out the bulk port */
|
||||
this_urb->transfer_buffer_length = todo;
|
||||
|
||||
this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
|
||||
this_urb->dev = port->serial->dev;
|
||||
err = usb_submit_urb(this_urb, GFP_ATOMIC);
|
||||
if (err) {
|
||||
dbg("usb_submit_urb %p (write bulk) failed (%d,, has %d)", this_urb, err, this_urb->status);
|
||||
continue;
|
||||
}
|
||||
portdata->tx_start_time[i] = jiffies;
|
||||
buf += todo;
|
||||
left -= todo;
|
||||
}
|
||||
|
||||
count -= left;
|
||||
#if 0
|
||||
port->write_urb_busy = 0;
|
||||
#endif
|
||||
dbg("%s: wrote (did %d)", __FUNCTION__, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
option_indat_callback (struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
int i, err;
|
||||
int endpoint;
|
||||
struct usb_serial_port *port;
|
||||
struct tty_struct *tty;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
|
||||
dbg("%s: %p", __FUNCTION__, urb);
|
||||
|
||||
endpoint = usb_pipeendpoint(urb->pipe);
|
||||
port = (struct usb_serial_port *) urb->context;
|
||||
|
||||
if (urb->status) {
|
||||
dbg("%s: nonzero status: %d on endpoint %02x.",
|
||||
__FUNCTION__, urb->status, endpoint);
|
||||
} else {
|
||||
tty = port->tty;
|
||||
if (urb->actual_length) {
|
||||
for (i = 0; i < urb->actual_length ; ++i) {
|
||||
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(tty, data[i], 0);
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
} else {
|
||||
dbg("%s: empty read urb received", __FUNCTION__);
|
||||
}
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
if (port->open_count && urb->status != -ESHUTDOWN) {
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: resubmit read urb failed. (%d)", __FUNCTION__, err);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
option_outdat_callback (struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct usb_serial_port *port;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
port = (struct usb_serial_port *) urb->context;
|
||||
|
||||
if (port->open_count)
|
||||
schedule_work(&port->work);
|
||||
}
|
||||
|
||||
static void
|
||||
option_instat_callback (struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
int err;
|
||||
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
|
||||
struct option_port_private *portdata = usb_get_serial_port_data(port);
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
|
||||
|
||||
if (urb->status == 0) {
|
||||
struct usb_ctrlrequest *req_pkt =
|
||||
(struct usb_ctrlrequest *)urb->transfer_buffer;
|
||||
|
||||
if (!req_pkt) {
|
||||
dbg("%s: NULL req_pkt\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
|
||||
int old_dcd_state;
|
||||
unsigned char signals = *((unsigned char *)
|
||||
urb->transfer_buffer + sizeof(struct usb_ctrlrequest));
|
||||
|
||||
dbg("%s: signal x%x", __FUNCTION__, signals);
|
||||
|
||||
old_dcd_state = portdata->dcd_state;
|
||||
portdata->cts_state = 1;
|
||||
portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
|
||||
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
|
||||
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
|
||||
|
||||
if (port->tty && !C_CLOCAL(port->tty)
|
||||
&& old_dcd_state && !portdata->dcd_state) {
|
||||
tty_hangup(port->tty);
|
||||
}
|
||||
} else
|
||||
dbg("%s: type %x req %x", __FUNCTION__, req_pkt->bRequestType,req_pkt->bRequest);
|
||||
} else
|
||||
dbg("%s: error %d", __FUNCTION__, urb->status);
|
||||
|
||||
/* Resubmit urb so we continue receiving IRQ data */
|
||||
if (urb->status != -ESHUTDOWN) {
|
||||
urb->dev = serial->dev;
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err)
|
||||
dbg("%s: resubmit intr urb failed. (%d)", __FUNCTION__, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_write_room (struct usb_serial_port *port)
|
||||
{
|
||||
struct option_port_private *portdata;
|
||||
int i;
|
||||
int data_len = 0;
|
||||
struct urb *this_urb;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
for (i=0; i < N_OUT_URB; i++)
|
||||
this_urb = portdata->out_urbs[i];
|
||||
if (this_urb && this_urb->status != -EINPROGRESS)
|
||||
data_len += OUT_BUFLEN;
|
||||
|
||||
dbg("%s: %d", __FUNCTION__, data_len);
|
||||
return data_len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_chars_in_buffer (struct usb_serial_port *port)
|
||||
{
|
||||
struct option_port_private *portdata;
|
||||
int i;
|
||||
int data_len = 0;
|
||||
struct urb *this_urb;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
for (i=0; i < N_OUT_URB; i++)
|
||||
this_urb = portdata->out_urbs[i];
|
||||
if (this_urb && this_urb->status == -EINPROGRESS)
|
||||
data_len += this_urb->transfer_buffer_length;
|
||||
|
||||
dbg("%s: %d", __FUNCTION__, data_len);
|
||||
return data_len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_open (struct usb_serial_port *port, struct file *filp)
|
||||
{
|
||||
struct option_port_private *portdata;
|
||||
struct usb_serial *serial = port->serial;
|
||||
int i, err;
|
||||
struct urb *urb;
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
/* Set some sane defaults */
|
||||
portdata->rts_state = 1;
|
||||
portdata->dtr_state = 1;
|
||||
|
||||
/* Reset low level data toggle and start reading from endpoints */
|
||||
for (i = 0; i < N_IN_URB; i++) {
|
||||
urb = portdata->in_urbs[i];
|
||||
if (! urb)
|
||||
continue;
|
||||
if (urb->dev != serial->dev) {
|
||||
dbg("%s: dev %p != %p", __FUNCTION__, urb->dev, serial->dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* make sure endpoint data toggle is synchronized with the device */
|
||||
|
||||
usb_clear_halt(urb->dev, urb->pipe);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err) {
|
||||
dbg("%s: submit urb %d failed (%d) %d", __FUNCTION__, i, err,
|
||||
urb->transfer_buffer_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset low level data toggle on out endpoints */
|
||||
for (i = 0; i < N_OUT_URB; i++) {
|
||||
urb = portdata->out_urbs[i];
|
||||
if (! urb)
|
||||
continue;
|
||||
urb->dev = serial->dev;
|
||||
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
|
||||
}
|
||||
|
||||
port->tty->low_latency = 1;
|
||||
|
||||
option_send_setup(port);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
stop_urb(struct urb *urb)
|
||||
{
|
||||
if (urb && urb->status == -EINPROGRESS) {
|
||||
urb->transfer_flags &= ~URB_ASYNC_UNLINK;
|
||||
usb_kill_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
option_close(struct usb_serial_port *port, struct file *filp)
|
||||
{
|
||||
int i;
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
portdata->rts_state = 0;
|
||||
portdata->dtr_state = 0;
|
||||
|
||||
if (serial->dev) {
|
||||
option_send_setup(port);
|
||||
|
||||
/* Stop reading/writing urbs */
|
||||
for (i = 0; i < N_IN_URB; i++)
|
||||
stop_urb(portdata->in_urbs[i]);
|
||||
for (i = 0; i < N_OUT_URB; i++)
|
||||
stop_urb(portdata->out_urbs[i]);
|
||||
}
|
||||
port->tty = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions used by option_setup_urbs */
|
||||
static struct urb *
|
||||
option_setup_urb (struct usb_serial *serial, int endpoint,
|
||||
int dir, void *ctx, char *buf, int len,
|
||||
void (*callback)(struct urb *, struct pt_regs *regs))
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
if (endpoint == -1)
|
||||
return NULL; /* endpoint not needed */
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
|
||||
if (urb == NULL) {
|
||||
dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fill URB using supplied data. */
|
||||
usb_fill_bulk_urb(urb, serial->dev,
|
||||
usb_sndbulkpipe(serial->dev, endpoint) | dir,
|
||||
buf, len, callback, ctx);
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
/* Setup urbs */
|
||||
static void
|
||||
option_setup_urbs(struct usb_serial *serial)
|
||||
{
|
||||
int j;
|
||||
struct usb_serial_port *port;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
port = serial->port[0];
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
/* Do indat endpoints first */
|
||||
for (j = 0; j <= N_IN_URB; ++j) {
|
||||
portdata->in_urbs[j] = option_setup_urb (serial,
|
||||
port->bulk_in_endpointAddress, USB_DIR_IN, port,
|
||||
portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
|
||||
}
|
||||
|
||||
/* outdat endpoints */
|
||||
for (j = 0; j <= N_OUT_URB; ++j) {
|
||||
portdata->out_urbs[j] = option_setup_urb (serial,
|
||||
port->bulk_out_endpointAddress, USB_DIR_OUT, port,
|
||||
portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_send_setup(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
if (port->tty) {
|
||||
int val = 0;
|
||||
if (portdata->dtr_state)
|
||||
val |= 0x01;
|
||||
if (portdata->rts_state)
|
||||
val |= 0x02;
|
||||
|
||||
return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
|
||||
0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_startup (struct usb_serial *serial)
|
||||
{
|
||||
int i, err;
|
||||
struct usb_serial_port *port;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
/* Now setup per port private data */
|
||||
for (i = 0; i < serial->num_ports; i++) {
|
||||
port = serial->port[i];
|
||||
portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
|
||||
if (!portdata) {
|
||||
dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i);
|
||||
return (1);
|
||||
}
|
||||
memset(portdata, 0, sizeof(struct option_port_private));
|
||||
|
||||
usb_set_serial_port_data(port, portdata);
|
||||
|
||||
if (! port->interrupt_in_urb)
|
||||
continue;
|
||||
err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (err)
|
||||
dbg("%s: submit irq_in urb failed %d", __FUNCTION__, err);
|
||||
}
|
||||
|
||||
option_setup_urbs(serial);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
option_shutdown (struct usb_serial *serial)
|
||||
{
|
||||
int i, j;
|
||||
struct usb_serial_port *port;
|
||||
struct option_port_private *portdata;
|
||||
|
||||
dbg("%s", __FUNCTION__);
|
||||
|
||||
/* Stop reading/writing urbs */
|
||||
for (i = 0; i < serial->num_ports; ++i) {
|
||||
port = serial->port[i];
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
for (j = 0; j < N_IN_URB; j++)
|
||||
stop_urb(portdata->in_urbs[j]);
|
||||
for (j = 0; j < N_OUT_URB; j++)
|
||||
stop_urb(portdata->out_urbs[j]);
|
||||
}
|
||||
|
||||
/* Now free them */
|
||||
for (i = 0; i < serial->num_ports; ++i) {
|
||||
port = serial->port[i];
|
||||
portdata = usb_get_serial_port_data(port);
|
||||
|
||||
for (j = 0; j < N_IN_URB; j++) {
|
||||
if (portdata->in_urbs[j]) {
|
||||
usb_free_urb(portdata->in_urbs[j]);
|
||||
portdata->in_urbs[j] = NULL;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < N_OUT_URB; j++) {
|
||||
if (portdata->out_urbs[j]) {
|
||||
usb_free_urb(portdata->out_urbs[j]);
|
||||
portdata->out_urbs[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now free per port private data */
|
||||
for (i = 0; i < serial->num_ports; i++) {
|
||||
port = serial->port[i];
|
||||
kfree(usb_get_serial_port_data(port));
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(debug, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Debug messages");
|
||||
|
|
@ -862,6 +862,15 @@ UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100,
|
|||
US_SC_DEVICE, US_PR_BULK, NULL,
|
||||
US_FL_NEED_OVERRIDE ),
|
||||
|
||||
/* Reported by Filippo Bardelli <filibard@libero.it>
|
||||
* The device reports a subclass of RBC, which is wrong.
|
||||
*/
|
||||
UNUSUAL_DEV( 0x090a, 0x1050, 0x0100, 0x0100,
|
||||
"Trumpion Microelectronics, Inc.",
|
||||
"33520 USB Digital Voice Recorder",
|
||||
US_SC_UFI, US_PR_DEVICE, NULL,
|
||||
0),
|
||||
|
||||
/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
|
||||
UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
|
||||
"Trumpion",
|
||||
|
|
|
@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm,
|
|||
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
|
||||
|
||||
down_write(¤t->mm->mmap_sem);
|
||||
textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0);
|
||||
textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
if (!textpos || textpos >= (unsigned long) -4096) {
|
||||
if (!textpos)
|
||||
|
@ -532,7 +532,7 @@ static int load_flat_file(struct linux_binprm * bprm,
|
|||
down_write(¤t->mm->mmap_sem);
|
||||
realdatastart = do_mmap(0, 0, data_len + extra +
|
||||
MAX_SHARED_LIBS * sizeof(unsigned long),
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0);
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
|
||||
if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
|
||||
|
@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm * bprm,
|
|||
down_write(¤t->mm->mmap_sem);
|
||||
textpos = do_mmap(0, 0, text_len + data_len + extra +
|
||||
MAX_SHARED_LIBS * sizeof(unsigned long),
|
||||
PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0);
|
||||
PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
if (!textpos || textpos >= (unsigned long) -4096) {
|
||||
if (!textpos)
|
||||
|
|
|
@ -79,8 +79,11 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
|
|||
if (--bvec >= bio->bi_io_vec)
|
||||
prefetchw(&bvec->bv_page->flags);
|
||||
|
||||
if (!uptodate)
|
||||
if (!uptodate){
|
||||
SetPageError(page);
|
||||
if (page->mapping)
|
||||
set_bit(AS_EIO, &page->mapping->flags);
|
||||
}
|
||||
end_page_writeback(page);
|
||||
} while (bvec >= bio->bi_io_vec);
|
||||
bio_put(bio);
|
||||
|
|
159
fs/namei.c
159
fs/namei.c
|
@ -493,12 +493,21 @@ fail:
|
|||
return PTR_ERR(link);
|
||||
}
|
||||
|
||||
static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
struct path {
|
||||
struct vfsmount *mnt;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
static inline int __do_follow_link(struct path *path, struct nameidata *nd)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry = path->dentry;
|
||||
|
||||
touch_atime(nd->mnt, dentry);
|
||||
touch_atime(path->mnt, dentry);
|
||||
nd_set_link(nd, NULL);
|
||||
|
||||
if (path->mnt == nd->mnt)
|
||||
mntget(path->mnt);
|
||||
error = dentry->d_inode->i_op->follow_link(dentry, nd);
|
||||
if (!error) {
|
||||
char *s = nd_get_link(nd);
|
||||
|
@ -507,6 +516,8 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
if (dentry->d_inode->i_op->put_link)
|
||||
dentry->d_inode->i_op->put_link(dentry, nd);
|
||||
}
|
||||
dput(dentry);
|
||||
mntput(path->mnt);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -518,7 +529,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
* Without that kind of total limit, nasty chains of consecutive
|
||||
* symlinks can cause almost arbitrarily long lookups.
|
||||
*/
|
||||
static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static inline int do_follow_link(struct path *path, struct nameidata *nd)
|
||||
{
|
||||
int err = -ELOOP;
|
||||
if (current->link_count >= MAX_NESTED_LINKS)
|
||||
|
@ -527,17 +538,20 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
goto loop;
|
||||
BUG_ON(nd->depth >= MAX_NESTED_LINKS);
|
||||
cond_resched();
|
||||
err = security_inode_follow_link(dentry, nd);
|
||||
err = security_inode_follow_link(path->dentry, nd);
|
||||
if (err)
|
||||
goto loop;
|
||||
current->link_count++;
|
||||
current->total_link_count++;
|
||||
nd->depth++;
|
||||
err = __do_follow_link(dentry, nd);
|
||||
err = __do_follow_link(path, nd);
|
||||
current->link_count--;
|
||||
nd->depth--;
|
||||
return err;
|
||||
loop:
|
||||
dput(path->dentry);
|
||||
if (path->mnt != nd->mnt)
|
||||
mntput(path->mnt);
|
||||
path_release(nd);
|
||||
return err;
|
||||
}
|
||||
|
@ -565,87 +579,91 @@ int follow_up(struct vfsmount **mnt, struct dentry **dentry)
|
|||
/* no need for dcache_lock, as serialization is taken care in
|
||||
* namespace.c
|
||||
*/
|
||||
static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
|
||||
static int __follow_mount(struct path *path)
|
||||
{
|
||||
int res = 0;
|
||||
while (d_mountpoint(*dentry)) {
|
||||
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
|
||||
while (d_mountpoint(path->dentry)) {
|
||||
struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
|
||||
if (!mounted)
|
||||
break;
|
||||
mntput(*mnt);
|
||||
*mnt = mounted;
|
||||
dput(*dentry);
|
||||
*dentry = dget(mounted->mnt_root);
|
||||
dput(path->dentry);
|
||||
if (res)
|
||||
mntput(path->mnt);
|
||||
path->mnt = mounted;
|
||||
path->dentry = dget(mounted->mnt_root);
|
||||
res = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void follow_mount(struct vfsmount **mnt, struct dentry **dentry)
|
||||
{
|
||||
while (d_mountpoint(*dentry)) {
|
||||
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
|
||||
if (!mounted)
|
||||
break;
|
||||
dput(*dentry);
|
||||
mntput(*mnt);
|
||||
*mnt = mounted;
|
||||
*dentry = dget(mounted->mnt_root);
|
||||
}
|
||||
}
|
||||
|
||||
/* no need for dcache_lock, as serialization is taken care in
|
||||
* namespace.c
|
||||
*/
|
||||
static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
|
||||
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
|
||||
{
|
||||
struct vfsmount *mounted;
|
||||
|
||||
mounted = lookup_mnt(*mnt, *dentry);
|
||||
if (mounted) {
|
||||
dput(*dentry);
|
||||
mntput(*mnt);
|
||||
*mnt = mounted;
|
||||
dput(*dentry);
|
||||
*dentry = dget(mounted->mnt_root);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
|
||||
{
|
||||
return __follow_down(mnt,dentry);
|
||||
}
|
||||
|
||||
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
|
||||
static inline void follow_dotdot(struct nameidata *nd)
|
||||
{
|
||||
while(1) {
|
||||
struct vfsmount *parent;
|
||||
struct dentry *old = *dentry;
|
||||
struct dentry *old = nd->dentry;
|
||||
|
||||
read_lock(¤t->fs->lock);
|
||||
if (*dentry == current->fs->root &&
|
||||
*mnt == current->fs->rootmnt) {
|
||||
if (nd->dentry == current->fs->root &&
|
||||
nd->mnt == current->fs->rootmnt) {
|
||||
read_unlock(¤t->fs->lock);
|
||||
break;
|
||||
}
|
||||
read_unlock(¤t->fs->lock);
|
||||
spin_lock(&dcache_lock);
|
||||
if (*dentry != (*mnt)->mnt_root) {
|
||||
*dentry = dget((*dentry)->d_parent);
|
||||
if (nd->dentry != nd->mnt->mnt_root) {
|
||||
nd->dentry = dget(nd->dentry->d_parent);
|
||||
spin_unlock(&dcache_lock);
|
||||
dput(old);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
parent = (*mnt)->mnt_parent;
|
||||
if (parent == *mnt) {
|
||||
parent = nd->mnt->mnt_parent;
|
||||
if (parent == nd->mnt) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
break;
|
||||
}
|
||||
mntget(parent);
|
||||
*dentry = dget((*mnt)->mnt_mountpoint);
|
||||
nd->dentry = dget(nd->mnt->mnt_mountpoint);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
dput(old);
|
||||
mntput(*mnt);
|
||||
*mnt = parent;
|
||||
mntput(nd->mnt);
|
||||
nd->mnt = parent;
|
||||
}
|
||||
follow_mount(mnt, dentry);
|
||||
follow_mount(&nd->mnt, &nd->dentry);
|
||||
}
|
||||
|
||||
struct path {
|
||||
struct vfsmount *mnt;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
/*
|
||||
* It's more convoluted than I'd like it to be, but... it's still fairly
|
||||
* small and for now I'd prefer to have fast path as straight as possible.
|
||||
|
@ -664,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
|
|||
done:
|
||||
path->mnt = mnt;
|
||||
path->dentry = dentry;
|
||||
__follow_mount(path);
|
||||
return 0;
|
||||
|
||||
need_lookup:
|
||||
|
@ -751,7 +770,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
|
|||
case 2:
|
||||
if (this.name[1] != '.')
|
||||
break;
|
||||
follow_dotdot(&nd->mnt, &nd->dentry);
|
||||
follow_dotdot(nd);
|
||||
inode = nd->dentry->d_inode;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
|
@ -771,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
|
|||
err = do_lookup(nd, &this, &next);
|
||||
if (err)
|
||||
break;
|
||||
/* Check mountpoints.. */
|
||||
follow_mount(&next.mnt, &next.dentry);
|
||||
|
||||
err = -ENOENT;
|
||||
inode = next.dentry->d_inode;
|
||||
|
@ -783,10 +800,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
|
|||
goto out_dput;
|
||||
|
||||
if (inode->i_op->follow_link) {
|
||||
mntget(next.mnt);
|
||||
err = do_follow_link(next.dentry, nd);
|
||||
dput(next.dentry);
|
||||
mntput(next.mnt);
|
||||
err = do_follow_link(&next, nd);
|
||||
if (err)
|
||||
goto return_err;
|
||||
err = -ENOENT;
|
||||
|
@ -798,6 +812,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
|
|||
break;
|
||||
} else {
|
||||
dput(nd->dentry);
|
||||
if (nd->mnt != next.mnt)
|
||||
mntput(nd->mnt);
|
||||
nd->mnt = next.mnt;
|
||||
nd->dentry = next.dentry;
|
||||
}
|
||||
|
@ -819,7 +835,7 @@ last_component:
|
|||
case 2:
|
||||
if (this.name[1] != '.')
|
||||
break;
|
||||
follow_dotdot(&nd->mnt, &nd->dentry);
|
||||
follow_dotdot(nd);
|
||||
inode = nd->dentry->d_inode;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
|
@ -833,19 +849,17 @@ last_component:
|
|||
err = do_lookup(nd, &this, &next);
|
||||
if (err)
|
||||
break;
|
||||
follow_mount(&next.mnt, &next.dentry);
|
||||
inode = next.dentry->d_inode;
|
||||
if ((lookup_flags & LOOKUP_FOLLOW)
|
||||
&& inode && inode->i_op && inode->i_op->follow_link) {
|
||||
mntget(next.mnt);
|
||||
err = do_follow_link(next.dentry, nd);
|
||||
dput(next.dentry);
|
||||
mntput(next.mnt);
|
||||
err = do_follow_link(&next, nd);
|
||||
if (err)
|
||||
goto return_err;
|
||||
inode = nd->dentry->d_inode;
|
||||
} else {
|
||||
dput(nd->dentry);
|
||||
if (nd->mnt != next.mnt)
|
||||
mntput(nd->mnt);
|
||||
nd->mnt = next.mnt;
|
||||
nd->dentry = next.dentry;
|
||||
}
|
||||
|
@ -885,6 +899,8 @@ return_base:
|
|||
return 0;
|
||||
out_dput:
|
||||
dput(next.dentry);
|
||||
if (nd->mnt != next.mnt)
|
||||
mntput(next.mnt);
|
||||
break;
|
||||
}
|
||||
path_release(nd);
|
||||
|
@ -1398,7 +1414,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
|
|||
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
|
||||
{
|
||||
int acc_mode, error = 0;
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
struct dentry *dir;
|
||||
int count = 0;
|
||||
|
||||
|
@ -1442,23 +1458,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
|
|||
dir = nd->dentry;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
down(&dir->d_inode->i_sem);
|
||||
dentry = __lookup_hash(&nd->last, nd->dentry, nd);
|
||||
path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
|
||||
path.mnt = nd->mnt;
|
||||
|
||||
do_last:
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(path.dentry);
|
||||
if (IS_ERR(path.dentry)) {
|
||||
up(&dir->d_inode->i_sem);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Negative dentry, just create the file */
|
||||
if (!dentry->d_inode) {
|
||||
if (!path.dentry->d_inode) {
|
||||
if (!IS_POSIXACL(dir->d_inode))
|
||||
mode &= ~current->fs->umask;
|
||||
error = vfs_create(dir->d_inode, dentry, mode, nd);
|
||||
error = vfs_create(dir->d_inode, path.dentry, mode, nd);
|
||||
up(&dir->d_inode->i_sem);
|
||||
dput(nd->dentry);
|
||||
nd->dentry = dentry;
|
||||
nd->dentry = path.dentry;
|
||||
if (error)
|
||||
goto exit;
|
||||
/* Don't check for write permission, don't truncate */
|
||||
|
@ -1476,22 +1493,24 @@ do_last:
|
|||
if (flag & O_EXCL)
|
||||
goto exit_dput;
|
||||
|
||||
if (d_mountpoint(dentry)) {
|
||||
if (__follow_mount(&path)) {
|
||||
error = -ELOOP;
|
||||
if (flag & O_NOFOLLOW)
|
||||
goto exit_dput;
|
||||
while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
|
||||
}
|
||||
error = -ENOENT;
|
||||
if (!dentry->d_inode)
|
||||
if (!path.dentry->d_inode)
|
||||
goto exit_dput;
|
||||
if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
|
||||
if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
|
||||
goto do_link;
|
||||
|
||||
dput(nd->dentry);
|
||||
nd->dentry = dentry;
|
||||
nd->dentry = path.dentry;
|
||||
if (nd->mnt != path.mnt)
|
||||
mntput(nd->mnt);
|
||||
nd->mnt = path.mnt;
|
||||
error = -EISDIR;
|
||||
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
|
||||
if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
|
||||
goto exit;
|
||||
ok:
|
||||
error = may_open(nd, acc_mode, flag);
|
||||
|
@ -1500,7 +1519,9 @@ ok:
|
|||
return 0;
|
||||
|
||||
exit_dput:
|
||||
dput(dentry);
|
||||
dput(path.dentry);
|
||||
if (nd->mnt != path.mnt)
|
||||
mntput(path.mnt);
|
||||
exit:
|
||||
path_release(nd);
|
||||
return error;
|
||||
|
@ -1520,18 +1541,15 @@ do_link:
|
|||
* are done. Procfs-like symlinks just set LAST_BIND.
|
||||
*/
|
||||
nd->flags |= LOOKUP_PARENT;
|
||||
error = security_inode_follow_link(dentry, nd);
|
||||
error = security_inode_follow_link(path.dentry, nd);
|
||||
if (error)
|
||||
goto exit_dput;
|
||||
error = __do_follow_link(dentry, nd);
|
||||
dput(dentry);
|
||||
error = __do_follow_link(&path, nd);
|
||||
if (error)
|
||||
return error;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
if (nd->last_type == LAST_BIND) {
|
||||
dentry = nd->dentry;
|
||||
if (nd->last_type == LAST_BIND)
|
||||
goto ok;
|
||||
}
|
||||
error = -EISDIR;
|
||||
if (nd->last_type != LAST_NORM)
|
||||
goto exit;
|
||||
|
@ -1546,7 +1564,8 @@ do_link:
|
|||
}
|
||||
dir = nd->dentry;
|
||||
down(&dir->d_inode->i_sem);
|
||||
dentry = __lookup_hash(&nd->last, nd->dentry, nd);
|
||||
path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
|
||||
path.mnt = nd->mnt;
|
||||
putname(nd->last.name);
|
||||
goto do_last;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _ASM_KMAP_TYPES_H
|
||||
#define _ASM_KMAP_TYPES_H
|
||||
#ifndef _ASM_H8300_KMAP_TYPES_H
|
||||
#define _ASM_H8300_KMAP_TYPES_H
|
||||
|
||||
enum km_type {
|
||||
KM_BOUNCE_READ,
|
||||
|
@ -13,6 +13,8 @@ enum km_type {
|
|||
KM_PTE1,
|
||||
KM_IRQ0,
|
||||
KM_IRQ1,
|
||||
KM_SOFTIRQ0,
|
||||
KM_SOFTIRQ1,
|
||||
KM_TYPE_NR
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define PROT_READ 0x1 /* page can be read */
|
||||
#define PROT_WRITE 0x2 /* page can be written */
|
||||
#define PROT_EXEC 0x4 /* page can be executed */
|
||||
#define PROT_SEM 0x8 /* page may be used for atomic ops */
|
||||
#define PROT_NONE 0x0 /* page can not be accessed */
|
||||
#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
|
||||
#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
|
||||
|
@ -19,6 +20,8 @@
|
|||
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
|
||||
#define MAP_LOCKED 0x2000 /* pages are locked */
|
||||
#define MAP_NORESERVE 0x4000 /* don't check for reservations */
|
||||
#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
|
||||
#define MAP_NONBLOCK 0x10000 /* do not block on IO */
|
||||
|
||||
#define MS_ASYNC 1 /* sync memory asynchronously */
|
||||
#define MS_INVALIDATE 2 /* invalidate the caches */
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#define _S390_USER_H
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <asm/ptrace.h>
|
||||
/* Core file format: The core file is written in such a way that gdb
|
||||
can understand it and provide useful information to the user (under
|
||||
linux we use the 'trad-core' bfd). There are quite a number of
|
||||
|
|
|
@ -23,7 +23,7 @@ struct shaper
|
|||
__u32 shapeclock;
|
||||
unsigned long recovery; /* Time we can next clock a packet out on
|
||||
an empty queue */
|
||||
unsigned long locked;
|
||||
struct semaphore sem;
|
||||
struct net_device_stats stats;
|
||||
struct net_device *dev;
|
||||
int (*hard_start_xmit) (struct sk_buff *skb,
|
||||
|
@ -38,7 +38,6 @@ struct shaper
|
|||
int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh);
|
||||
void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr);
|
||||
struct net_device_stats* (*get_stats)(struct net_device *dev);
|
||||
wait_queue_head_t wait_queue;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
|
|
|
@ -467,12 +467,34 @@ static inline u8 ata_chk_status(struct ata_port *ap)
|
|||
return ap->ops->check_status(ap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_pause - Flush writes and pause 400 nanoseconds.
|
||||
* @ap: Port to wait for.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
|
||||
static inline void ata_pause(struct ata_port *ap)
|
||||
{
|
||||
ata_altstatus(ap);
|
||||
ndelay(400);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_busy_wait - Wait for a port status register
|
||||
* @ap: Port to wait for.
|
||||
*
|
||||
* Waits up to max*10 microseconds for the selected bits in the port's
|
||||
* status register to be cleared.
|
||||
* Returns final value of status register.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
|
||||
static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
|
||||
unsigned int max)
|
||||
{
|
||||
|
@ -487,6 +509,18 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
|
|||
return status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_wait_idle - Wait for a port to be idle.
|
||||
* @ap: Port to wait for.
|
||||
*
|
||||
* Waits up to 10ms for port's BUSY and DRQ signals to clear.
|
||||
* Returns final value of status register.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
|
||||
static inline u8 ata_wait_idle(struct ata_port *ap)
|
||||
{
|
||||
u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
|
||||
|
@ -525,6 +559,18 @@ static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, uns
|
|||
tf->device = ATA_DEVICE_OBS | ATA_DEV1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_irq_on - Enable interrupts on a port.
|
||||
* @ap: Port on which interrupts are enabled.
|
||||
*
|
||||
* Enable interrupts on a legacy IDE device using MMIO or PIO,
|
||||
* wait for idle, clear any pending interrupts.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
|
||||
static inline u8 ata_irq_on(struct ata_port *ap)
|
||||
{
|
||||
struct ata_ioports *ioaddr = &ap->ioaddr;
|
||||
|
@ -544,6 +590,18 @@ static inline u8 ata_irq_on(struct ata_port *ap)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_irq_ack - Acknowledge a device interrupt.
|
||||
* @ap: Port on which interrupts are enabled.
|
||||
*
|
||||
* Wait up to 10 ms for legacy IDE device to become idle (BUSY
|
||||
* or BUSY+DRQ clear). Obtain dma status and port status from
|
||||
* device. Clear the interrupt. Return port status.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
|
||||
{
|
||||
unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
|
||||
|
|
|
@ -204,7 +204,7 @@ struct hh_cache
|
|||
/* cached hardware header; allow for machine alignment needs. */
|
||||
#define HH_DATA_MOD 16
|
||||
#define HH_DATA_OFF(__len) \
|
||||
(HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
|
||||
(HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1))
|
||||
#define HH_DATA_ALIGN(__len) \
|
||||
(((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
|
||||
unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
|
||||
|
|
|
@ -796,6 +796,10 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
|
|||
* of the iso_frame_desc array, and the number of errors is reported in
|
||||
* error_count. Completion callbacks for ISO transfers will normally
|
||||
* (re)submit URBs to ensure a constant transfer rate.
|
||||
*
|
||||
* Note that even fields marked "public" should not be touched by the driver
|
||||
* when the urb is owned by the hcd, that is, since the call to
|
||||
* usb_submit_urb() till the entry into the completion routine.
|
||||
*/
|
||||
struct urb
|
||||
{
|
||||
|
@ -803,12 +807,12 @@ struct urb
|
|||
struct kref kref; /* reference count of the URB */
|
||||
spinlock_t lock; /* lock for the URB */
|
||||
void *hcpriv; /* private data for host controller */
|
||||
struct list_head urb_list; /* list pointer to all active urbs */
|
||||
int bandwidth; /* bandwidth for INT/ISO request */
|
||||
atomic_t use_count; /* concurrent submissions counter */
|
||||
u8 reject; /* submissions will fail */
|
||||
|
||||
/* public, documented fields in the urb that can be used by drivers */
|
||||
struct list_head urb_list; /* list head for use by the urb owner */
|
||||
struct usb_device *dev; /* (in) pointer to associated device */
|
||||
unsigned int pipe; /* (in) pipe information */
|
||||
int status; /* (return) non-ISO status */
|
||||
|
|
|
@ -1968,6 +1968,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
do {
|
||||
unsigned long index;
|
||||
unsigned long offset;
|
||||
unsigned long maxlen;
|
||||
size_t copied;
|
||||
|
||||
offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
|
||||
|
@ -1982,7 +1983,10 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
* same page as we're writing to, without it being marked
|
||||
* up-to-date.
|
||||
*/
|
||||
fault_in_pages_readable(buf, bytes);
|
||||
maxlen = cur_iov->iov_len - iov_base;
|
||||
if (maxlen > bytes)
|
||||
maxlen = bytes;
|
||||
fault_in_pages_readable(buf, maxlen);
|
||||
|
||||
page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
|
||||
if (!page) {
|
||||
|
@ -2024,6 +2028,8 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
filemap_set_next_iovec(&cur_iov,
|
||||
&iov_base, status);
|
||||
buf = cur_iov->iov_base + iov_base;
|
||||
} else {
|
||||
iov_base += status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o
|
|||
|
||||
ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
|
||||
ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
|
||||
ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o \
|
||||
ip_vs_est.o ip_vs_proto.o \
|
||||
$(ip_vs_proto-objs-y)
|
||||
|
||||
|
||||
|
|
|
@ -216,9 +216,6 @@ int ip_vs_protocol_init(void)
|
|||
#ifdef CONFIG_IP_VS_PROTO_UDP
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_udp);
|
||||
#endif
|
||||
#ifdef CONFIG_IP_VS_PROTO_ICMP
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_icmp);
|
||||
#endif
|
||||
#ifdef CONFIG_IP_VS_PROTO_AH
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_ah);
|
||||
#endif
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* ip_vs_proto_icmp.c: ICMP load balancing support for IP Virtual Server
|
||||
*
|
||||
* Authors: Julian Anastasov <ja@ssi.bg>, March 2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation;
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
|
||||
#include <net/ip_vs.h>
|
||||
|
||||
|
||||
static int icmp_timeouts[1] = { 1*60*HZ };
|
||||
|
||||
static char * icmp_state_name_table[1] = { "ICMP" };
|
||||
|
||||
static struct ip_vs_conn *
|
||||
icmp_conn_in_get(const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp,
|
||||
const struct iphdr *iph,
|
||||
unsigned int proto_off,
|
||||
int inverse)
|
||||
{
|
||||
#if 0
|
||||
struct ip_vs_conn *cp;
|
||||
|
||||
if (likely(!inverse)) {
|
||||
cp = ip_vs_conn_in_get(iph->protocol,
|
||||
iph->saddr, 0,
|
||||
iph->daddr, 0);
|
||||
} else {
|
||||
cp = ip_vs_conn_in_get(iph->protocol,
|
||||
iph->daddr, 0,
|
||||
iph->saddr, 0);
|
||||
}
|
||||
|
||||
return cp;
|
||||
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ip_vs_conn *
|
||||
icmp_conn_out_get(const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp,
|
||||
const struct iphdr *iph,
|
||||
unsigned int proto_off,
|
||||
int inverse)
|
||||
{
|
||||
#if 0
|
||||
struct ip_vs_conn *cp;
|
||||
|
||||
if (likely(!inverse)) {
|
||||
cp = ip_vs_conn_out_get(iph->protocol,
|
||||
iph->saddr, 0,
|
||||
iph->daddr, 0);
|
||||
} else {
|
||||
cp = ip_vs_conn_out_get(IPPROTO_UDP,
|
||||
iph->daddr, 0,
|
||||
iph->saddr, 0);
|
||||
}
|
||||
|
||||
return cp;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
|
||||
int *verdict, struct ip_vs_conn **cpp)
|
||||
{
|
||||
*verdict = NF_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
|
||||
{
|
||||
if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) {
|
||||
if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
|
||||
if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) {
|
||||
IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
icmp_debug_packet(struct ip_vs_protocol *pp,
|
||||
const struct sk_buff *skb,
|
||||
int offset,
|
||||
const char *msg)
|
||||
{
|
||||
char buf[256];
|
||||
struct iphdr _iph, *ih;
|
||||
|
||||
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
|
||||
if (ih == NULL)
|
||||
sprintf(buf, "%s TRUNCATED", pp->name);
|
||||
else if (ih->frag_off & __constant_htons(IP_OFFSET))
|
||||
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
|
||||
pp->name, NIPQUAD(ih->saddr),
|
||||
NIPQUAD(ih->daddr));
|
||||
else {
|
||||
struct icmphdr _icmph, *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, offset + ih->ihl*4,
|
||||
sizeof(_icmph), &_icmph);
|
||||
if (ic == NULL)
|
||||
sprintf(buf, "%s TRUNCATED to %u bytes\n",
|
||||
pp->name, skb->len - offset);
|
||||
else
|
||||
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
|
||||
pp->name, NIPQUAD(ih->saddr),
|
||||
NIPQUAD(ih->daddr),
|
||||
ic->type, ic->code);
|
||||
}
|
||||
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_state_transition(struct ip_vs_conn *cp, int direction,
|
||||
const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp)
|
||||
{
|
||||
cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
|
||||
{
|
||||
int num;
|
||||
char **names;
|
||||
|
||||
num = IP_VS_ICMP_S_LAST;
|
||||
names = icmp_state_name_table;
|
||||
return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to);
|
||||
}
|
||||
|
||||
|
||||
static void icmp_init(struct ip_vs_protocol *pp)
|
||||
{
|
||||
pp->timeout_table = icmp_timeouts;
|
||||
}
|
||||
|
||||
static void icmp_exit(struct ip_vs_protocol *pp)
|
||||
{
|
||||
}
|
||||
|
||||
struct ip_vs_protocol ip_vs_protocol_icmp = {
|
||||
.name = "ICMP",
|
||||
.protocol = IPPROTO_ICMP,
|
||||
.dont_defrag = 0,
|
||||
.init = icmp_init,
|
||||
.exit = icmp_exit,
|
||||
.conn_schedule = icmp_conn_schedule,
|
||||
.conn_in_get = icmp_conn_in_get,
|
||||
.conn_out_get = icmp_conn_out_get,
|
||||
.snat_handler = NULL,
|
||||
.dnat_handler = NULL,
|
||||
.csum_check = icmp_csum_check,
|
||||
.state_transition = icmp_state_transition,
|
||||
.register_app = NULL,
|
||||
.unregister_app = NULL,
|
||||
.app_conn_bind = NULL,
|
||||
.debug_packet = icmp_debug_packet,
|
||||
.timeout_change = NULL,
|
||||
.set_state_timeout = icmp_set_state_timeout,
|
||||
};
|
|
@ -37,5 +37,4 @@ EXPORT_SYMBOL(in6_dev_finish_destroy);
|
|||
EXPORT_SYMBOL(xfrm6_rcv);
|
||||
#endif
|
||||
EXPORT_SYMBOL(rt6_lookup);
|
||||
EXPORT_SYMBOL(fl6_sock_lookup);
|
||||
EXPORT_SYMBOL(ipv6_push_nfrag_opts);
|
||||
|
|
Loading…
Reference in New Issue