auto merge with /home/aegl/GIT/linus

This commit is contained in:
Tony Luck 2005-06-06 15:42:07 -07:00
commit 26abd53d8e
51 changed files with 2375 additions and 1096 deletions

View File

@ -14,7 +14,7 @@
</authorgroup> </authorgroup>
<copyright> <copyright>
<year>2003</year> <year>2003-2005</year>
<holder>Jeff Garzik</holder> <holder>Jeff Garzik</holder>
</copyright> </copyright>
@ -44,30 +44,38 @@
<toc></toc> <toc></toc>
<chapter id="libataThanks"> <chapter id="libataIntroduction">
<title>Thanks</title> <title>Introduction</title>
<para> <para>
The bulk of the ATA knowledge comes thanks to long conversations with libATA is a library used inside the Linux kernel to support ATA host
Andre Hedrick (www.linux-ide.org). controllers and devices. libATA provides an ATA driver API, class
transports for ATA and ATAPI devices, and SCSI&lt;-&gt;ATA translation
for ATA devices according to the T10 SAT specification.
</para> </para>
<para> <para>
Thanks to Alan Cox for pointing out similarities This Guide documents the libATA driver API, library functions, library
between SATA and SCSI, and in general for motivation to hack on internals, and a couple sample ATA low-level drivers.
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> </para>
</chapter> </chapter>
<chapter id="libataDriverApi"> <chapter id="libataDriverApi">
<title>libata Driver API</title> <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> <sect1>
<title>struct ata_port_operations</title> <title>struct ata_port_operations</title>
<sect2><title>Disable ATA port</title>
<programlisting> <programlisting>
void (*port_disable) (struct ata_port *); void (*port_disable) (struct ata_port *);
</programlisting> </programlisting>
@ -78,6 +86,9 @@ void (*port_disable) (struct ata_port *);
unplug). unplug).
</para> </para>
</sect2>
<sect2><title>Post-IDENTIFY device configuration</title>
<programlisting> <programlisting>
void (*dev_config) (struct ata_port *, struct ata_device *); void (*dev_config) (struct ata_port *, struct ata_device *);
</programlisting> </programlisting>
@ -88,6 +99,9 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
issue of SET FEATURES - XFER MODE, and prior to operation. issue of SET FEATURES - XFER MODE, and prior to operation.
</para> </para>
</sect2>
<sect2><title>Set PIO/DMA mode</title>
<programlisting> <programlisting>
void (*set_piomode) (struct ata_port *, struct ata_device *); void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (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. ->set_dma_mode() is only called if DMA is possible.
</para> </para>
</sect2>
<sect2><title>Taskfile read/write</title>
<programlisting> <programlisting>
void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
void (*tf_read) (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. taskfile register values.
</para> </para>
</sect2>
<sect2><title>ATA command execute</title>
<programlisting> <programlisting>
void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
</programlisting> </programlisting>
@ -129,17 +149,37 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
->tf_load(), to be initiated in hardware. ->tf_load(), to be initiated in hardware.
</para> </para>
</sect2>
<sect2><title>Per-cmd ATAPI DMA capabilities filter</title>
<programlisting> <programlisting>
u8 (*check_status)(struct ata_port *ap); int (*check_atapi_dma) (struct ata_queued_cmd *qc);
void (*dev_select)(struct ata_port *ap, unsigned int device);
</programlisting> </programlisting>
<para> <para>
Reads the Status ATA shadow register from hardware. On some Allow low-level driver to filter ATA PACKET commands, returning a status
hardware, this has the side effect of clearing the interrupt indicating whether or not it is OK to use DMA for the supplied PACKET
condition. command.
</para> </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> <programlisting>
void (*dev_select)(struct ata_port *ap, unsigned int device); void (*dev_select)(struct ata_port *ap, unsigned int device);
</programlisting> </programlisting>
@ -147,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
<para> <para>
Issues the low-level hardware command(s) that causes one of N Issues the low-level hardware command(s) that causes one of N
hardware devices to be considered 'selected' (active and 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> </para>
</sect2>
<sect2><title>Reset ATA bus</title>
<programlisting> <programlisting>
void (*phy_reset) (struct ata_port *ap); void (*phy_reset) (struct ata_port *ap);
</programlisting> </programlisting>
@ -162,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap);
functions ata_bus_reset() or sata_phy_reset() for this hook. functions ata_bus_reset() or sata_phy_reset() for this hook.
</para> </para>
</sect2>
<sect2><title>Control PCI IDE BMDMA engine</title>
<programlisting> <programlisting>
void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (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> </programlisting>
<para> <para>
When setting up an IDE BMDMA transaction, these hooks arm When setting up an IDE BMDMA transaction, these hooks arm
(->bmdma_setup) and fire (->bmdma_start) the hardware's DMA (->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop)
engine. the hardware's DMA engine. ->bmdma_status is used to read the standard
PCI IDE DMA Status register.
</para> </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> <programlisting>
void (*qc_prep) (struct ata_queued_cmd *qc); void (*qc_prep) (struct ata_queued_cmd *qc);
int (*qc_issue) (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 ->qc_issue is used to make a command active, once the hardware
and S/G tables have been prepared. IDE BMDMA drivers use the and S/G tables have been prepared. IDE BMDMA drivers use the
helper function ata_qc_issue_prot() for taskfile protocol-based helper function ata_qc_issue_prot() for taskfile protocol-based
dispatch. More advanced drivers roll their own ->qc_issue dispatch. More advanced drivers implement their own ->qc_issue.
implementation, using this as the "issue new ATA command to
hardware" hook.
</para> </para>
</sect2>
<sect2><title>Timeout (error) handling</title>
<programlisting> <programlisting>
void (*eng_timeout) (struct ata_port *ap); void (*eng_timeout) (struct ata_port *ap);
</programlisting> </programlisting>
<para> <para>
This is a high level error handling function, called from the This is a high level error handling function, called from the
error handling thread, when a command times out. 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> </para>
</sect2>
<sect2><title>Hardware interrupt handling</title>
<programlisting> <programlisting>
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *); void (*irq_clear) (struct ata_port *);
@ -216,6 +280,9 @@ void (*irq_clear) (struct ata_port *);
is quiet. is quiet.
</para> </para>
</sect2>
<sect2><title>SATA phy read/write</title>
<programlisting> <programlisting>
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
void (*scr_write) (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. if ->phy_reset hook called the sata_phy_reset() helper function.
</para> </para>
</sect2>
<sect2><title>Init and shutdown</title>
<programlisting> <programlisting>
int (*port_start) (struct ata_port *ap); int (*port_start) (struct ata_port *ap);
void (*port_stop) (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. tasks.
</para> </para>
<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 ->port_stop() is called after ->host_stop(). It's sole function
is to release DMA/memory resources, now that they are no longer is to release DMA/memory resources, now that they are no longer
actively being used. actively being used.
</para> </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> </sect1>
</chapter> </chapter>
@ -279,4 +351,24 @@ void (*host_stop) (struct ata_host_set *host_set);
!Idrivers/scsi/sata_sil.c !Idrivers/scsi/sata_sil.c
</chapter> </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> </book>

View File

@ -1,7 +1,7 @@
VERSION = 2 VERSION = 2
PATCHLEVEL = 6 PATCHLEVEL = 6
SUBLEVEL = 12 SUBLEVEL = 12
EXTRAVERSION =-rc5 EXTRAVERSION =-rc6
NAME=Woozy Numbat NAME=Woozy Numbat
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void);
*/ */
void default_idle(void) void default_idle(void)
{ {
while(1) { local_irq_disable();
if (need_resched()) while (!need_resched()) {
__asm__("stop #0x2000" : : : "cc"); /* This stop will re-enable interrupts */
schedule(); __asm__("stop #0x2000" : : : "cc");
local_irq_disable();
} }
local_irq_enable();
} }
void (*idle)(void) = default_idle; void (*idle)(void) = default_idle;
@ -63,7 +65,12 @@ void (*idle)(void) = default_idle;
void cpu_idle(void) void cpu_idle(void)
{ {
/* endless idle loop with no priority at all */ /* endless idle loop with no priority at all */
idle(); while (1) {
idle();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
} }
void machine_restart(char * __unused) void machine_restart(char * __unused)

View File

@ -619,7 +619,7 @@ _GLOBAL(flush_instruction_cache)
_GLOBAL(flush_icache_range) _GLOBAL(flush_icache_range)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
blr /* for 601, do nothing */ 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 li r5,L1_CACHE_LINE_SIZE-1
andc r3,r3,r5 andc r3,r3,r5
subf r4,r3,r4 subf r4,r3,r4
@ -736,7 +736,7 @@ _GLOBAL(flush_dcache_all)
_GLOBAL(__flush_dcache_icache) _GLOBAL(__flush_dcache_icache)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
blr /* for 601, do nothing */ 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 */ rlwinm r3,r3,0,0,19 /* Get page base address */
li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */
mtctr r4 mtctr r4
@ -764,7 +764,7 @@ END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
_GLOBAL(__flush_dcache_icache_phys) _GLOBAL(__flush_dcache_icache_phys)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
blr /* for 601, do nothing */ blr /* for 601, do nothing */
END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE) END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
mfmsr r10 mfmsr r10
rlwinm r0,r10,0,28,26 /* clear DR */ rlwinm r0,r10,0,28,26 /* clear DR */
mtmsr r0 mtmsr r0

View File

@ -1370,7 +1370,7 @@ static int __init prom_find_machine_type(void)
} }
/* Default to pSeries. We need to know if we are running LPAR */ /* Default to pSeries. We need to know if we are running LPAR */
rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
if (!PHANDLE_VALID(rtas)) { if (PHANDLE_VALID(rtas)) {
int x = prom_getproplen(rtas, "ibm,hypertas-functions"); int x = prom_getproplen(rtas, "ibm,hypertas-functions");
if (x != PROM_ERROR) { if (x != PROM_ERROR) {
prom_printf("Hypertas detected, assuming LPAR !\n"); prom_printf("Hypertas detected, assuming LPAR !\n");

View File

@ -28,6 +28,7 @@
//#include <linux/kernel_stat.h> //#include <linux/kernel_stat.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/workqueue.h>
#include "appldata.h" #include "appldata.h"
@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL;
static int appldata_timer_active; 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 * Ops list
@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock);
static LIST_HEAD(appldata_ops_list); static LIST_HEAD(appldata_ops_list);
/************************* timer, tasklet, DIAG ******************************/ /*************************** timer, work, DIAG *******************************/
/* /*
* appldata_timer_function() * 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) 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)); atomic_read(&appldata_expire_count));
if (atomic_dec_and_test(&appldata_expire_count)) { if (atomic_dec_and_test(&appldata_expire_count)) {
atomic_set(&appldata_expire_count, num_online_cpus()); 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 * 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 list_head *lh;
struct appldata_ops *ops; struct appldata_ops *ops;
int i; int i;
P_DEBUG(" -= Tasklet =-\n"); P_DEBUG(" -= Work Queue =-\n");
i = 0; i = 0;
spin_lock(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { 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"); : "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
return (int) ry; return (int) ry;
} }
/********************** timer, tasklet, DIAG <END> ***************************/ /************************ timer, work, DIAG <END> ****************************/
/****************************** /proc stuff **********************************/ /****************************** /proc stuff **********************************/
@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
struct list_head *lh; struct list_head *lh;
found = 0; found = 0;
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list); tmp_ops = list_entry(lh, struct appldata_ops, list);
if (&tmp_ops->ctl_table[2] == ctl) { if (&tmp_ops->ctl_table[2] == ctl) {
@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
} }
} }
if (!found) { if (!found) {
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -ENODEV; return -ENODEV;
} }
ops = ctl->data; ops = ctl->data;
if (!try_module_get(ops->owner)) { // protect this function if (!try_module_get(ops->owner)) { // protect this function
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -ENODEV; return -ENODEV;
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
if (!*lenp || *ppos) { if (!*lenp || *ppos) {
*lenp = 0; *lenp = 0;
@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
return -EFAULT; return -EFAULT;
} }
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
if ((buf[0] == '1') && (ops->active == 0)) { if ((buf[0] == '1') && (ops->active == 0)) {
if (!try_module_get(ops->owner)) { // protect tasklet // protect work queue callback
spin_unlock_bh(&appldata_ops_lock); if (!try_module_get(ops->owner)) {
spin_unlock(&appldata_ops_lock);
module_put(ops->owner); module_put(ops->owner);
return -ENODEV; return -ENODEV;
} }
@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
} }
module_put(ops->owner); module_put(ops->owner);
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
out: out:
*lenp = len; *lenp = len;
*ppos += 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)); 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) { list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list); tmp_ops = list_entry(lh, struct appldata_ops, list);
P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n", 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) { APPLDATA_PROC_NAME_LENGTH) == 0) {
P_ERROR("Name \"%s\" already registered!\n", ops->name); P_ERROR("Name \"%s\" already registered!\n", ops->name);
kfree(ops->ctl_table); kfree(ops->ctl_table);
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -EBUSY; return -EBUSY;
} }
if (tmp_ops->ctl_nr == ops->ctl_nr) { if (tmp_ops->ctl_nr == ops->ctl_nr) {
P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr); P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
kfree(ops->ctl_table); kfree(ops->ctl_table);
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -EBUSY; return -EBUSY;
} }
} }
list_add(&ops->list, &appldata_ops_list); 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].ctl_name = CTL_APPLDATA;
ops->ctl_table[0].procname = appldata_proc_name; 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) 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); unregister_sysctl_table(ops->sysctl_header);
list_del(&ops->list); list_del(&ops->list);
kfree(ops->ctl_table); kfree(ops->ctl_table);
ops->ctl_table = NULL; ops->ctl_table = NULL;
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
P_INFO("%s-ops unregistered!\n", ops->name); P_INFO("%s-ops unregistered!\n", ops->name);
} }
/********************** module-ops management <END> **************************/ /********************** module-ops management <END> **************************/
@ -602,7 +607,7 @@ appldata_online_cpu(int cpu)
init_virt_timer(&per_cpu(appldata_timer, cpu)); init_virt_timer(&per_cpu(appldata_timer, cpu));
per_cpu(appldata_timer, cpu).function = appldata_timer_function; per_cpu(appldata_timer, cpu).function = appldata_timer_function;
per_cpu(appldata_timer, cpu).data = (unsigned long) per_cpu(appldata_timer, cpu).data = (unsigned long)
&appldata_tasklet_struct; &appldata_work;
atomic_inc(&appldata_expire_count); atomic_inc(&appldata_expire_count);
spin_lock(&appldata_timer_lock); spin_lock(&appldata_timer_lock);
__appldata_vtimer_setup(APPLDATA_MOD_TIMER); __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu)
del_virt_timer(&per_cpu(appldata_timer, cpu)); del_virt_timer(&per_cpu(appldata_timer, cpu));
if (atomic_dec_and_test(&appldata_expire_count)) { if (atomic_dec_and_test(&appldata_expire_count)) {
atomic_set(&appldata_expire_count, num_online_cpus()); atomic_set(&appldata_expire_count, num_online_cpus());
tasklet_schedule(&appldata_tasklet_struct); queue_work(appldata_wq, &appldata_work);
} }
spin_lock(&appldata_timer_lock); spin_lock(&appldata_timer_lock);
__appldata_vtimer_setup(APPLDATA_MOD_TIMER); __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = {
/* /*
* appldata_init() * appldata_init()
* *
* init timer and tasklet, register /proc entries * init timer, register /proc entries
*/ */
static int __init appldata_init(void) static int __init appldata_init(void)
{ {
@ -657,6 +662,12 @@ static int __init appldata_init(void)
P_DEBUG("sizeof(parameter_list) = %lu\n", P_DEBUG("sizeof(parameter_list) = %lu\n",
sizeof(struct appldata_parameter_list)); 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) for_each_online_cpu(i)
appldata_online_cpu(i); appldata_online_cpu(i);
@ -670,7 +681,6 @@ static int __init appldata_init(void)
appldata_table[1].de->owner = THIS_MODULE; appldata_table[1].de->owner = THIS_MODULE;
#endif #endif
tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
P_DEBUG("Base interface initialized.\n"); P_DEBUG("Base interface initialized.\n");
return 0; return 0;
} }
@ -678,7 +688,7 @@ static int __init appldata_init(void)
/* /*
* appldata_exit() * appldata_exit()
* *
* stop timer and tasklet, unregister /proc entries * stop timer, unregister /proc entries
*/ */
static void __exit appldata_exit(void) 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... * 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) { list_for_each(lh, &appldata_ops_list) {
ops = list_entry(lh, struct appldata_ops, list); ops = list_entry(lh, struct appldata_ops, list);
rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, 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); "return code: %d\n", ops->name, rc);
} }
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
for_each_online_cpu(i) for_each_online_cpu(i)
appldata_offline_cpu(i); appldata_offline_cpu(i);
@ -709,7 +719,7 @@ static void __exit appldata_exit(void)
unregister_sysctl_table(appldata_sysctl_header); unregister_sysctl_table(appldata_sysctl_header);
tasklet_kill(&appldata_tasklet_struct); destroy_workqueue(appldata_wq);
P_DEBUG("... module unloaded!\n"); P_DEBUG("... module unloaded!\n");
} }
/**************************** init / exit <END> ******************************/ /**************************** init / exit <END> ******************************/

View File

@ -68,7 +68,7 @@ struct appldata_mem_data {
u64 pgmajfault; /* page faults (major only) */ u64 pgmajfault; /* page faults (major only) */
// <-- New in 2.6 // <-- New in 2.6
} appldata_mem_data; } __attribute__((packed)) appldata_mem_data;
static inline void appldata_debug_print(struct appldata_mem_data *mem_data) static inline void appldata_debug_print(struct appldata_mem_data *mem_data)

View File

@ -57,7 +57,7 @@ struct appldata_net_sum_data {
u64 rx_dropped; /* no space in linux buffers */ u64 rx_dropped; /* no space in linux buffers */
u64 tx_dropped; /* no space available in linux */ u64 tx_dropped; /* no space available in linux */
u64 collisions; /* collisions while transmitting */ 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) static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)

View File

@ -49,7 +49,7 @@ struct appldata_os_per_cpu {
u32 per_cpu_softirq; /* ... spent in softirqs */ u32 per_cpu_softirq; /* ... spent in softirqs */
u32 per_cpu_iowait; /* ... spent while waiting for I/O */ u32 per_cpu_iowait; /* ... spent while waiting for I/O */
// <-- New in 2.6 // <-- New in 2.6
}; } __attribute__((packed));
struct appldata_os_data { struct appldata_os_data {
u64 timestamp; u64 timestamp;
@ -75,7 +75,7 @@ struct appldata_os_data {
/* per cpu data */ /* per cpu data */
struct appldata_os_per_cpu os_cpu[0]; struct appldata_os_per_cpu os_cpu[0];
}; } __attribute__((packed));
static struct appldata_os_data *appldata_os_data; static struct appldata_os_data *appldata_os_data;

View File

@ -40,6 +40,7 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h>
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
#include "compat_ptrace.h" #include "compat_ptrace.h"
@ -130,13 +131,19 @@ static int
peek_user(struct task_struct *child, addr_t addr, addr_t data) peek_user(struct task_struct *child, addr_t addr, addr_t data)
{ {
struct user *dummy = NULL; struct user *dummy = NULL;
addr_t offset, tmp; addr_t offset, tmp, mask;
/* /*
* Stupid gdb peeks/pokes the access registers in 64 bit with * Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell... * 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; return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) { 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 * access registers are stored in the thread structure
*/ */
offset = addr - (addr_t) &dummy->regs.acrs; 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); tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { } 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; offset = addr - (addr_t) &dummy->regs.fp_regs;
tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); 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)) { } 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) poke_user(struct task_struct *child, addr_t addr, addr_t data)
{ {
struct user *dummy = NULL; struct user *dummy = NULL;
addr_t offset; addr_t offset, mask;
/* /*
* Stupid gdb peeks/pokes the access registers in 64 bit with * Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell indeed... * 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; return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) { 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 * access registers are stored in the thread structure
*/ */
offset = addr - (addr_t) &dummy->regs.acrs; 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; *(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { } 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 * floating point regs. are stored in the thread structure
*/ */
if (addr == (addr_t) &dummy->regs.fp_regs.fpc && 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; return -EINVAL;
offset = addr - (addr_t) &dummy->regs.fp_regs; offset = addr - (addr_t) &dummy->regs.fp_regs;
*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; *(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) ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0)); ? 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 * 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 * for normal use. strace only continues with a signal if the

View File

@ -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 * we are not in an interrupt and that there is a
* user context. * user context.
*/ */
if (user_address == 0 || in_interrupt() || !mm) if (user_address == 0 || in_atomic() || !mm)
goto no_context; goto no_context;
/* /*

View File

@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
fore_200e-objs += fore200e_pca_fw.o fore_200e-objs += fore200e_pca_fw.o
# guess the target endianess to choose the right PCA-200E firmware image # guess the target endianess to choose the right PCA-200E firmware image
ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) 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
endif endif

View File

@ -383,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore200e)
switch(fore200e->state) { switch(fore200e->state) {
case FORE200E_STATE_COMPLETE: case FORE200E_STATE_COMPLETE:
if (fore200e->stats) kfree(fore200e->stats);
kfree(fore200e->stats);
case FORE200E_STATE_IRQ: case FORE200E_STATE_IRQ:
free_irq(fore200e->irq, fore200e->atm_dev); 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); entry, txq->tail, entry->vc_map, entry->skb);
/* free copy of misaligned data */ /* free copy of misaligned data */
if (entry->data) kfree(entry->data);
kfree(entry->data);
/* remove DMA mapping */ /* remove DMA mapping */
fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,

View File

@ -412,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
init_one_failure: init_one_failure:
if (atm_dev) if (atm_dev)
atm_dev_deregister(atm_dev); atm_dev_deregister(atm_dev);
if (he_dev) kfree(he_dev);
kfree(he_dev);
pci_disable_device(pci_dev); pci_disable_device(pci_dev);
return err; return err;
} }
@ -2534,8 +2533,7 @@ he_open(struct atm_vcc *vcc)
open_failed: open_failed:
if (err) { if (err) {
if (he_vcc) kfree(he_vcc);
kfree(he_vcc);
clear_bit(ATM_VF_ADDR, &vcc->flags); clear_bit(ATM_VF_ADDR, &vcc->flags);
} }
else else

View File

@ -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); PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
/* Initialize SCQ0, the only VBR SCQ used */ /* Initialize SCQ0, the only VBR SCQ used */
card->scq1 = (scq_info *) NULL; card->scq1 = NULL;
card->scq2 = (scq_info *) NULL; card->scq2 = NULL;
card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); 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); printk("nicstar%d: can't get SCQ0.\n", i);
error = 12; error = 12;
@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 scd)
int i; int i;
if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
return (scq_info *) NULL; return NULL;
scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
if (scq == (scq_info *) NULL) if (scq == NULL)
return (scq_info *) NULL; return NULL;
scq->org = kmalloc(2 * size, GFP_KERNEL); scq->org = kmalloc(2 * size, GFP_KERNEL);
if (scq->org == NULL) if (scq->org == NULL)
{ {
kfree(scq); kfree(scq);
return (scq_info *) NULL; return NULL;
} }
scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
(size / NS_SCQE_SIZE), GFP_KERNEL); (size / NS_SCQE_SIZE), GFP_KERNEL);
if (scq->skb == (struct sk_buff **) NULL) if (scq->skb == NULL)
{ {
kfree(scq->org); kfree(scq->org);
kfree(scq); kfree(scq);
return (scq_info *) NULL; return NULL;
} }
scq->num_entries = size / NS_SCQE_SIZE; scq->num_entries = size / NS_SCQE_SIZE;
scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, 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; vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); 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); PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
card->scd2vc[frscdi] = NULL; card->scd2vc[frscdi] = NULL;

View File

@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc)
zatm_dev->tx_bw += vcc->qos.txtp.min_pcr; zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
dealloc_shaper(vcc->dev,zatm_vcc->shaper); 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; return 0;
out: out:
for (i = 0; i < NR_MBX; i++) for (i = 0; i < NR_MBX; i++)
if (zatm_dev->mbx_start[i] != 0) kfree(zatm_dev->mbx_start[i]);
kfree((void *) zatm_dev->mbx_start[i]); kfree(zatm_dev->rx_map);
if (zatm_dev->rx_map != NULL) kfree(zatm_dev->tx_map);
kfree(zatm_dev->rx_map);
if (zatm_dev->tx_map != NULL)
kfree(zatm_dev->tx_map);
free_irq(zatm_dev->irq, dev); free_irq(zatm_dev->irq, dev);
return error; return error;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1995,9 +1995,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
unsigned char ch, gdl; unsigned char ch, gdl;
int ignored = 0; int ignored = 0;
int cnt = 0; int cnt = 0;
unsigned char *cp;
char *fp;
int count;
int recv_room; int recv_room;
int max = 256; int max = 256;
unsigned long flags; unsigned long flags;
@ -2011,10 +2008,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
//return; //return;
} }
cp = tty->flip.char_buf;
fp = tty->flip.flag_buf;
count = 0;
// following add by Victor Yu. 09-02-2002 // following add by Victor Yu. 09-02-2002
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) { if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
@ -2041,12 +2034,10 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
} }
while (gdl--) { while (gdl--) {
ch = inb(info->base + UART_RX); ch = inb(info->base + UART_RX);
count++; tty_insert_flip_char(tty, ch, 0);
*cp++ = ch;
*fp++ = 0;
cnt++; cnt++;
/* /*
if((count>=HI_WATER) && (info->stop_rx==0)){ if((cnt>=HI_WATER) && (info->stop_rx==0)){
mxser_stoprx(tty); mxser_stoprx(tty);
info->stop_rx=1; info->stop_rx=1;
break; break;
@ -2061,7 +2052,7 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
if (max-- < 0) if (max-- < 0)
break; break;
/* /*
if((count>=HI_WATER) && (info->stop_rx==0)){ if((cnt>=HI_WATER) && (info->stop_rx==0)){
mxser_stoprx(tty); mxser_stoprx(tty);
info->stop_rx=1; info->stop_rx=1;
break; break;
@ -2078,36 +2069,33 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
if (++ignored > 100) if (++ignored > 100)
break; break;
} else { } else {
count++; char flag = 0;
if (*status & UART_LSR_SPECIAL) { if (*status & UART_LSR_SPECIAL) {
if (*status & UART_LSR_BI) { if (*status & UART_LSR_BI) {
*fp++ = TTY_BREAK; flag = TTY_BREAK;
/* added by casper 1/11/2000 */ /* added by casper 1/11/2000 */
info->icount.brk++; info->icount.brk++;
/* */ /* */
if (info->flags & ASYNC_SAK) if (info->flags & ASYNC_SAK)
do_SAK(tty); do_SAK(tty);
} else if (*status & UART_LSR_PE) { } else if (*status & UART_LSR_PE) {
*fp++ = TTY_PARITY; flag = TTY_PARITY;
/* added by casper 1/11/2000 */ /* added by casper 1/11/2000 */
info->icount.parity++; info->icount.parity++;
/* */ /* */
} else if (*status & UART_LSR_FE) { } else if (*status & UART_LSR_FE) {
*fp++ = TTY_FRAME; flag = TTY_FRAME;
/* added by casper 1/11/2000 */ /* added by casper 1/11/2000 */
info->icount.frame++; info->icount.frame++;
/* */ /* */
} else if (*status & UART_LSR_OE) { } else if (*status & UART_LSR_OE) {
*fp++ = TTY_OVERRUN; flag = TTY_OVERRUN;
/* added by casper 1/11/2000 */ /* added by casper 1/11/2000 */
info->icount.overrun++; info->icount.overrun++;
/* */ /* */
} else }
*fp++ = 0; }
} else tty_insert_flip_char(tty, ch, flag);
*fp++ = 0;
*cp++ = ch;
cnt++; cnt++;
if (cnt >= recv_room) { if (cnt >= recv_room) {
if (!info->ldisc_stop_rx) { if (!info->ldisc_stop_rx) {
@ -2132,13 +2120,13 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
// above add by Victor Yu. 09-02-2002 // above add by Victor Yu. 09-02-2002
} while (*status & UART_LSR_DR); } 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; mxvar_log.rxcnt[info->port] += cnt;
info->mon_data.rxcnt += cnt; info->mon_data.rxcnt += cnt;
info->mon_data.up_rxcnt += cnt; info->mon_data.up_rxcnt += cnt;
spin_unlock_irqrestore(&info->slock, flags); spin_unlock_irqrestore(&info->slock, flags);
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }

View File

@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *dev)
spin_lock_irqsave(&lp->window_lock, flags); spin_lock_irqsave(&lp->window_lock, flags);
update_stats(dev); update_stats(dev);
spin_unlock_irqrestore(&lp->window_lock, flags); spin_unlock_irqrestore(&lp->window_lock, flags);
/* force interrupts off */
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
} }
link->open--; link->open--;

View File

@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(EarlyTxThres, EarlyTxThld); RTL_W8(EarlyTxThres, EarlyTxThld);
/* For gigabit rtl8169, MTU + header + CRC + VLAN */ /* Low hurts. Let's disable the filtering. */
RTL_W16(RxMaxSize, tp->rx_buf_sz); RTL_W16(RxMaxSize, 16383);
/* Set Rx Config register */ /* Set Rx Config register */
i = rtl8169_rx_config | 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) static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
{ {
u32 opts1 = le32_to_cpu(desc->opts1); 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) { while (rx_left > 0) {
unsigned int entry = cur_rx % NUM_RX_DESC; unsigned int entry = cur_rx % NUM_RX_DESC;
struct RxDesc *desc = tp->RxDescArray + entry;
u32 status; u32 status;
rmb(); rmb();
status = le32_to_cpu(tp->RxDescArray[entry].opts1); status = le32_to_cpu(desc->opts1);
if (status & DescOwn) if (status & DescOwn)
break; break;
if (status & RxRES) { 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++; tp->stats.rx_errors++;
if (status & (RxRWT | RxRUNT)) if (status & (RxRWT | RxRUNT))
tp->stats.rx_length_errors++; tp->stats.rx_length_errors++;
if (status & RxCRC) if (status & RxCRC)
tp->stats.rx_crc_errors++; tp->stats.rx_crc_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else { } else {
struct RxDesc *desc = tp->RxDescArray + entry;
struct sk_buff *skb = tp->Rx_skbuff[entry]; struct sk_buff *skb = tp->Rx_skbuff[entry];
int pkt_size = (status & 0x00001FFF) - 4; int pkt_size = (status & 0x00001FFF) - 4;
void (*pci_action)(struct pci_dev *, dma_addr_t, void (*pci_action)(struct pci_dev *, dma_addr_t,
size_t, int) = pci_dma_sync_single_for_device; 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); rtl8169_rx_csum(skb, desc);
pci_dma_sync_single_for_cpu(tp->pci_dev, 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_bytes += pkt_size;
tp->stats.rx_packets++; tp->stats.rx_packets++;
} }
move_on:
cur_rx++; cur_rx++;
rx_left--; rx_left--;
} }

View File

@ -100,35 +100,8 @@ static int sh_debug; /* Debug flag */
#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" #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_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 * Compute clocks on a buffer
*/ */
@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
* Throw a frame at a shaper. * 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; struct sk_buff *ptr;
/* if (down_trylock(&shaper->sem))
* Get ready to work on this shaper. Lock may fail if its return -1;
* an interrupt and locked.
*/
if(!shaper_lock(shaper))
return -1;
ptr=shaper->sendq.prev; ptr=shaper->sendq.prev;
/* /*
@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
dev_kfree_skb(ptr); dev_kfree_skb(ptr);
shaper->stats.collisions++; shaper->stats.collisions++;
} }
shaper_unlock(shaper); shaper_kick(shaper);
up(&shaper->sem);
return 0; 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) static void shaper_timer(unsigned long data)
{ {
struct shaper *sh=(struct shaper *)data; struct shaper *shaper = (struct shaper *)data;
shaper_kick(sh);
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; 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) * Walk the list (may be empty)
*/ */
@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper)
if(skb!=NULL) if(skb!=NULL)
mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); 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) static void shaper_flush(struct shaper *shaper)
{ {
struct sk_buff *skb; struct sk_buff *skb;
if(!shaper_lock(shaper))
{ down(&shaper->sem);
printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n");
return;
}
while((skb=skb_dequeue(&shaper->sendq))!=NULL) while((skb=skb_dequeue(&shaper->sendq))!=NULL)
dev_kfree_skb(skb); 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. * 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) static struct net_device_stats *shaper_get_stats(struct net_device *dev)
{ {
struct shaper *sh=dev->priv; struct shaper *sh=dev->priv;
@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev)
init_timer(&sh->timer); init_timer(&sh->timer);
sh->timer.function=shaper_timer; sh->timer.function=shaper_timer;
sh->timer.data=(unsigned long)sh; sh->timer.data=(unsigned long)sh;
init_waitqueue_head(&sh->wait_queue);
} }
/* /*

View File

@ -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); return ata_pci_init_one(pdev, port_info, n_ports);
} }
/**
* piix_init -
*
* LOCKING:
*
* RETURNS:
*
*/
static int __init piix_init(void) static int __init piix_init(void)
{ {
int rc; int rc;
@ -689,13 +680,6 @@ static int __init piix_init(void)
return 0; return 0;
} }
/**
* piix_exit -
*
* LOCKING:
*
*/
static void __exit piix_exit(void) static void __exit piix_exit(void)
{ {
pci_unregister_driver(&piix_pci_driver); pci_unregister_driver(&piix_pci_driver);

View File

@ -186,6 +186,28 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
ata_wait_idle(ap); 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) void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
{ {
if (ap->flags & ATA_FLAG_MMIO) 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 * @ap: port to which command is being issued
* @tf: ATA taskfile register set * @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. * synchronization with interrupt handler / other threads.
* *
* LOCKING: * LOCKING:
@ -235,6 +257,18 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
ata_pause(ap); 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) void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
{ {
if (ap->flags & ATA_FLAG_MMIO) 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 * @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input * @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) void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{ {
if (ap->flags & ATA_FLAG_MMIO) 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 * @ap: port where the device is
* *
* Reads ATA taskfile status register for currently-selected device * 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 * from this device
* *
* LOCKING: * LOCKING:
@ -397,7 +448,7 @@ static u8 ata_check_status_pio(struct ata_port *ap)
* @ap: port where the device is * @ap: port where the device is
* *
* Reads ATA taskfile status register for currently-selected device * 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 * from this device
* *
* LOCKING: * LOCKING:
@ -408,6 +459,20 @@ static u8 ata_check_status_mmio(struct ata_port *ap)
return readb((void __iomem *) ap->ioaddr.status_addr); 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) u8 ata_check_status(struct ata_port *ap)
{ {
if (ap->flags & ATA_FLAG_MMIO) if (ap->flags & ATA_FLAG_MMIO)
@ -415,6 +480,20 @@ u8 ata_check_status(struct ata_port *ap)
return ata_check_status_pio(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) u8 ata_altstatus(struct ata_port *ap)
{ {
if (ap->ops->check_altstatus) if (ap->ops->check_altstatus)
@ -425,6 +504,20 @@ u8 ata_altstatus(struct ata_port *ap)
return inb(ap->ioaddr.altstatus_addr); 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) u8 ata_chk_err(struct ata_port *ap)
{ {
if (ap->ops->check_err) 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) void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
{ {
} }
/** /**
* ata_std_dev_select - Select device 0/1 on ATA bus * ata_std_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate * @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 * Use the method defined in the ATA specification to
* make either device 0, or device 1, active on the * 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: * LOCKING:
* caller. * caller.
@ -1190,7 +1299,12 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
* ata_bus_probe - Reset and probe ATA bus * ata_bus_probe - Reset and probe ATA bus
* @ap: Bus to probe * @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: * LOCKING:
* PCI/etc. bus probe sem.
* *
* RETURNS: * RETURNS:
* Zero on success, non-zero on error. * Zero on success, non-zero on error.
@ -1229,10 +1343,14 @@ static int ata_bus_probe(struct ata_port *ap)
} }
/** /**
* ata_port_probe - * ata_port_probe - Mark port as enabled
* @ap: * @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) void ata_port_probe(struct ata_port *ap)
@ -1241,10 +1359,15 @@ void ata_port_probe(struct ata_port *ap)
} }
/** /**
* __sata_phy_reset - * __sata_phy_reset - Wake/reset a low-level SATA PHY
* @ap: * @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: * LOCKING:
* PCI/etc. bus probe sem.
* *
*/ */
void __sata_phy_reset(struct ata_port *ap) void __sata_phy_reset(struct ata_port *ap)
@ -1289,10 +1412,14 @@ void __sata_phy_reset(struct ata_port *ap)
} }
/** /**
* __sata_phy_reset - * sata_phy_reset - Reset SATA bus.
* @ap: * @ap: SATA port associated with target SATA PHY.
*
* This function resets the SATA bus, and then probes
* the bus for devices.
* *
* LOCKING: * LOCKING:
* PCI/etc. bus probe sem.
* *
*/ */
void sata_phy_reset(struct ata_port *ap) void sata_phy_reset(struct ata_port *ap)
@ -1304,10 +1431,16 @@ void sata_phy_reset(struct ata_port *ap)
} }
/** /**
* ata_port_disable - * ata_port_disable - Disable port.
* @ap: * @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) 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 * ata_set_mode - Program timings and issue SET FEATURES - XFER
* @ap: port on which timings will be programmed * @ap: port on which timings will be programmed
* *
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
*
* LOCKING: * LOCKING:
* PCI/etc. bus probe sem.
* *
*/ */
static void ata_set_mode(struct ata_port *ap) static void ata_set_mode(struct ata_port *ap)
@ -1467,7 +1603,10 @@ static void ata_set_mode(struct ata_port *ap)
* @tmout_pat: impatience timeout * @tmout_pat: impatience timeout
* @tmout: overall 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 - * ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
* @ap: * @ap: Port to reset and probe
*
* Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
* probe the bus. Not often used these days.
* *
* LOCKING: * 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. * the device is ATA or ATAPI.
* *
* LOCKING: * LOCKING:
* Inherited from caller. Some functions called by this function * PCI/etc. bus probe sem.
* obtain the host_set lock. * Obtains host_set lock.
* *
* SIDE EFFECTS: * SIDE EFFECTS:
* Sets ATA_FLAG_PORT_DISABLED if bus reset fails. * 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_mode_out: (output) SET FEATURES - XFER MODE code
* @xfer_shift_out: (output) bit shift that selects this mode * @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: * LOCKING:
* PCI/etc. bus probe sem.
* *
* RETURNS: * RETURNS:
* Zero on success, negative on error. * 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 * @ap: Port associated with device @dev
* @dev: Device to which command will be sent * @dev: Device to which command will be sent
* *
* Issue SET FEATURES - XFER MODE command to device @dev
* on port @ap.
*
* LOCKING: * LOCKING:
* PCI/etc. bus probe sem.
*/ */
static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) 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 - * ata_sg_clean - Unmap DMA memory associated with command
* @qc: * @qc: Command containing DMA memory to be released
*
* Unmap all mapped DMA memory associated with this command.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock)
*/ */
static void ata_sg_clean(struct ata_queued_cmd *qc) 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 * ata_fill_sg - Fill PCI IDE PRD table
* @qc: Metadata associated with taskfile to be transferred * @qc: Metadata associated with taskfile to be transferred
* *
* Fill PCI IDE PRD (scatter-gather) table with segments
* associated with the current disk command.
*
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock)
* *
*/ */
static void ata_fill_sg(struct ata_queued_cmd *qc) 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 * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
* @qc: Metadata associated with taskfile to check * @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: * LOCKING:
* spin_lock_irqsave(host_set lock)
*
* RETURNS: 0 when ATAPI DMA can be used * RETURNS: 0 when ATAPI DMA can be used
* nonzero otherwise * nonzero otherwise
*/ */
@ -2046,6 +2210,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
* ata_qc_prep - Prepare taskfile for submission * ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared * @qc: Metadata associated with taskfile to be prepared
* *
* Prepare ATA taskfile for submission.
*
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock) * spin_lock_irqsave(host_set lock)
*/ */
@ -2057,6 +2223,32 @@ void ata_qc_prep(struct ata_queued_cmd *qc)
ata_fill_sg(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) void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
{ {
struct scatterlist *sg; 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; 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, void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
unsigned int n_elem) unsigned int n_elem)
{ {
@ -2083,14 +2301,16 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
} }
/** /**
* ata_sg_setup_one - * ata_sg_setup_one - DMA-map the memory buffer associated with a command.
* @qc: * @qc: Command with memory buffer to be mapped.
*
* DMA-map the memory buffer associated with queued_cmd @qc.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock) * spin_lock_irqsave(host_set lock)
* *
* RETURNS: * RETURNS:
* * Zero on success, negative on error.
*/ */
static int ata_sg_setup_one(struct ata_queued_cmd *qc) 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 - * ata_sg_setup - DMA-map the scatter-gather table associated with a command.
* @qc: * @qc: Command with scatter-gather table to be mapped.
*
* DMA-map the scatter-gather table associated with queued_cmd @qc.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock) * spin_lock_irqsave(host_set lock)
* *
* RETURNS: * RETURNS:
* Zero on success, negative on error.
* *
*/ */
@ -2151,6 +2374,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
* @ap: * @ap:
* *
* LOCKING: * LOCKING:
* None. (executing in kernel thread context)
* *
* RETURNS: * RETURNS:
* *
@ -2198,6 +2422,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
* @ap: * @ap:
* *
* LOCKING: * LOCKING:
* None. (executing in kernel thread context)
*/ */
static void ata_pio_complete (struct ata_port *ap) 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); 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) void swap_buf_le16(u16 *buf, unsigned int buf_words)
{ {
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
@ -2415,6 +2652,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
* @ap: * @ap:
* *
* LOCKING: * LOCKING:
* None. (executing in kernel thread context)
*/ */
static void ata_pio_block(struct ata_port *ap) 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. * transaction completed successfully.
* *
* LOCKING: * LOCKING:
* Inherited from SCSI layer (none, can sleep)
*/ */
static void ata_qc_timeout(struct ata_queued_cmd *qc) static void ata_qc_timeout(struct ata_queued_cmd *qc)
@ -2692,6 +2931,7 @@ void ata_eng_timeout(struct ata_port *ap)
* @dev: Device from whom we request an available command structure * @dev: Device from whom we request an available command structure
* *
* LOCKING: * LOCKING:
* None.
*/ */
static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) 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 * @dev: Device from whom we request an available command structure
* *
* LOCKING: * LOCKING:
* None.
*/ */
struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, 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. * in case something prevents using it.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock)
* *
*/ */
void ata_qc_free(struct ata_queued_cmd *qc) 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 * ata_qc_complete - Complete an active ATA command
* @qc: Command to complete * @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: * LOCKING:
* spin_lock_irqsave(host_set lock)
* *
*/ */
@ -2892,6 +3138,7 @@ int ata_qc_issue(struct ata_queued_cmd *qc)
return -1; return -1;
} }
/** /**
* ata_qc_issue_prot - issue taskfile to device in proto-dependent manner * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
* @qc: command to issue to device * @qc: command to issue to device
@ -2901,6 +3148,8 @@ int ata_qc_issue(struct ata_queued_cmd *qc)
* classes called "protocols", and issuing each type of protocol * classes called "protocols", and issuing each type of protocol
* is slightly different. * is slightly different.
* *
* May be used as the qc_issue() entry in ata_port_operations.
*
* LOCKING: * LOCKING:
* spin_lock_irqsave(host_set lock) * 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. * @qc: Info associated with this ATA transaction.
* *
* LOCKING: * LOCKING:
@ -3065,6 +3314,18 @@ static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
ap->ioaddr.bmdma_addr + ATA_DMA_CMD); 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) void ata_bmdma_start(struct ata_queued_cmd *qc)
{ {
if (qc->ap->flags & ATA_FLAG_MMIO) 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_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) void ata_bmdma_setup(struct ata_queued_cmd *qc)
{ {
if (qc->ap->flags & ATA_FLAG_MMIO) 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_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) void ata_bmdma_irq_clear(struct ata_port *ap)
{ {
if (ap->flags & ATA_FLAG_MMIO) { 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 ata_bmdma_status(struct ata_port *ap)
{ {
u8 host_stat; u8 host_stat;
@ -3104,6 +3405,19 @@ u8 ata_bmdma_status(struct ata_port *ap)
return host_stat; 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) void ata_bmdma_stop(struct ata_port *ap)
{ {
if (ap->flags & ATA_FLAG_MMIO) { if (ap->flags & ATA_FLAG_MMIO) {
@ -3203,13 +3517,18 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
/** /**
* ata_interrupt - Default ATA host interrupt handler * ata_interrupt - Default ATA host interrupt handler
* @irq: irq line * @irq: irq line (unused)
* @dev_instance: pointer to our host information structure * @dev_instance: pointer to our ata_host_set information structure
* @regs: unused * @regs: unused
* *
* Default interrupt handler for PCI IDE devices. Calls
* ata_host_intr() for each port that is not disabled.
*
* LOCKING: * LOCKING:
* Obtains host_set lock during operation.
* *
* RETURNS: * RETURNS:
* IRQ_NONE or IRQ_HANDLED.
* *
*/ */
@ -3302,6 +3621,19 @@ static void atapi_packet_task(void *_data)
ata_qc_complete(qc, ATA_ERR); 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) int ata_port_start (struct ata_port *ap)
{ {
struct device *dev = ap->host_set->dev; struct device *dev = ap->host_set->dev;
@ -3315,6 +3647,18 @@ int ata_port_start (struct ata_port *ap)
return 0; 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) void ata_port_stop (struct ata_port *ap)
{ {
struct device *dev = ap->host_set->dev; 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 * @ent: Probe information provided by low-level driver
* @port_no: Port number associated with this ata_port * @port_no: Port number associated with this ata_port
* *
* Initialize a new ata_port structure, and its associated
* scsi_host.
*
* LOCKING: * 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 * @host_set: Collections of ports to which we add
* @port_no: Port number associated with this host * @port_no: Port number associated with this host
* *
* Attach low-level ATA driver to system.
*
* LOCKING: * LOCKING:
* PCI/etc. bus probe sem.
* *
* RETURNS: * RETURNS:
* New ata_port on success, for NULL on error.
* *
*/ */
@ -3447,12 +3799,22 @@ static struct ata_port * ata_host_add(struct ata_probe_ent *ent,
} }
/** /**
* ata_device_add - * ata_device_add - Register hardware device with ATA and SCSI layers
* @ent: * @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: * LOCKING:
* PCI/etc. bus probe sem.
* *
* RETURNS: * 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. * ata_std_ports - initialize ioaddr with standard port offsets.
* @ioaddr: IO address structure to be initialized * @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) void ata_std_ports(struct ata_ioports *ioaddr)
{ {
ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; 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; 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 #ifdef CONFIG_PCI
struct ata_probe_ent * struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) 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 * @port_info: Information from low-level host driver
* @n_ports: Number of ports attached to host controller * @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: * LOCKING:
* Inherited from PCI layer (may sleep). * Inherited from PCI layer (may sleep).
* *
* RETURNS: * 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 */ #endif /* CONFIG_PCI */
/**
* ata_init -
*
* LOCKING:
*
* RETURNS:
*
*/
static int __init ata_init(void) static int __init ata_init(void)
{ {
ata_wq = create_workqueue("ata"); ata_wq = create_workqueue("ata");

View File

@ -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. * @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
* @buflen: Response buffer length. * @buflen: Response buffer length.

View File

@ -507,6 +507,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
int ret, i; int ret, i;
unsigned int id, lun; unsigned int id, lun;
unsigned long serial; unsigned long serial;
unsigned long flags;
if (!CMD_SP(cmd)) if (!CMD_SP(cmd))
return FAILED; return FAILED;
@ -519,7 +520,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
/* Check active list for command command. */ /* Check active list for command command. */
spin_unlock_irq(ha->host->host_lock); 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++) { for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
sp = ha->outstanding_cmds[i]; sp = ha->outstanding_cmds[i];
@ -534,7 +535,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
sp->state)); sp->state));
DEBUG3(qla2x00_print_scsi_cmd(cmd);) DEBUG3(qla2x00_print_scsi_cmd(cmd);)
spin_unlock(&ha->hardware_lock); spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (qla2x00_abort_command(ha, sp)) { if (qla2x00_abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command " DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no)); "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)); "mbx success.\n", __func__, ha->host_no));
ret = SUCCESS; ret = SUCCESS;
} }
spin_lock(&ha->hardware_lock); spin_lock_irqsave(&ha->hardware_lock, flags);
break; break;
} }
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Wait for the command to be returned. */ /* Wait for the command to be returned. */
if (ret == SUCCESS) { if (ret == SUCCESS) {
spin_unlock(&ha->hardware_lock);
if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) { if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
qla_printk(KERN_ERR, ha, qla_printk(KERN_ERR, ha,
"scsi(%ld:%d:%d): Abort handler timed out -- %lx " "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
"%x.\n", ha->host_no, id, lun, serial, ret); "%x.\n", ha->host_no, id, lun, serial, ret);
} }
spin_lock(&ha->hardware_lock);
} }
spin_lock_irq(ha->host->host_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; int status;
srb_t *sp; srb_t *sp;
struct scsi_cmnd *cmd; struct scsi_cmnd *cmd;
unsigned long flags;
status = 0; status = 0;
@ -596,11 +597,11 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
* array * array
*/ */
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { 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]; sp = ha->outstanding_cmds[cnt];
if (sp) { if (sp) {
cmd = sp->cmd; cmd = sp->cmd;
spin_unlock(&ha->hardware_lock); spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (cmd->device->id == t) { if (cmd->device->id == t) {
if (!qla2x00_eh_wait_on_command(ha, cmd)) { if (!qla2x00_eh_wait_on_command(ha, cmd)) {
status = 1; status = 1;
@ -608,7 +609,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
} }
} }
} else { } else {
spin_unlock(&ha->hardware_lock); spin_unlock_irqrestore(&ha->hardware_lock, flags);
} }
} }
return (status); return (status);
@ -740,6 +741,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
int status; int status;
srb_t *sp; srb_t *sp;
struct scsi_cmnd *cmd; struct scsi_cmnd *cmd;
unsigned long flags;
status = 1; status = 1;
@ -748,17 +750,17 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
* array * array
*/ */
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { 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]; sp = ha->outstanding_cmds[cnt];
if (sp) { if (sp) {
cmd = sp->cmd; cmd = sp->cmd;
spin_unlock(&ha->hardware_lock); spin_unlock_irqrestore(&ha->hardware_lock, flags);
status = qla2x00_eh_wait_on_command(ha, cmd); status = qla2x00_eh_wait_on_command(ha, cmd);
if (status == 0) if (status == 0)
break; break;
} }
else { else {
spin_unlock(&ha->hardware_lock); spin_unlock_irqrestore(&ha->hardware_lock, flags);
} }
} }
return (status); return (status);

View File

@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (!starget) if (!starget)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
get_device(&starget->dev);
down(&shost->scan_mutex); down(&shost->scan_mutex);
res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
if (res != SCSI_SCAN_LUN_PRESENT) if (res != SCSI_SCAN_LUN_PRESENT)

View File

@ -234,7 +234,7 @@ static inline const char *siu_type_name(struct uart_port *port)
return "DSIU"; return "DSIU";
} }
return "unknown"; return NULL;
} }
static unsigned int siu_tx_empty(struct uart_port *port) 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; struct uart_port *port;
uint8_t iir, lsr; uint8_t iir, lsr;
if (dev_id == NULL)
return IRQ_NONE;
port = (struct uart_port *)dev_id; port = (struct uart_port *)dev_id;
iir = siu_read(port, UART_IIR); iir = siu_read(port, UART_IIR);
@ -507,6 +504,9 @@ static int siu_startup(struct uart_port *port)
{ {
int retval; int retval;
if (port->membase == NULL)
return -ENODEV;
siu_clear_fifo(port); siu_clear_fifo(port);
(void)siu_read(port, UART_LSR); (void)siu_read(port, UART_LSR);
@ -545,9 +545,6 @@ static void siu_shutdown(struct uart_port *port)
unsigned long flags; unsigned long flags;
uint8_t lcr; uint8_t lcr;
if (port->membase == NULL)
return;
siu_write(port, UART_IER, 0); siu_write(port, UART_IER, 0);
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
@ -802,53 +799,6 @@ static int siu_init_ports(void)
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE #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) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void wait_for_xmitr(struct uart_port *port) 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->membase == NULL) {
if (port->mapbase == 0) if (port->mapbase == 0)
return -ENODEV; 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); vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
@ -949,7 +899,7 @@ static int __devinit siu_console_init(void)
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
port = &siu_uart_ports[i]; port = &siu_uart_ports[i];
port->ops = &early_uart_ops; port->ops = &siu_uart_ops;
} }
register_console(&siu_console); register_console(&siu_console);
@ -994,8 +944,10 @@ static int siu_probe(struct device *dev)
port->dev = dev; port->dev = dev;
retval = uart_add_one_port(&siu_uart_driver, port); retval = uart_add_one_port(&siu_uart_driver, port);
if (retval) if (retval < 0) {
port->dev = NULL;
break; break;
}
} }
if (i == 0 && retval < 0) { if (i == 0 && retval < 0) {

View File

@ -290,32 +290,30 @@ static ssize_t show_modalias(struct device *dev, char *buf)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_device *udev; struct usb_device *udev;
int len;
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf); 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", 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,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol);
} else {
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*\n",
le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct), le16_to_cpu(udev->descriptor.idProduct),
le16_to_cpu(udev->descriptor.bcdDevice), le16_to_cpu(udev->descriptor.bcdDevice),
udev->descriptor.bDeviceClass, udev->descriptor.bDeviceClass,
udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol); 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); static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);

View File

@ -1315,6 +1315,8 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_WACOM_INTUOS2 0x0040 #define USB_DEVICE_ID_WACOM_INTUOS2 0x0040
#define USB_DEVICE_ID_WACOM_VOLITO 0x0060 #define USB_DEVICE_ID_WACOM_VOLITO 0x0060
#define USB_DEVICE_ID_WACOM_PTU 0x0003 #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_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 #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_VENDOR_ID_DELORME 0x1163
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
#define USB_VENDOR_ID_MCC 0x09db #define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #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_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_KEYBOARD 0x5303 #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. * 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_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, 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_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_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_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_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 + 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 + 400, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, 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_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, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, 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_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_VOLITO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, 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_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },

View File

@ -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.

View File

@ -2765,7 +2765,7 @@ static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf)
} }
/* expect bcdVersion 1.0, ignore */ /* expect bcdVersion 1.0, ignore */
if (memcmp(&desc->bGUID, blan_guid, 16) 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! */ /* hey, this one might _really_ be MDLM! */
dev_dbg (&intf->dev, "MDLM guid\n"); dev_dbg (&intf->dev, "MDLM guid\n");
goto bad_desc; goto bad_desc;

View File

@ -455,6 +455,17 @@ config USB_SERIAL_XIRCOM
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called keyspan_pda. 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 config USB_SERIAL_OMNINET
tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL depends on USB_SERIAL && EXPERIMENTAL

View File

@ -32,6 +32,7 @@ obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.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_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o

View File

@ -7,6 +7,14 @@
* modify it under the terms of the GNU General Public License version * modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation. * 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> #include <linux/config.h>
@ -24,7 +32,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.03" #define DRIVER_VERSION "v0.04"
#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" #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_close(struct usb_serial_port*, struct file*);
static void cp2101_get_termios(struct usb_serial_port*); static void cp2101_get_termios(struct usb_serial_port*);
static void cp2101_set_termios(struct usb_serial_port*, struct termios*); 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 void cp2101_break_ctl(struct usb_serial_port*, int);
static int cp2101_startup (struct usb_serial *); static int cp2101_startup (struct usb_serial *);
static void cp2101_shutdown(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 int debug;
static struct usb_device_id id_table [] = { static struct usb_device_id id_table [] = {
{USB_DEVICE(0x10c4, 0xea60) }, /*Silicon labs factory default*/ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{USB_DEVICE(0x10ab, 0x10c5) }, /*Siemens MC60 Cable*/ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
{ } /* Terminating Entry*/ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ } /* Terminating Entry */
}; };
MODULE_DEVICE_TABLE (usb, id_table); MODULE_DEVICE_TABLE (usb, id_table);
@ -70,32 +82,35 @@ static struct usb_serial_device_type cp2101_device = {
.close = cp2101_close, .close = cp2101_close,
.break_ctl = cp2101_break_ctl, .break_ctl = cp2101_break_ctl,
.set_termios = cp2101_set_termios, .set_termios = cp2101_set_termios,
.tiocmget = cp2101_tiocmget,
.tiocmset = cp2101_tiocmset,
.attach = cp2101_startup, .attach = cp2101_startup,
.shutdown = cp2101_shutdown, .shutdown = cp2101_shutdown,
}; };
/*Config request types*/ /* Config request types */
#define REQTYPE_HOST_TO_DEVICE 0x41 #define REQTYPE_HOST_TO_DEVICE 0x41
#define REQTYPE_DEVICE_TO_HOST 0xc1 #define REQTYPE_DEVICE_TO_HOST 0xc1
/*Config SET requests. To GET, add 1 to the request number*/ /* Config SET requests. To GET, add 1 to the request number */
#define CP2101_UART 0x00 /*Enable / Disable*/ #define CP2101_UART 0x00 /* Enable / Disable */
#define CP2101_BAUDRATE 0x01 /*(BAUD_RATE_GEN_FREQ / baudrate)*/ #define CP2101_BAUDRATE 0x01 /* (BAUD_RATE_GEN_FREQ / baudrate) */
#define CP2101_BITS 0x03 /*0x(0)(data bits)(parity)(stop bits)*/ #define CP2101_BITS 0x03 /* 0x(0)(databits)(parity)(stopbits) */
#define CP2101_BREAK 0x05 /*On / Off*/ #define CP2101_BREAK 0x05 /* On / Off */
#define CP2101_DTRRTS 0x07 /*101 / 202 ???*/ #define CP2101_CONTROL 0x07 /* Flow control line states */
#define CP2101_CONFIG_16 0x13 /*16 bytes of config data ???*/ #define CP2101_MODEMCTL 0x13 /* Modem controls */
#define CP2101_CONFIG_6 0x19 /*6 bytes of config data ???*/ #define CP2101_CONFIG_6 0x19 /* 6 bytes of config data ??? */
/*CP2101_UART*/ /* CP2101_UART */
#define UART_ENABLE 0x0001 #define UART_ENABLE 0x0001
#define UART_DISABLE 0x0000 #define UART_DISABLE 0x0000
/*CP2101_BAUDRATE*/ /* CP2101_BAUDRATE */
#define BAUD_RATE_GEN_FREQ 0x384000 #define BAUD_RATE_GEN_FREQ 0x384000
/*CP2101_BITS*/ /* CP2101_BITS */
#define BITS_DATA_MASK 0X0f00 #define BITS_DATA_MASK 0X0f00
#define BITS_DATA_5 0X0500
#define BITS_DATA_6 0X0600 #define BITS_DATA_6 0X0600
#define BITS_DATA_7 0X0700 #define BITS_DATA_7 0X0700
#define BITS_DATA_8 0X0800 #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 0x0000
#define BITS_STOP_1_5 0x0001 #define BITS_STOP_1_5 0x0001
#define BITS_STOP_2 0x0002 #define BITS_STOP_2 0x0002
/* CP2101_BREAK */
#define BREAK_ON 0x0000 #define BREAK_ON 0x0000
#define BREAK_OFF 0x0001 #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; struct usb_serial *serial = port->serial;
unsigned char buf[4]; u32 *buf;
unsigned int value; int result, i, length;
int result, i;
/*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++; 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), result = usb_control_msg (serial->dev,usb_rcvctrlpipe (serial->dev, 0),
request, REQTYPE_DEVICE_TO_HOST, 0x0000, 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, " dev_err(&port->dev, "%s - Unable to send config request, "
"request=0x%x result=%d\n", "request=0x%x size=%d result=%d\n",
__FUNCTION__, request, result); __FUNCTION__, request, size, result);
return 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; 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) static int cp2101_open (struct usb_serial_port *port, struct file *filp)
{ {
struct usb_serial *serial = port->serial; 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); 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", dev_err(&port->dev, "%s - Unable to enable UART\n",
__FUNCTION__); __FUNCTION__);
return -EPROTO; return -EPROTO;
@ -198,9 +286,12 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
return result; return result;
} }
/*Configure the termios structure*/ /* Configure the termios structure */
cp2101_get_termios(port); cp2101_get_termios(port);
/* Set the DTR and RTS pins low */
cp2101_tiocmset(port, NULL, TIOCM_DTR | TIOCM_RTS, 0);
return 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->write_urb);
usb_kill_urb(port->read_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*/ * cp2101_get_termios
/* Corrects any unsupported values*/ * Reads the baud rate, data bits, parity, stop bits and flow control mode
/* Configures the termios structure to reflect the state of the device*/ * 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) static void cp2101_get_termios (struct usb_serial_port *port)
{ {
unsigned int cflag; unsigned int cflag, modem_ctl[4];
int baud; int baud;
int bits; int bits;
@ -249,15 +342,16 @@ static void cp2101_get_termios (struct usb_serial_port *port)
} }
cflag = port->tty->termios->c_cflag; cflag = port->tty->termios->c_cflag;
baud = cp2101_get_config(port, CP2101_BAUDRATE); cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
/*Convert to baudrate*/ /* Convert to baudrate */
if (baud) if (baud)
baud = BAUD_RATE_GEN_FREQ / baud; baud = BAUD_RATE_GEN_FREQ / baud;
dbg("%s - baud rate = %d", __FUNCTION__, baud); dbg("%s - baud rate = %d", __FUNCTION__, baud);
cflag &= ~CBAUD; cflag &= ~CBAUD;
switch (baud) { 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 * appear to be supported by the device
* but are non-standard * 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, " dbg("%s - Baud rate is not supported, "
"using 9600 baud", __FUNCTION__); "using 9600 baud", __FUNCTION__);
cflag |= B9600; cflag |= B9600;
cp2101_set_config(port, CP2101_BAUDRATE, cp2101_set_config_single(port, CP2101_BAUDRATE,
(BAUD_RATE_GEN_FREQ/9600)); (BAUD_RATE_GEN_FREQ/9600));
break; break;
} }
bits = cp2101_get_config(port, CP2101_BITS); cp2101_get_config(port, CP2101_BITS, &bits, 2);
cflag &= ~CSIZE; cflag &= ~CSIZE;
switch(bits & BITS_DATA_MASK) { switch(bits & BITS_DATA_MASK) {
case BITS_DATA_5:
dbg("%s - data bits = 5", __FUNCTION__);
cflag |= CS5;
break;
case BITS_DATA_6: case BITS_DATA_6:
dbg("%s - data bits = 6", __FUNCTION__); dbg("%s - data bits = 6", __FUNCTION__);
cflag |= CS6; cflag |= CS6;
@ -310,7 +408,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
cflag |= CS8; cflag |= CS8;
bits &= ~BITS_DATA_MASK; bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8; bits |= BITS_DATA_8;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
default: default:
dbg("%s - Unknown number of data bits, " dbg("%s - Unknown number of data bits, "
@ -318,7 +416,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
cflag |= CS8; cflag |= CS8;
bits &= ~BITS_DATA_MASK; bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8; bits |= BITS_DATA_8;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
} }
@ -341,21 +439,21 @@ static void cp2101_get_termios (struct usb_serial_port *port)
"disabling parity)", __FUNCTION__); "disabling parity)", __FUNCTION__);
cflag &= ~PARENB; cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK; bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
case BITS_PARITY_SPACE: case BITS_PARITY_SPACE:
dbg("%s - parity = SPACE (not supported, " dbg("%s - parity = SPACE (not supported, "
"disabling parity)", __FUNCTION__); "disabling parity)", __FUNCTION__);
cflag &= ~PARENB; cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK; bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
default: default:
dbg("%s - Unknown parity mode, " dbg("%s - Unknown parity mode, "
"disabling parity", __FUNCTION__); "disabling parity", __FUNCTION__);
cflag &= ~PARENB; cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK; bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
} }
@ -366,9 +464,9 @@ static void cp2101_get_termios (struct usb_serial_port *port)
break; break;
case BITS_STOP_1_5: case BITS_STOP_1_5:
dbg("%s - stop bits = 1.5 (not supported, " dbg("%s - stop bits = 1.5 (not supported, "
"using 1 stop bit", __FUNCTION__); "using 1 stop bit)", __FUNCTION__);
bits &= ~BITS_STOP_MASK; bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; break;
case BITS_STOP_2: case BITS_STOP_2:
dbg("%s - stop bits = 2", __FUNCTION__); 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, " dbg("%s - Unknown number of stop bits, "
"using 1 stop bit", __FUNCTION__); "using 1 stop bit", __FUNCTION__);
bits &= ~BITS_STOP_MASK; bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, bits); cp2101_set_config(port, CP2101_BITS, &bits, 2);
break; 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; port->tty->termios->c_cflag = cflag;
} }
@ -389,8 +496,8 @@ static void cp2101_set_termios (struct usb_serial_port *port,
struct termios *old_termios) struct termios *old_termios)
{ {
unsigned int cflag, old_cflag=0; unsigned int cflag, old_cflag=0;
int baud=0; int baud=0, bits;
int bits; unsigned int modem_ctl[4];
dbg("%s - port %d", __FUNCTION__, port->number); 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; 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 (old_termios) {
if ((cflag == old_termios->c_cflag) && if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) (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 the baud rate is to be updated*/
if ((cflag & CBAUD) != (old_cflag & CBAUD)) { if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
switch (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 * appear to be supported by the device
* but are non-standard * but are non-standard
*/ */
@ -448,18 +556,22 @@ static void cp2101_set_termios (struct usb_serial_port *port,
if (baud) { if (baud) {
dbg("%s - Setting baud rate to %d baud", __FUNCTION__, dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
baud); baud);
if (cp2101_set_config(port, CP2101_BAUDRATE, if (cp2101_set_config_single(port, CP2101_BAUDRATE,
(BAUD_RATE_GEN_FREQ / baud))) (BAUD_RATE_GEN_FREQ / baud)))
dev_err(&port->dev, "Baud rate requested not " dev_err(&port->dev, "Baud rate requested not "
"supported by device\n"); "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)) { 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; bits &= ~BITS_DATA_MASK;
switch (cflag & CSIZE) { switch (cflag & CSIZE) {
case CS5:
bits |= BITS_DATA_5;
dbg("%s - data bits = 5", __FUNCTION__);
break;
case CS6: case CS6:
bits |= BITS_DATA_6; bits |= BITS_DATA_6;
dbg("%s - data bits = 6", __FUNCTION__); dbg("%s - data bits = 6", __FUNCTION__);
@ -483,13 +595,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
bits |= BITS_DATA_8; bits |= BITS_DATA_8;
break; 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 " dev_err(&port->dev, "Number of data bits requested "
"not supported by device\n"); "not supported by device\n");
} }
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { 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; bits &= ~BITS_PARITY_MASK;
if (cflag & PARENB) { if (cflag & PARENB) {
if (cflag & PARODD) { if (cflag & PARODD) {
@ -500,13 +612,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
dbg("%s - parity = EVEN", __FUNCTION__); 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 " dev_err(&port->dev, "Parity mode not supported "
"by device\n"); "by device\n");
} }
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { 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; bits &= ~BITS_STOP_MASK;
if (cflag & CSTOPB) { if (cflag & CSTOPB) {
bits |= BITS_STOP_2; bits |= BITS_STOP_2;
@ -515,15 +627,90 @@ static void cp2101_set_termios (struct usb_serial_port *port,
bits |= BITS_STOP_1; bits |= BITS_STOP_1;
dbg("%s - stop bits = 1", __FUNCTION__); 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 " dev_err(&port->dev, "Number of stop bits requested "
"not supported by device\n"); "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) static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
{ {
u16 state; int state;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (break_state == 0) if (break_state == 0)
@ -532,12 +719,12 @@ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
state = BREAK_ON; state = BREAK_ON;
dbg("%s - turning break %s", __FUNCTION__, dbg("%s - turning break %s", __FUNCTION__,
state==BREAK_OFF ? "off" : "on"); 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) 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); usb_reset_device(serial->dev);
return 0; return 0;
} }
@ -548,7 +735,7 @@ static void cp2101_shutdown (struct usb_serial *serial)
dbg("%s", __FUNCTION__); 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) { for (i=0; i < serial->num_ports; ++i) {
cp2101_cleanup(serial->port[i]); cp2101_cleanup(serial->port[i]);
} }
@ -560,16 +747,16 @@ static int __init cp2101_init (void)
retval = usb_serial_register(&cp2101_device); retval = usb_serial_register(&cp2101_device);
if (retval) if (retval)
return retval; /*Failed to register*/ return retval; /* Failed to register */
retval = usb_register(&cp2101_driver); retval = usb_register(&cp2101_driver);
if (retval) { if (retval) {
/*Failed to register*/ /* Failed to register */
usb_serial_deregister(&cp2101_device); usb_serial_deregister(&cp2101_device);
return retval; return retval;
} }
/*Success*/ /* Success */
info(DRIVER_DESC " " DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION);
return 0; return 0;
} }

729
drivers/usb/serial/option.c Normal file
View File

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

View File

@ -862,6 +862,15 @@ UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_BULK, NULL, US_SC_DEVICE, US_PR_BULK, NULL,
US_FL_NEED_OVERRIDE ), 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) */ /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
"Trumpion", "Trumpion",

View File

@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm,
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
down_write(&current->mm->mmap_sem); down_write(&current->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(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos) if (!textpos)
@ -532,7 +532,7 @@ static int load_flat_file(struct linux_binprm * bprm,
down_write(&current->mm->mmap_sem); down_write(&current->mm->mmap_sem);
realdatastart = do_mmap(0, 0, data_len + extra + realdatastart = do_mmap(0, 0, data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long), 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(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm * bprm,
down_write(&current->mm->mmap_sem); down_write(&current->mm->mmap_sem);
textpos = do_mmap(0, 0, text_len + data_len + extra + textpos = do_mmap(0, 0, text_len + data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long), 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(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos) if (!textpos)

View File

@ -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) if (--bvec >= bio->bi_io_vec)
prefetchw(&bvec->bv_page->flags); prefetchw(&bvec->bv_page->flags);
if (!uptodate) if (!uptodate){
SetPageError(page); SetPageError(page);
if (page->mapping)
set_bit(AS_EIO, &page->mapping->flags);
}
end_page_writeback(page); end_page_writeback(page);
} while (bvec >= bio->bi_io_vec); } while (bvec >= bio->bi_io_vec);
bio_put(bio); bio_put(bio);

View File

@ -493,12 +493,21 @@ static inline int __vfs_follow_link(struct nameidata *nd, const char *link)
return PTR_ERR(link); 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; int error;
struct dentry *dentry = path->dentry;
touch_atime(nd->mnt, dentry); touch_atime(path->mnt, dentry);
nd_set_link(nd, NULL); nd_set_link(nd, NULL);
if (path->mnt == nd->mnt)
mntget(path->mnt);
error = dentry->d_inode->i_op->follow_link(dentry, nd); error = dentry->d_inode->i_op->follow_link(dentry, nd);
if (!error) { if (!error) {
char *s = nd_get_link(nd); 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) if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd); dentry->d_inode->i_op->put_link(dentry, nd);
} }
dput(dentry);
mntput(path->mnt);
return error; 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 * Without that kind of total limit, nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups. * 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; int err = -ELOOP;
if (current->link_count >= MAX_NESTED_LINKS) 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; goto loop;
BUG_ON(nd->depth >= MAX_NESTED_LINKS); BUG_ON(nd->depth >= MAX_NESTED_LINKS);
cond_resched(); cond_resched();
err = security_inode_follow_link(dentry, nd); err = security_inode_follow_link(path->dentry, nd);
if (err) if (err)
goto loop; goto loop;
current->link_count++; current->link_count++;
current->total_link_count++; current->total_link_count++;
nd->depth++; nd->depth++;
err = __do_follow_link(dentry, nd); err = __do_follow_link(path, nd);
current->link_count--; current->link_count--;
nd->depth--; nd->depth--;
return err; return err;
loop: loop:
dput(path->dentry);
if (path->mnt != nd->mnt)
mntput(path->mnt);
path_release(nd); path_release(nd);
return err; 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 /* no need for dcache_lock, as serialization is taken care in
* namespace.c * namespace.c
*/ */
static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) static int __follow_mount(struct path *path)
{ {
int res = 0; int res = 0;
while (d_mountpoint(*dentry)) { while (d_mountpoint(path->dentry)) {
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
if (!mounted) if (!mounted)
break; break;
mntput(*mnt); dput(path->dentry);
*mnt = mounted; if (res)
dput(*dentry); mntput(path->mnt);
*dentry = dget(mounted->mnt_root); path->mnt = mounted;
path->dentry = dget(mounted->mnt_root);
res = 1; res = 1;
} }
return res; 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 /* no need for dcache_lock, as serialization is taken care in
* namespace.c * 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; struct vfsmount *mounted;
mounted = lookup_mnt(*mnt, *dentry); mounted = lookup_mnt(*mnt, *dentry);
if (mounted) { if (mounted) {
dput(*dentry);
mntput(*mnt); mntput(*mnt);
*mnt = mounted; *mnt = mounted;
dput(*dentry);
*dentry = dget(mounted->mnt_root); *dentry = dget(mounted->mnt_root);
return 1; return 1;
} }
return 0; return 0;
} }
int follow_down(struct vfsmount **mnt, struct dentry **dentry) static inline void follow_dotdot(struct nameidata *nd)
{
return __follow_down(mnt,dentry);
}
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
{ {
while(1) { while(1) {
struct vfsmount *parent; struct vfsmount *parent;
struct dentry *old = *dentry; struct dentry *old = nd->dentry;
read_lock(&current->fs->lock); read_lock(&current->fs->lock);
if (*dentry == current->fs->root && if (nd->dentry == current->fs->root &&
*mnt == current->fs->rootmnt) { nd->mnt == current->fs->rootmnt) {
read_unlock(&current->fs->lock); read_unlock(&current->fs->lock);
break; break;
} }
read_unlock(&current->fs->lock); read_unlock(&current->fs->lock);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
if (*dentry != (*mnt)->mnt_root) { if (nd->dentry != nd->mnt->mnt_root) {
*dentry = dget((*dentry)->d_parent); nd->dentry = dget(nd->dentry->d_parent);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
dput(old); dput(old);
break; break;
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
parent = (*mnt)->mnt_parent; parent = nd->mnt->mnt_parent;
if (parent == *mnt) { if (parent == nd->mnt) {
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
break; break;
} }
mntget(parent); mntget(parent);
*dentry = dget((*mnt)->mnt_mountpoint); nd->dentry = dget(nd->mnt->mnt_mountpoint);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
dput(old); dput(old);
mntput(*mnt); mntput(nd->mnt);
*mnt = parent; 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 * 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. * 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: done:
path->mnt = mnt; path->mnt = mnt;
path->dentry = dentry; path->dentry = dentry;
__follow_mount(path);
return 0; return 0;
need_lookup: need_lookup:
@ -751,7 +770,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
case 2: case 2:
if (this.name[1] != '.') if (this.name[1] != '.')
break; break;
follow_dotdot(&nd->mnt, &nd->dentry); follow_dotdot(nd);
inode = nd->dentry->d_inode; inode = nd->dentry->d_inode;
/* fallthrough */ /* fallthrough */
case 1: case 1:
@ -771,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
err = do_lookup(nd, &this, &next); err = do_lookup(nd, &this, &next);
if (err) if (err)
break; break;
/* Check mountpoints.. */
follow_mount(&next.mnt, &next.dentry);
err = -ENOENT; err = -ENOENT;
inode = next.dentry->d_inode; inode = next.dentry->d_inode;
@ -783,10 +800,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
goto out_dput; goto out_dput;
if (inode->i_op->follow_link) { if (inode->i_op->follow_link) {
mntget(next.mnt); err = do_follow_link(&next, nd);
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
if (err) if (err)
goto return_err; goto return_err;
err = -ENOENT; err = -ENOENT;
@ -798,6 +812,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
break; break;
} else { } else {
dput(nd->dentry); dput(nd->dentry);
if (nd->mnt != next.mnt)
mntput(nd->mnt);
nd->mnt = next.mnt; nd->mnt = next.mnt;
nd->dentry = next.dentry; nd->dentry = next.dentry;
} }
@ -819,7 +835,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
case 2: case 2:
if (this.name[1] != '.') if (this.name[1] != '.')
break; break;
follow_dotdot(&nd->mnt, &nd->dentry); follow_dotdot(nd);
inode = nd->dentry->d_inode; inode = nd->dentry->d_inode;
/* fallthrough */ /* fallthrough */
case 1: case 1:
@ -833,19 +849,17 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
err = do_lookup(nd, &this, &next); err = do_lookup(nd, &this, &next);
if (err) if (err)
break; break;
follow_mount(&next.mnt, &next.dentry);
inode = next.dentry->d_inode; inode = next.dentry->d_inode;
if ((lookup_flags & LOOKUP_FOLLOW) if ((lookup_flags & LOOKUP_FOLLOW)
&& inode && inode->i_op && inode->i_op->follow_link) { && inode && inode->i_op && inode->i_op->follow_link) {
mntget(next.mnt); err = do_follow_link(&next, nd);
err = do_follow_link(next.dentry, nd);
dput(next.dentry);
mntput(next.mnt);
if (err) if (err)
goto return_err; goto return_err;
inode = nd->dentry->d_inode; inode = nd->dentry->d_inode;
} else { } else {
dput(nd->dentry); dput(nd->dentry);
if (nd->mnt != next.mnt)
mntput(nd->mnt);
nd->mnt = next.mnt; nd->mnt = next.mnt;
nd->dentry = next.dentry; nd->dentry = next.dentry;
} }
@ -885,6 +899,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
return 0; return 0;
out_dput: out_dput:
dput(next.dentry); dput(next.dentry);
if (nd->mnt != next.mnt)
mntput(next.mnt);
break; break;
} }
path_release(nd); 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 open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
{ {
int acc_mode, error = 0; int acc_mode, error = 0;
struct dentry *dentry; struct path path;
struct dentry *dir; struct dentry *dir;
int count = 0; int count = 0;
@ -1442,23 +1458,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
dir = nd->dentry; dir = nd->dentry;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
down(&dir->d_inode->i_sem); 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: do_last:
error = PTR_ERR(dentry); error = PTR_ERR(path.dentry);
if (IS_ERR(dentry)) { if (IS_ERR(path.dentry)) {
up(&dir->d_inode->i_sem); up(&dir->d_inode->i_sem);
goto exit; goto exit;
} }
/* Negative dentry, just create the file */ /* Negative dentry, just create the file */
if (!dentry->d_inode) { if (!path.dentry->d_inode) {
if (!IS_POSIXACL(dir->d_inode)) if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask; 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); up(&dir->d_inode->i_sem);
dput(nd->dentry); dput(nd->dentry);
nd->dentry = dentry; nd->dentry = path.dentry;
if (error) if (error)
goto exit; goto exit;
/* Don't check for write permission, don't truncate */ /* Don't check for write permission, don't truncate */
@ -1476,22 +1493,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
if (flag & O_EXCL) if (flag & O_EXCL)
goto exit_dput; goto exit_dput;
if (d_mountpoint(dentry)) { if (__follow_mount(&path)) {
error = -ELOOP; error = -ELOOP;
if (flag & O_NOFOLLOW) if (flag & O_NOFOLLOW)
goto exit_dput; goto exit_dput;
while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
} }
error = -ENOENT; error = -ENOENT;
if (!dentry->d_inode) if (!path.dentry->d_inode)
goto exit_dput; 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; goto do_link;
dput(nd->dentry); dput(nd->dentry);
nd->dentry = dentry; nd->dentry = path.dentry;
if (nd->mnt != path.mnt)
mntput(nd->mnt);
nd->mnt = path.mnt;
error = -EISDIR; 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; goto exit;
ok: ok:
error = may_open(nd, acc_mode, flag); error = may_open(nd, acc_mode, flag);
@ -1500,7 +1519,9 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
return 0; return 0;
exit_dput: exit_dput:
dput(dentry); dput(path.dentry);
if (nd->mnt != path.mnt)
mntput(path.mnt);
exit: exit:
path_release(nd); path_release(nd);
return error; return error;
@ -1520,18 +1541,15 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
* are done. Procfs-like symlinks just set LAST_BIND. * are done. Procfs-like symlinks just set LAST_BIND.
*/ */
nd->flags |= LOOKUP_PARENT; nd->flags |= LOOKUP_PARENT;
error = security_inode_follow_link(dentry, nd); error = security_inode_follow_link(path.dentry, nd);
if (error) if (error)
goto exit_dput; goto exit_dput;
error = __do_follow_link(dentry, nd); error = __do_follow_link(&path, nd);
dput(dentry);
if (error) if (error)
return error; return error;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
if (nd->last_type == LAST_BIND) { if (nd->last_type == LAST_BIND)
dentry = nd->dentry;
goto ok; goto ok;
}
error = -EISDIR; error = -EISDIR;
if (nd->last_type != LAST_NORM) if (nd->last_type != LAST_NORM)
goto exit; goto exit;
@ -1546,7 +1564,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
} }
dir = nd->dentry; dir = nd->dentry;
down(&dir->d_inode->i_sem); 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); putname(nd->last.name);
goto do_last; goto do_last;
} }

View File

@ -1,5 +1,5 @@
#ifndef _ASM_KMAP_TYPES_H #ifndef _ASM_H8300_KMAP_TYPES_H
#define _ASM_KMAP_TYPES_H #define _ASM_H8300_KMAP_TYPES_H
enum km_type { enum km_type {
KM_BOUNCE_READ, KM_BOUNCE_READ,
@ -13,6 +13,8 @@ enum km_type {
KM_PTE1, KM_PTE1,
KM_IRQ0, KM_IRQ0,
KM_IRQ1, KM_IRQ1,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_TYPE_NR KM_TYPE_NR
}; };

View File

@ -4,6 +4,7 @@
#define PROT_READ 0x1 /* page can be read */ #define PROT_READ 0x1 /* page can be read */
#define PROT_WRITE 0x2 /* page can be written */ #define PROT_WRITE 0x2 /* page can be written */
#define PROT_EXEC 0x4 /* page can be executed */ #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_NONE 0x0 /* page can not be accessed */
#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ #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 */ #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_EXECUTABLE 0x1000 /* mark it as an executable */
#define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_LOCKED 0x2000 /* pages are locked */
#define MAP_NORESERVE 0x4000 /* don't check for reservations */ #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_ASYNC 1 /* sync memory asynchronously */
#define MS_INVALIDATE 2 /* invalidate the caches */ #define MS_INVALIDATE 2 /* invalidate the caches */

View File

@ -10,7 +10,7 @@
#define _S390_USER_H #define _S390_USER_H
#include <asm/page.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 /* 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 can understand it and provide useful information to the user (under
linux we use the 'trad-core' bfd). There are quite a number of linux we use the 'trad-core' bfd). There are quite a number of

View File

@ -23,7 +23,7 @@ struct shaper
__u32 shapeclock; __u32 shapeclock;
unsigned long recovery; /* Time we can next clock a packet out on unsigned long recovery; /* Time we can next clock a packet out on
an empty queue */ an empty queue */
unsigned long locked; struct semaphore sem;
struct net_device_stats stats; struct net_device_stats stats;
struct net_device *dev; struct net_device *dev;
int (*hard_start_xmit) (struct sk_buff *skb, 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); 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); 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); struct net_device_stats* (*get_stats)(struct net_device *dev);
wait_queue_head_t wait_queue;
struct timer_list timer; struct timer_list timer;
}; };

View File

@ -467,12 +467,34 @@ static inline u8 ata_chk_status(struct ata_port *ap)
return ap->ops->check_status(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) static inline void ata_pause(struct ata_port *ap)
{ {
ata_altstatus(ap); ata_altstatus(ap);
ndelay(400); 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, static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
unsigned int max) unsigned int max)
{ {
@ -487,6 +509,18 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
return status; 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) static inline u8 ata_wait_idle(struct ata_port *ap)
{ {
u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); 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; 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) static inline u8 ata_irq_on(struct ata_port *ap)
{ {
struct ata_ioports *ioaddr = &ap->ioaddr; struct ata_ioports *ioaddr = &ap->ioaddr;
@ -544,6 +590,18 @@ static inline u8 ata_irq_on(struct ata_port *ap)
return tmp; 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) 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; unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;

View File

@ -204,7 +204,7 @@ struct hh_cache
/* cached hardware header; allow for machine alignment needs. */ /* cached hardware header; allow for machine alignment needs. */
#define HH_DATA_MOD 16 #define HH_DATA_MOD 16
#define HH_DATA_OFF(__len) \ #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) \ #define HH_DATA_ALIGN(__len) \
(((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)]; unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];

View File

@ -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 * of the iso_frame_desc array, and the number of errors is reported in
* error_count. Completion callbacks for ISO transfers will normally * error_count. Completion callbacks for ISO transfers will normally
* (re)submit URBs to ensure a constant transfer rate. * (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 struct urb
{ {
@ -803,12 +807,12 @@ struct urb
struct kref kref; /* reference count of the URB */ struct kref kref; /* reference count of the URB */
spinlock_t lock; /* lock for the URB */ spinlock_t lock; /* lock for the URB */
void *hcpriv; /* private data for host controller */ 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 */ int bandwidth; /* bandwidth for INT/ISO request */
atomic_t use_count; /* concurrent submissions counter */ atomic_t use_count; /* concurrent submissions counter */
u8 reject; /* submissions will fail */ u8 reject; /* submissions will fail */
/* public, documented fields in the urb that can be used by drivers */ /* 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 */ struct usb_device *dev; /* (in) pointer to associated device */
unsigned int pipe; /* (in) pipe information */ unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */ int status; /* (return) non-ISO status */

View File

@ -1968,6 +1968,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
do { do {
unsigned long index; unsigned long index;
unsigned long offset; unsigned long offset;
unsigned long maxlen;
size_t copied; size_t copied;
offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ 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 * same page as we're writing to, without it being marked
* up-to-date. * 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); page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
if (!page) { if (!page) {
@ -2024,6 +2028,8 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
filemap_set_next_iovec(&cur_iov, filemap_set_next_iovec(&cur_iov,
&iov_base, status); &iov_base, status);
buf = cur_iov->iov_base + iov_base; buf = cur_iov->iov_base + iov_base;
} else {
iov_base += status;
} }
} }
} }

View File

@ -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-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_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) $(ip_vs_proto-objs-y)

View File

@ -216,9 +216,6 @@ int ip_vs_protocol_init(void)
#ifdef CONFIG_IP_VS_PROTO_UDP #ifdef CONFIG_IP_VS_PROTO_UDP
REGISTER_PROTOCOL(&ip_vs_protocol_udp); REGISTER_PROTOCOL(&ip_vs_protocol_udp);
#endif #endif
#ifdef CONFIG_IP_VS_PROTO_ICMP
REGISTER_PROTOCOL(&ip_vs_protocol_icmp);
#endif
#ifdef CONFIG_IP_VS_PROTO_AH #ifdef CONFIG_IP_VS_PROTO_AH
REGISTER_PROTOCOL(&ip_vs_protocol_ah); REGISTER_PROTOCOL(&ip_vs_protocol_ah);
#endif #endif

View File

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

View File

@ -37,5 +37,4 @@ EXPORT_SYMBOL(in6_dev_finish_destroy);
EXPORT_SYMBOL(xfrm6_rcv); EXPORT_SYMBOL(xfrm6_rcv);
#endif #endif
EXPORT_SYMBOL(rt6_lookup); EXPORT_SYMBOL(rt6_lookup);
EXPORT_SYMBOL(fl6_sock_lookup);
EXPORT_SYMBOL(ipv6_push_nfrag_opts); EXPORT_SYMBOL(ipv6_push_nfrag_opts);