]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorSteve French <sfrench@hera.kernel.org>
Mon, 6 Jun 2005 16:57:33 +0000 (09:57 -0700)
committerSteve French <sfrench@hera.kernel.org>
Mon, 6 Jun 2005 16:57:33 +0000 (09:57 -0700)
56 files changed:
Documentation/DocBook/libata.tmpl
Makefile
arch/m68knommu/kernel/process.c
arch/ppc64/kernel/entry.S
arch/ppc64/kernel/head.S
arch/ppc64/kernel/iSeries_setup.c
arch/ppc64/kernel/idle.c
arch/ppc64/kernel/process.c
arch/ppc64/kernel/prom_init.c
arch/ppc64/kernel/setup.c
arch/ppc64/kernel/smp.c
arch/ppc64/kernel/sysfs.c
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/appldata/appldata_os.c
arch/s390/kernel/ptrace.c
arch/s390/mm/fault.c
drivers/atm/Makefile
drivers/atm/fore200e.c
drivers/atm/he.c
drivers/atm/nicstar.c
drivers/atm/zatm.c
drivers/block/ub.c
drivers/net/hamradio/baycom_epp.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/r8169.c
drivers/net/shaper.c
drivers/scsi/ata_piix.c
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_scan.c
drivers/serial/vr41xx_siu.c
drivers/usb/core/sysfs.c
drivers/usb/input/hid-core.c
drivers/usb/media/pwc/ChangeLog [deleted file]
drivers/usb/net/usbnet.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/cp2101.c
drivers/usb/serial/option.c [new file with mode: 0644]
drivers/usb/storage/unusual_devs.h
fs/jbd/checkpoint.c
fs/mpage.c
include/asm-ppc64/processor.h
include/asm-ppc64/thread_info.h
include/asm-s390/user.h
include/linux/if_shaper.h
include/linux/libata.h
include/linux/netdevice.h
include/linux/usb.h
net/ipv4/ipvs/Makefile
net/ipv4/ipvs/ip_vs_proto.c
net/ipv4/ipvs/ip_vs_proto_icmp.c [deleted file]
net/ipv6/ipv6_syms.c

index cf2fce7707da202e7f408f40929dde7255cf742e..6df1dfd18b651fce1224fe0e127cf7e777981d34 100644 (file)
@@ -14,7 +14,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2003</year>
+   <year>2003-2005</year>
    <holder>Jeff Garzik</holder>
   </copyright>
 
 
 <toc></toc>
 
-  <chapter id="libataThanks">
-     <title>Thanks</title>
+  <chapter id="libataIntroduction">
+     <title>Introduction</title>
   <para>
-  The bulk of the ATA knowledge comes thanks to long conversations with
-  Andre Hedrick (www.linux-ide.org).
+  libATA is a library used inside the Linux kernel to support ATA host
+  controllers and devices.  libATA provides an ATA driver API, class
+  transports for ATA and ATAPI devices, and SCSI&lt;-&gt;ATA translation
+  for ATA devices according to the T10 SAT specification.
   </para>
   <para>
-  Thanks to Alan Cox for pointing out similarities 
-  between SATA and SCSI, and in general for motivation to hack on
-  libata.
-  </para>
-  <para>
-  libata's device detection
-  method, ata_pio_devchk, and in general all the early probing was
-  based on extensive study of Hale Landis's probe/reset code in his
-  ATADRVR driver (www.ata-atapi.com).
+  This Guide documents the libATA driver API, library functions, library
+  internals, and a couple sample ATA low-level drivers.
   </para>
   </chapter>
 
   <chapter id="libataDriverApi">
      <title>libata Driver API</title>
+     <para>
+     struct ata_port_operations is defined for every low-level libata
+     hardware driver, and it controls how the low-level driver
+     interfaces with the ATA and SCSI layers.
+     </para>
+     <para>
+     FIS-based drivers will hook into the system with ->qc_prep() and
+     ->qc_issue() high-level hooks.  Hardware which behaves in a manner
+     similar to PCI IDE hardware may utilize several generic helpers,
+     defining at a bare minimum the bus I/O addresses of the ATA shadow
+     register blocks.
+     </para>
      <sect1>
         <title>struct ata_port_operations</title>
 
+       <sect2><title>Disable ATA port</title>
        <programlisting>
 void (*port_disable) (struct ata_port *);
        </programlisting>
@@ -78,6 +86,9 @@ void (*port_disable) (struct ata_port *);
        unplug).
        </para>
 
+       </sect2>
+
+       <sect2><title>Post-IDENTIFY device configuration</title>
        <programlisting>
 void (*dev_config) (struct ata_port *, struct ata_device *);
        </programlisting>
@@ -88,6 +99,9 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
        issue of SET FEATURES - XFER MODE, and prior to operation.
        </para>
 
+       </sect2>
+
+       <sect2><title>Set PIO/DMA mode</title>
        <programlisting>
 void (*set_piomode) (struct ata_port *, struct ata_device *);
 void (*set_dmamode) (struct ata_port *, struct ata_device *);
@@ -108,6 +122,9 @@ void (*post_set_mode) (struct ata_port *ap);
        ->set_dma_mode() is only called if DMA is possible.
        </para>
 
+       </sect2>
+
+       <sect2><title>Taskfile read/write</title>
        <programlisting>
 void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
 void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -120,6 +137,9 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
        taskfile register values.
        </para>
 
+       </sect2>
+
+       <sect2><title>ATA command execute</title>
        <programlisting>
 void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
        </programlisting>
@@ -129,17 +149,37 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
        ->tf_load(), to be initiated in hardware.
        </para>
 
+       </sect2>
+
+       <sect2><title>Per-cmd ATAPI DMA capabilities filter</title>
+       <programlisting>
+int (*check_atapi_dma) (struct ata_queued_cmd *qc);
+       </programlisting>
+
+       <para>
+Allow low-level driver to filter ATA PACKET commands, returning a status
+indicating whether or not it is OK to use DMA for the supplied PACKET
+command.
+       </para>
+
+       </sect2>
+
+       <sect2><title>Read specific ATA shadow registers</title>
        <programlisting>
 u8   (*check_status)(struct ata_port *ap);
-void (*dev_select)(struct ata_port *ap, unsigned int device);
+u8   (*check_altstatus)(struct ata_port *ap);
+u8   (*check_err)(struct ata_port *ap);
        </programlisting>
 
        <para>
-       Reads the Status ATA shadow register from hardware.  On some
-       hardware, this has the side effect of clearing the interrupt
-       condition.
+       Reads the Status/AltStatus/Error ATA shadow register from
+       hardware.  On some hardware, reading the Status register has
+       the side effect of clearing the interrupt condition.
        </para>
 
+       </sect2>
+
+       <sect2><title>Select ATA device on bus</title>
        <programlisting>
 void (*dev_select)(struct ata_port *ap, unsigned int device);
        </programlisting>
@@ -147,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
        <para>
        Issues the low-level hardware command(s) that causes one of N
        hardware devices to be considered 'selected' (active and
-       available for use) on the ATA bus.
+       available for use) on the ATA bus.  This generally has no
+meaning on FIS-based devices.
        </para>
 
+       </sect2>
+
+       <sect2><title>Reset ATA bus</title>
        <programlisting>
 void (*phy_reset) (struct ata_port *ap);
        </programlisting>
@@ -162,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap);
        functions ata_bus_reset() or sata_phy_reset() for this hook.
        </para>
 
+       </sect2>
+
+       <sect2><title>Control PCI IDE BMDMA engine</title>
        <programlisting>
 void (*bmdma_setup) (struct ata_queued_cmd *qc);
 void (*bmdma_start) (struct ata_queued_cmd *qc);
+void (*bmdma_stop) (struct ata_port *ap);
+u8   (*bmdma_status) (struct ata_port *ap);
        </programlisting>
 
        <para>
-       When setting up an IDE BMDMA transaction, these hooks arm
-       (->bmdma_setup) and fire (->bmdma_start) the hardware's DMA
-       engine.
+When setting up an IDE BMDMA transaction, these hooks arm
+(->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop)
+the hardware's DMA engine.  ->bmdma_status is used to read the standard
+PCI IDE DMA Status register.
        </para>
 
+       <para>
+These hooks are typically either no-ops, or simply not implemented, in
+FIS-based drivers.
+       </para>
+
+       </sect2>
+
+       <sect2><title>High-level taskfile hooks</title>
        <programlisting>
 void (*qc_prep) (struct ata_queued_cmd *qc);
 int (*qc_issue) (struct ata_queued_cmd *qc);
@@ -190,20 +248,26 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
        ->qc_issue is used to make a command active, once the hardware
        and S/G tables have been prepared.  IDE BMDMA drivers use the
        helper function ata_qc_issue_prot() for taskfile protocol-based
-       dispatch.  More advanced drivers roll their own ->qc_issue
-       implementation, using this as the "issue new ATA command to
-       hardware" hook.
+       dispatch.  More advanced drivers implement their own ->qc_issue.
        </para>
 
+       </sect2>
+
+       <sect2><title>Timeout (error) handling</title>
        <programlisting>
 void (*eng_timeout) (struct ata_port *ap);
        </programlisting>
 
        <para>
-       This is a high level error handling function, called from the
-       error handling thread, when a command times out.
+This is a high level error handling function, called from the
+error handling thread, when a command times out.  Most newer
+hardware will implement its own error handling code here.  IDE BMDMA
+drivers may use the helper function ata_eng_timeout().
        </para>
 
+       </sect2>
+
+       <sect2><title>Hardware interrupt handling</title>
        <programlisting>
 irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
 void (*irq_clear) (struct ata_port *);
@@ -216,6 +280,9 @@ void (*irq_clear) (struct ata_port *);
        is quiet.
        </para>
 
+       </sect2>
+
+       <sect2><title>SATA phy read/write</title>
        <programlisting>
 u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
 void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
@@ -227,6 +294,9 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
        if ->phy_reset hook called the sata_phy_reset() helper function.
        </para>
 
+       </sect2>
+
+       <sect2><title>Init and shutdown</title>
        <programlisting>
 int (*port_start) (struct ata_port *ap);
 void (*port_stop) (struct ata_port *ap);
@@ -240,15 +310,17 @@ void (*host_stop) (struct ata_host_set *host_set);
        tasks.  
        </para>
        <para>
-       ->host_stop() is called when the rmmod or hot unplug process
-       begins.  The hook must stop all hardware interrupts, DMA
-       engines, etc.
-       </para>
-       <para>
        ->port_stop() is called after ->host_stop().  It's sole function
        is to release DMA/memory resources, now that they are no longer
        actively being used.
        </para>
+       <para>
+       ->host_stop() is called after all ->port_stop() calls
+have completed.  The hook must finalize hardware shutdown, release DMA
+and other resources, etc.
+       </para>
+
+       </sect2>
 
      </sect1>
   </chapter>
@@ -279,4 +351,24 @@ void (*host_stop) (struct ata_host_set *host_set);
 !Idrivers/scsi/sata_sil.c
   </chapter>
 
+  <chapter id="libataThanks">
+     <title>Thanks</title>
+  <para>
+  The bulk of the ATA knowledge comes thanks to long conversations with
+  Andre Hedrick (www.linux-ide.org), and long hours pondering the ATA
+  and SCSI specifications.
+  </para>
+  <para>
+  Thanks to Alan Cox for pointing out similarities 
+  between SATA and SCSI, and in general for motivation to hack on
+  libata.
+  </para>
+  <para>
+  libata's device detection
+  method, ata_pio_devchk, and in general all the early probing was
+  based on extensive study of Hale Landis's probe/reset code in his
+  ATADRVR driver (www.ata-atapi.com).
+  </para>
+  </chapter>
+
 </book>
index c11a317ea910df5c8456de992ae8f932a102b12b..9e005e18c71c4b7adc83a200e1ae10782c751920 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 12
-EXTRAVERSION =-rc5
+EXTRAVERSION =-rc6
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
index 2b6c9d32b7a6267754ab11b202317755a825a0b5..c4a33f265dc07e53577350d5366b3a936c8bc665 100644 (file)
@@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void);
  */
 void default_idle(void)
 {
-       while(1) {
-               if (need_resched())
-                       __asm__("stop #0x2000" : : : "cc");
-               schedule();
+       local_irq_disable();
+       while (!need_resched()) {
+               /* This stop will re-enable interrupts */
+               __asm__("stop #0x2000" : : : "cc");
+               local_irq_disable();
        }
+       local_irq_enable();
 }
 
 void (*idle)(void) = default_idle;
@@ -63,7 +65,12 @@ void (*idle)(void) = default_idle;
 void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
-       idle();
+       while (1) {
+               idle();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
 }
 
 void machine_restart(char * __unused)
index d3604056e1a9c53d2407243ecb44aa282609363c..b61572eb2a7130d7a46924f8412024b9879286e7 100644 (file)
@@ -436,15 +436,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        REST_8GPRS(14, r1)
        REST_10GPRS(22, r1)
 
-#ifdef CONFIG_PPC_ISERIES
-       clrrdi  r7,r1,THREAD_SHIFT      /* get current_thread_info() */
-       ld      r7,TI_FLAGS(r7)         /* Get run light flag */
-       mfspr   r9,CTRLF
-       srdi    r7,r7,TIF_RUN_LIGHT
-       insrdi  r9,r7,1,63              /* Insert run light into CTRL */
-       mtspr   CTRLT,r9
-#endif
-
        /* convert old thread to its task_struct for return value */
        addi    r3,r3,-THREAD
        ld      r7,_NIP(r1)     /* Return to _switch caller in new task */
index 92a744c31ab183b2aec6e4532a593cef614bba13..346dbf606b5dd910e1a3609d315d96a1a830fa00 100644 (file)
@@ -626,10 +626,10 @@ system_reset_iSeries:
        lhz     r24,PACAPACAINDEX(r13)  /* Get processor # */
        cmpwi   0,r24,0                 /* Are we processor 0? */
        beq     .__start_initialization_iSeries /* Start up the first processor */
-       mfspr   r4,CTRLF
-       li      r5,RUNLATCH             /* Turn off the run light */
+       mfspr   r4,SPRN_CTRLF
+       li      r5,CTRL_RUNLATCH        /* Turn off the run light */
        andc    r4,r4,r5
-       mtspr   CTRLT,r4
+       mtspr   SPRN_CTRLT,r4
 
 1:
        HMT_LOW
@@ -2082,9 +2082,9 @@ _GLOBAL(hmt_start_secondary)
        mfspr   r4, HID0
        ori     r4, r4, 0x1
        mtspr   HID0, r4
-       mfspr   r4, CTRLF
+       mfspr   r4, SPRN_CTRLF
        oris    r4, r4, 0x40
-       mtspr   CTRLT, r4
+       mtspr   SPRN_CTRLT, r4
        blr
 #endif
 
index da20120f22617515f554e405d9eaa744288aca57..6d06eb550a3fb839077953caab8d6f82d96afe8a 100644 (file)
@@ -852,6 +852,28 @@ static int __init iSeries_src_init(void)
 
 late_initcall(iSeries_src_init);
 
+static int set_spread_lpevents(char *str)
+{
+       unsigned long i;
+       unsigned long val = simple_strtoul(str, NULL, 0);
+
+       /*
+        * The parameter is the number of processors to share in processing
+        * lp events.
+        */
+       if (( val > 0) && (val <= NR_CPUS)) {
+               for (i = 1; i < val; ++i)
+                       paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
+
+               printk("lpevent processing spread over %ld processors\n", val);
+       } else {
+               printk("invalid spread_lpevents %ld\n", val);
+       }
+
+       return 1;
+}
+__setup("spread_lpevents=", set_spread_lpevents);
+
 void __init iSeries_early_setup(void)
 {
        iSeries_fixup_klimit();
index 6abc621d3ba0ca1fd2f52b934d83faaae4d8d81e..f24ce2b872004ae4feb1f419eddb3c0866c1c440 100644 (file)
@@ -75,13 +75,9 @@ static int iSeries_idle(void)
 {
        struct paca_struct *lpaca;
        long oldval;
-       unsigned long CTRL;
 
        /* ensure iSeries run light will be out when idle */
-       clear_thread_flag(TIF_RUN_LIGHT);
-       CTRL = mfspr(CTRLF);
-       CTRL &= ~RUNLATCH;
-       mtspr(CTRLT, CTRL);
+       ppc64_runlatch_off();
 
        lpaca = get_paca();
 
@@ -111,7 +107,9 @@ static int iSeries_idle(void)
                        }
                }
 
+               ppc64_runlatch_on();
                schedule();
+               ppc64_runlatch_off();
        }
 
        return 0;
index 8b06861227385709431ace73498417c448b10e5d..cdfecbeb331f58d586edd4b85aa58212f859d872 100644 (file)
@@ -378,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
                p->thread.regs = NULL;  /* no user register state */
                clear_ti_thread_flag(p->thread_info, TIF_32BIT);
-#ifdef CONFIG_PPC_ISERIES
-               set_ti_thread_flag(p->thread_info, TIF_RUN_LIGHT);
-#endif
        } else {
                childregs->gpr[1] = usp;
                p->thread.regs = childregs;
index 1ac531ba7056783ba5c48c6ca7ba2da350bd39ed..b7683abfbe6a5f71e8031610ef8cb67dd14a07bd 100644 (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 */
        rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
-       if (!PHANDLE_VALID(rtas)) {
+       if (PHANDLE_VALID(rtas)) {
                int x = prom_getproplen(rtas, "ibm,hypertas-functions");
                if (x != PROM_ERROR) {
                        prom_printf("Hypertas detected, assuming LPAR !\n");
index 21c57f539c29305b1bf7ecef8c8a7a5b72a33046..dce198d39328aefd6541efef430f6a6e71d9ca4f 100644 (file)
@@ -103,11 +103,6 @@ extern void unflatten_device_tree(void);
 
 extern void smp_release_cpus(void);
 
-unsigned long decr_overclock = 1;
-unsigned long decr_overclock_proc0 = 1;
-unsigned long decr_overclock_set = 0;
-unsigned long decr_overclock_proc0_set = 0;
-
 int have_of = 1;
 int boot_cpuid = 0;
 int boot_cpuid_phys = 0;
@@ -1120,64 +1115,15 @@ void ppc64_dump_msg(unsigned int src, const char *msg)
        printk("[dump]%04x %s\n", src, msg);
 }
 
-int set_spread_lpevents( char * str )
-{
-       /* The parameter is the number of processors to share in processing lp events */
-       unsigned long i;
-       unsigned long val = simple_strtoul( str, NULL, 0 );
-       if ( ( val > 0 ) && ( val <= NR_CPUS ) ) {
-               for ( i=1; i<val; ++i )
-                       paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
-               printk("lpevent processing spread over %ld processors\n", val);
-       }
-       else
-               printk("invalid spreaqd_lpevents %ld\n", val);
-       return 1;
-}      
-
 /* This should only be called on processor 0 during calibrate decr */
 void setup_default_decr(void)
 {
        struct paca_struct *lpaca = get_paca();
 
-       if ( decr_overclock_set && !decr_overclock_proc0_set )
-               decr_overclock_proc0 = decr_overclock;
-
-       lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;        
+       lpaca->default_decr = tb_ticks_per_jiffy;
        lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
 }
 
-int set_decr_overclock_proc0( char * str )
-{
-       unsigned long val = simple_strtoul( str, NULL, 0 );
-       if ( ( val >= 1 ) && ( val <= 48 ) ) {
-               decr_overclock_proc0_set = 1;
-               decr_overclock_proc0 = val;
-               printk("proc 0 decrementer overclock factor of %ld\n", val);
-       }
-       else
-               printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
-       return 1;
-}
-
-int set_decr_overclock( char * str )
-{
-       unsigned long val = simple_strtoul( str, NULL, 0 );
-       if ( ( val >= 1 ) && ( val <= 48 ) ) {
-               decr_overclock_set = 1;
-               decr_overclock = val;
-               printk("decrementer overclock factor of %ld\n", val);
-       }
-       else
-               printk("invalid decrementer overclock factor of %ld\n", val);
-       return 1;
-
-}
-
-__setup("spread_lpevents=", set_spread_lpevents );
-__setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
-__setup("decr_overclock=", set_decr_overclock );
-
 #ifndef CONFIG_PPC_ISERIES
 /*
  * This function can be used by platforms to "find" legacy serial ports.
index 3b906cd940378086b84d18f2d0b71c70a33308cc..9ef5d36d6b253d38127cc026554e2d0e698f87d5 100644 (file)
@@ -334,7 +334,6 @@ void smp_call_function_interrupt(void)
        }
 }
 
-extern unsigned long decr_overclock;
 extern struct gettimeofday_struct do_gtod;
 
 struct thread_info *current_set[NR_CPUS];
@@ -491,7 +490,7 @@ int __devinit __cpu_up(unsigned int cpu)
        if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
                return -EINVAL;
 
-       paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock;
+       paca[cpu].default_decr = tb_ticks_per_jiffy;
 
        if (!cpu_has_feature(CPU_FTR_SLB)) {
                void *tmp;
index 0925694c3ce5e7873438ae300075a80d648e7657..c8fa6569b2fd789fc3476a3c5ab86c3bf6b3c203 100644 (file)
@@ -113,7 +113,6 @@ void ppc64_enable_pmcs(void)
 #ifdef CONFIG_PPC_PSERIES
        unsigned long set, reset;
        int ret;
-       unsigned int ctrl;
 #endif /* CONFIG_PPC_PSERIES */
 
        /* Only need to enable them once */
@@ -167,11 +166,8 @@ void ppc64_enable_pmcs(void)
         * On SMT machines we have to set the run latch in the ctrl register
         * in order to make PMC6 spin.
         */
-       if (cpu_has_feature(CPU_FTR_SMT)) {
-               ctrl = mfspr(CTRLF);
-               ctrl |= RUNLATCH;
-               mtspr(CTRLT, ctrl);
-       }
+       if (cpu_has_feature(CPU_FTR_SMT))
+               ppc64_runlatch_on();
 #endif /* CONFIG_PPC_PSERIES */
 }
 
index 01ae1964c938cd828379dc594087299309531725..c067435bae4506130b9dd05cbf4e6a30078000a1 100644 (file)
@@ -28,6 +28,7 @@
 //#include <linux/kernel_stat.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
+#include <linux/workqueue.h>
 
 #include "appldata.h"
 
@@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL;
 static int appldata_timer_active;
 
 /*
- * Tasklet
+ * Work queue
  */
-static struct tasklet_struct appldata_tasklet_struct;
+static struct workqueue_struct *appldata_wq;
+static void appldata_work_fn(void *data);
+static DECLARE_WORK(appldata_work, appldata_work_fn, NULL);
+
 
 /*
  * Ops list
@@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock);
 static LIST_HEAD(appldata_ops_list);
 
 
-/************************* timer, tasklet, DIAG ******************************/
+/*************************** timer, work, DIAG *******************************/
 /*
  * appldata_timer_function()
  *
- * schedule tasklet and reschedule timer
+ * schedule work and reschedule timer
  */
 static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
 {
@@ -157,22 +161,22 @@ static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
                atomic_read(&appldata_expire_count));
        if (atomic_dec_and_test(&appldata_expire_count)) {
                atomic_set(&appldata_expire_count, num_online_cpus());
-               tasklet_schedule((struct tasklet_struct *) data);
+               queue_work(appldata_wq, (struct work_struct *) data);
        }
 }
 
 /*
- * appldata_tasklet_function()
+ * appldata_work_fn()
  *
  * call data gathering function for each (active) module
  */
-static void appldata_tasklet_function(unsigned long data)
+static void appldata_work_fn(void *data)
 {
        struct list_head *lh;
        struct appldata_ops *ops;
        int i;
 
-       P_DEBUG("  -= Tasklet =-\n");
+       P_DEBUG("  -= Work Queue =-\n");
        i = 0;
        spin_lock(&appldata_ops_lock);
        list_for_each(lh, &appldata_ops_list) {
@@ -231,7 +235,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
                        : "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
        return (int) ry;
 }
-/********************** timer, tasklet, DIAG <END> ***************************/
+/************************ timer, work, DIAG <END> ****************************/
 
 
 /****************************** /proc stuff **********************************/
@@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
        struct list_head *lh;
 
        found = 0;
-       spin_lock_bh(&appldata_ops_lock);
+       spin_lock(&appldata_ops_lock);
        list_for_each(lh, &appldata_ops_list) {
                tmp_ops = list_entry(lh, struct appldata_ops, list);
                if (&tmp_ops->ctl_table[2] == ctl) {
@@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                }
        }
        if (!found) {
-               spin_unlock_bh(&appldata_ops_lock);
+               spin_unlock(&appldata_ops_lock);
                return -ENODEV;
        }
        ops = ctl->data;
        if (!try_module_get(ops->owner)) {      // protect this function
-               spin_unlock_bh(&appldata_ops_lock);
+               spin_unlock(&appldata_ops_lock);
                return -ENODEV;
        }
-       spin_unlock_bh(&appldata_ops_lock);
+       spin_unlock(&appldata_ops_lock);
 
        if (!*lenp || *ppos) {
                *lenp = 0;
@@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                return -EFAULT;
        }
 
-       spin_lock_bh(&appldata_ops_lock);
+       spin_lock(&appldata_ops_lock);
        if ((buf[0] == '1') && (ops->active == 0)) {
-               if (!try_module_get(ops->owner)) {      // protect tasklet
-                       spin_unlock_bh(&appldata_ops_lock);
+               // protect work queue callback
+               if (!try_module_get(ops->owner)) {
+                       spin_unlock(&appldata_ops_lock);
                        module_put(ops->owner);
                        return -ENODEV;
                }
@@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                }
                module_put(ops->owner);
        }
-       spin_unlock_bh(&appldata_ops_lock);
+       spin_unlock(&appldata_ops_lock);
 out:
        *lenp = len;
        *ppos += len;
@@ -529,7 +534,7 @@ int appldata_register_ops(struct appldata_ops *ops)
        }
        memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
 
-       spin_lock_bh(&appldata_ops_lock);
+       spin_lock(&appldata_ops_lock);
        list_for_each(lh, &appldata_ops_list) {
                tmp_ops = list_entry(lh, struct appldata_ops, list);
                P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
@@ -541,18 +546,18 @@ int appldata_register_ops(struct appldata_ops *ops)
                                APPLDATA_PROC_NAME_LENGTH) == 0) {
                        P_ERROR("Name \"%s\" already registered!\n", ops->name);
                        kfree(ops->ctl_table);
-                       spin_unlock_bh(&appldata_ops_lock);
+                       spin_unlock(&appldata_ops_lock);
                        return -EBUSY;
                }
                if (tmp_ops->ctl_nr == ops->ctl_nr) {
                        P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
                        kfree(ops->ctl_table);
-                       spin_unlock_bh(&appldata_ops_lock);
+                       spin_unlock(&appldata_ops_lock);
                        return -EBUSY;
                }
        }
        list_add(&ops->list, &appldata_ops_list);
-       spin_unlock_bh(&appldata_ops_lock);
+       spin_unlock(&appldata_ops_lock);
 
        ops->ctl_table[0].ctl_name = CTL_APPLDATA;
        ops->ctl_table[0].procname = appldata_proc_name;
@@ -583,12 +588,12 @@ int appldata_register_ops(struct appldata_ops *ops)
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
-       spin_lock_bh(&appldata_ops_lock);
+       spin_lock(&appldata_ops_lock);
        unregister_sysctl_table(ops->sysctl_header);
        list_del(&ops->list);
        kfree(ops->ctl_table);
        ops->ctl_table = NULL;
-       spin_unlock_bh(&appldata_ops_lock);
+       spin_unlock(&appldata_ops_lock);
        P_INFO("%s-ops unregistered!\n", ops->name);
 }
 /********************** module-ops management <END> **************************/
@@ -602,7 +607,7 @@ appldata_online_cpu(int cpu)
        init_virt_timer(&per_cpu(appldata_timer, cpu));
        per_cpu(appldata_timer, cpu).function = appldata_timer_function;
        per_cpu(appldata_timer, cpu).data = (unsigned long)
-               &appldata_tasklet_struct;
+               &appldata_work;
        atomic_inc(&appldata_expire_count);
        spin_lock(&appldata_timer_lock);
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu)
        del_virt_timer(&per_cpu(appldata_timer, cpu));
        if (atomic_dec_and_test(&appldata_expire_count)) {
                atomic_set(&appldata_expire_count, num_online_cpus());
-               tasklet_schedule(&appldata_tasklet_struct);
+               queue_work(appldata_wq, &appldata_work);
        }
        spin_lock(&appldata_timer_lock);
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
@@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = {
 /*
  * appldata_init()
  *
- * init timer and tasklet, register /proc entries
+ * init timer, register /proc entries
  */
 static int __init appldata_init(void)
 {
@@ -657,6 +662,12 @@ static int __init appldata_init(void)
        P_DEBUG("sizeof(parameter_list) = %lu\n",
                sizeof(struct appldata_parameter_list));
 
+       appldata_wq = create_singlethread_workqueue("appldata");
+       if (!appldata_wq) {
+               P_ERROR("Could not create work queue\n");
+               return -ENOMEM;
+       }
+
        for_each_online_cpu(i)
                appldata_online_cpu(i);
 
@@ -670,7 +681,6 @@ static int __init appldata_init(void)
        appldata_table[1].de->owner = THIS_MODULE;
 #endif
 
-       tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
        P_DEBUG("Base interface initialized.\n");
        return 0;
 }
@@ -678,7 +688,7 @@ static int __init appldata_init(void)
 /*
  * appldata_exit()
  *
- * stop timer and tasklet, unregister /proc entries
+ * stop timer, unregister /proc entries
  */
 static void __exit appldata_exit(void)
 {
@@ -690,7 +700,7 @@ static void __exit appldata_exit(void)
        /*
         * ops list should be empty, but just in case something went wrong...
         */
-       spin_lock_bh(&appldata_ops_lock);
+       spin_lock(&appldata_ops_lock);
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
@@ -700,7 +710,7 @@ static void __exit appldata_exit(void)
                                "return code: %d\n", ops->name, rc);
                }
        }
-       spin_unlock_bh(&appldata_ops_lock);
+       spin_unlock(&appldata_ops_lock);
 
        for_each_online_cpu(i)
                appldata_offline_cpu(i);
@@ -709,7 +719,7 @@ static void __exit appldata_exit(void)
 
        unregister_sysctl_table(appldata_sysctl_header);
 
-       tasklet_kill(&appldata_tasklet_struct);
+       destroy_workqueue(appldata_wq);
        P_DEBUG("... module unloaded!\n");
 }
 /**************************** init / exit <END> ******************************/
index 462ee9a84e7655fb39403fdcc4ff2ba83e33823b..f0e2fbed3d4cf86a8000ec212e435546098507fc 100644 (file)
@@ -68,7 +68,7 @@ struct appldata_mem_data {
        u64 pgmajfault;         /* page faults (major only) */
 // <-- New in 2.6
 
-} appldata_mem_data;
+} __attribute__((packed)) appldata_mem_data;
 
 
 static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
index dd61638d3027c6eddcaa0bf8bfd5e1d8d2477541..2a4c7432db4ac2960cde34ee6033671fe171cfc5 100644 (file)
@@ -57,7 +57,7 @@ struct appldata_net_sum_data {
        u64 rx_dropped;         /* no space in linux buffers     */
        u64 tx_dropped;         /* no space available in linux   */
        u64 collisions;         /* collisions while transmitting */
-} appldata_net_sum_data;
+} __attribute__((packed)) appldata_net_sum_data;
 
 
 static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
index b83f074845514ad409f8c5da3e57cf3a2c2b8459..e0a476bf4fd644691bf5b50e93db05a2367b59bd 100644 (file)
@@ -49,7 +49,7 @@ struct appldata_os_per_cpu {
        u32 per_cpu_softirq;    /* ... spent in softirqs            */
        u32 per_cpu_iowait;     /* ... spent while waiting for I/O  */
 // <-- New in 2.6
-};
+} __attribute__((packed));
 
 struct appldata_os_data {
        u64 timestamp;
@@ -75,7 +75,7 @@ struct appldata_os_data {
 
        /* per cpu data */
        struct appldata_os_per_cpu os_cpu[0];
-};
+} __attribute__((packed));
 
 static struct appldata_os_data *appldata_os_data;
 
index 26889366929a1ac3d9162a2ba357dd837a143877..06afa3103ace75143d44258c215cc9c3d1a7fb00 100644 (file)
@@ -40,6 +40,7 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #ifdef CONFIG_S390_SUPPORT
 #include "compat_ptrace.h"
@@ -130,13 +131,19 @@ static int
 peek_user(struct task_struct *child, addr_t addr, addr_t data)
 {
        struct user *dummy = NULL;
-       addr_t offset, tmp;
+       addr_t offset, tmp, mask;
 
        /*
         * Stupid gdb peeks/pokes the access registers in 64 bit with
         * an alignment of 4. Programmers from hell...
         */
-       if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+       mask = __ADDR_MASK;
+#ifdef CONFIG_ARCH_S390X
+       if (addr >= (addr_t) &dummy->regs.acrs &&
+           addr < (addr_t) &dummy->regs.orig_gpr2)
+               mask = 3;
+#endif
+       if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
                return -EIO;
 
        if (addr < (addr_t) &dummy->regs.acrs) {
@@ -153,6 +160,16 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
                 * access registers are stored in the thread structure
                 */
                offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_ARCH_S390X
+               /*
+                * Very special case: old & broken 64 bit gdb reading
+                * from acrs[15]. Result is a 64 bit value. Read the
+                * 32 bit acrs[15] value and shift it by 32. Sick...
+                */
+               if (addr == (addr_t) &dummy->regs.acrs[15])
+                       tmp = ((unsigned long) child->thread.acrs[15]) << 32;
+               else
+#endif
                tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
 
        } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
@@ -167,6 +184,9 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
                 */
                offset = addr - (addr_t) &dummy->regs.fp_regs;
                tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
+               if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
+                       tmp &= (unsigned long) FPC_VALID_MASK
+                               << (BITS_PER_LONG - 32);
 
        } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
                /*
@@ -191,13 +211,19 @@ static int
 poke_user(struct task_struct *child, addr_t addr, addr_t data)
 {
        struct user *dummy = NULL;
-       addr_t offset;
+       addr_t offset, mask;
 
        /*
         * Stupid gdb peeks/pokes the access registers in 64 bit with
         * an alignment of 4. Programmers from hell indeed...
         */
-       if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
+       mask = __ADDR_MASK;
+#ifdef CONFIG_ARCH_S390X
+       if (addr >= (addr_t) &dummy->regs.acrs &&
+           addr < (addr_t) &dummy->regs.orig_gpr2)
+               mask = 3;
+#endif
+       if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
                return -EIO;
 
        if (addr < (addr_t) &dummy->regs.acrs) {
@@ -224,6 +250,17 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 * access registers are stored in the thread structure
                 */
                offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_ARCH_S390X
+               /*
+                * Very special case: old & broken 64 bit gdb writing
+                * to acrs[15] with a 64 bit value. Ignore the lower
+                * half of the value and write the upper 32 bit to
+                * acrs[15]. Sick...
+                */
+               if (addr == (addr_t) &dummy->regs.acrs[15])
+                       child->thread.acrs[15] = (unsigned int) (data >> 32);
+               else
+#endif
                *(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
 
        } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
@@ -237,7 +274,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 * floating point regs. are stored in the thread structure
                 */
                if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
-                   (data & ~FPC_VALID_MASK) != 0)
+                   (data & ~((unsigned long) FPC_VALID_MASK
+                             << (BITS_PER_LONG - 32))) != 0)
                        return -EINVAL;
                offset = addr - (addr_t) &dummy->regs.fp_regs;
                *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
@@ -722,6 +760,13 @@ syscall_trace(struct pt_regs *regs, int entryexit)
        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
                                 ? 0x80 : 0));
 
+       /*
+        * If the debuffer has set an invalid system call number,
+        * we prepare to skip the system call restart handling.
+        */
+       if (!entryexit && regs->gprs[2] >= NR_syscalls)
+               regs->trap = -1;
+
        /*
         * this isn't the same as continuing with a signal, but it will do
         * for normal use.  strace only continues with a signal if the
index 80306bc8c799b7c7e8c98d819806a78a1a7eb951..75fde949d12570a68d1a5aaa228fc946fccc0c4b 100644 (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 
         * user context.
         */
-        if (user_address == 0 || in_interrupt() || !mm)
+        if (user_address == 0 || in_atomic() || !mm)
                 goto no_context;
 
        /*
index d1dcd8eae3c901c3bacb00f08875ebb770141e44..5b77188527a9ad91f8d3f70691ba9c2d4393f4a1 100644 (file)
@@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
   fore_200e-objs               += fore200e_pca_fw.o
   # guess the target endianess to choose the right PCA-200E firmware image
   ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
-    CONFIG_ATM_FORE200E_PCA_FW = $(shell if test -n "`$(CC) -E -dM $(src)/../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo $(obj)/pca200e.bin; else echo $(obj)/pca200e_ecd.bin2; fi)
+    byteorder.h                        := include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h
+    CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
   endif
 endif
 
index 9e65bfb85ba325285f299dcaf82388146bcafebb..5f702199543ac043eec3905b6231e119e421ba7c 100644 (file)
@@ -383,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore200e)
     switch(fore200e->state) {
 
     case FORE200E_STATE_COMPLETE:
-       if (fore200e->stats)
-           kfree(fore200e->stats);
+       kfree(fore200e->stats);
 
     case FORE200E_STATE_IRQ:
        free_irq(fore200e->irq, fore200e->atm_dev);
@@ -963,8 +962,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
                entry, txq->tail, entry->vc_map, entry->skb);
 
        /* free copy of misaligned data */
-       if (entry->data)
-           kfree(entry->data);
+       kfree(entry->data);
        
        /* remove DMA mapping */
        fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
index 3022c548a132317e4b8c9334b0cd520b63bde32e..df2c83fd5496015ac64025ea9762e90e80c5093f 100644 (file)
@@ -412,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
 init_one_failure:
        if (atm_dev)
                atm_dev_deregister(atm_dev);
-       if (he_dev)
-               kfree(he_dev);
+       kfree(he_dev);
        pci_disable_device(pci_dev);
        return err;
 }
@@ -2534,8 +2533,7 @@ he_open(struct atm_vcc *vcc)
 open_failed:
 
        if (err) {
-               if (he_vcc)
-                       kfree(he_vcc);
+               kfree(he_vcc);
                clear_bit(ATM_VF_ADDR, &vcc->flags);
        }
        else
index 85bf5c8442b000917465b56fb9ce12d2b0e68a14..b2a7b754fd1403a4c7dbd4ffe5ab47cd3de70b5e 100644 (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);
       
    /* Initialize SCQ0, the only VBR SCQ used */
-   card->scq1 = (scq_info *) NULL;
-   card->scq2 = (scq_info *) NULL;
+   card->scq1 = NULL;
+   card->scq2 = NULL;
    card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
-   if (card->scq0 == (scq_info *) NULL)
+   if (card->scq0 == NULL)
    {
       printk("nicstar%d: can't get SCQ0.\n", i);
       error = 12;
@@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 scd)
    int i;
 
    if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
-      return (scq_info *) NULL;
+      return NULL;
 
    scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
-   if (scq == (scq_info *) NULL)
-      return (scq_info *) NULL;
+   if (scq == NULL)
+      return NULL;
    scq->org = kmalloc(2 * size, GFP_KERNEL);
    if (scq->org == NULL)
    {
       kfree(scq);
-      return (scq_info *) NULL;
+      return NULL;
    }
    scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
                                           (size / NS_SCQE_SIZE), GFP_KERNEL);
-   if (scq->skb == (struct sk_buff **) NULL)
+   if (scq->skb == NULL)
    {
       kfree(scq->org);
       kfree(scq);
-      return (scq_info *) NULL;
+      return NULL;
    }
    scq->num_entries = size / NS_SCQE_SIZE;
    scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
@@ -1498,7 +1498,7 @@ static int ns_open(struct atm_vcc *vcc)
          vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
 
          scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
-         if (scq == (scq_info *) NULL)
+         if (scq == NULL)
          {
             PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
             card->scd2vc[frscdi] = NULL;
index 47a800519ad01ed87638b329f1fd4a1213c6a641..8d5e65cb975528203ebb5b951044d9eaf73c91ad 100644 (file)
@@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc)
                zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
                dealloc_shaper(vcc->dev,zatm_vcc->shaper);
        }
-       if (zatm_vcc->ring) kfree(zatm_vcc->ring);
+       kfree(zatm_vcc->ring);
 }
 
 
@@ -1339,12 +1339,9 @@ static int __init zatm_start(struct atm_dev *dev)
        return 0;
     out:
        for (i = 0; i < NR_MBX; i++)
-               if (zatm_dev->mbx_start[i] != 0)
-                       kfree((void *) zatm_dev->mbx_start[i]);
-       if (zatm_dev->rx_map != NULL)
-               kfree(zatm_dev->rx_map);
-       if (zatm_dev->tx_map != NULL)
-               kfree(zatm_dev->tx_map);
+               kfree(zatm_dev->mbx_start[i]);
+       kfree(zatm_dev->rx_map);
+       kfree(zatm_dev->tx_map);
        free_irq(zatm_dev->irq, dev);
        return error;
 }
index ce42889f98fbdac287a2af1d50a8c66346a5433a..adc4dcc306f4225f850c24cfe4916e60b2b6f372 100644 (file)
@@ -8,13 +8,12 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
+ *  -- Kill first_open (Al Viro fixed the block layer now)
  *  -- Do resets with usb_device_reset (needs a thread context, use khubd)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
- *  -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- verify the 13 conditions and do bulk resets
- *  -- normal pool of commands instead of cmdv[]?
  *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- highmem and sg
 #define US_SC_SCSI     0x06            /* Transparent */
 
 /*
+ * This many LUNs per USB device.
+ * Every one of them takes a host, see UB_MAX_HOSTS.
  */
+#define UB_MAX_LUNS   4
+
+/*
+ */
+
 #define UB_MINORS_PER_MAJOR    8
 
 #define UB_MAX_CDB_SIZE      16                /* Corresponds to Bulk */
@@ -65,7 +71,7 @@ struct bulk_cb_wrap {
        u32     Tag;                    /* unique per command id */
        __le32  DataTransferLength;     /* size of data */
        u8      Flags;                  /* direction in bit 0 */
-       u8      Lun;                    /* LUN normally 0 */
+       u8      Lun;                    /* LUN */
        u8      Length;                 /* of of the CDB */
        u8      CDB[UB_MAX_CDB_SIZE];   /* max command */
 };
@@ -168,6 +174,7 @@ struct ub_scsi_cmd {
        unsigned int len;               /* Requested length */
        // struct scatterlist sgv[UB_MAX_REQ_SG];
 
+       struct ub_lun *lun;
        void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
        void *back;
 };
@@ -252,25 +259,47 @@ struct ub_scsi_cmd_queue {
 };
 
 /*
- * The UB device instance.
+ * The block device instance (one per LUN).
+ */
+struct ub_lun {
+       struct ub_dev *udev;
+       struct list_head link;
+       struct gendisk *disk;
+       int id;                         /* Host index */
+       int num;                        /* LUN number */
+       char name[16];
+
+       int changed;                    /* Media was changed */
+       int removable;
+       int readonly;
+       int first_open;                 /* Kludge. See ub_bd_open. */
+
+       /* Use Ingo's mempool if or when we have more than one command. */
+       /*
+        * Currently we never need more than one command for the whole device.
+        * However, giving every LUN a command is a cheap and automatic way
+        * to enforce fairness between them.
+        */
+       int cmda[1];
+       struct ub_scsi_cmd cmdv[1];
+
+       struct ub_capacity capacity; 
+};
+
+/*
+ * The USB device instance.
  */
 struct ub_dev {
        spinlock_t lock;
-       int id;                         /* Number among ub's */
        atomic_t poison;                /* The USB device is disconnected */
        int openc;                      /* protected by ub_lock! */
                                        /* kref is too implicit for our taste */
        unsigned int tagcnt;
-       int changed;                    /* Media was changed */
-       int removable;
-       int readonly;
-       int first_open;                 /* Kludge. See ub_bd_open. */
-       char name[8];
+       char name[12];
        struct usb_device *dev;
        struct usb_interface *intf;
 
-       struct ub_capacity capacity; 
-       struct gendisk *disk;
+       struct list_head luns;
 
        unsigned int send_bulk_pipe;    /* cached pipe values */
        unsigned int recv_bulk_pipe;
@@ -279,10 +308,6 @@ struct ub_dev {
 
        struct tasklet_struct tasklet;
 
-       /* XXX Use Ingo's mempool (once we have more than one) */
-       int cmda[1];
-       struct ub_scsi_cmd cmdv[1];
-
        struct ub_scsi_cmd_queue cmd_queue;
        struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */
        unsigned char top_sense[UB_SENSE_SIZE];
@@ -301,9 +326,9 @@ struct ub_dev {
 /*
  */
 static void ub_cleanup(struct ub_dev *sc);
-static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq);
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq);
+static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
+static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq);
 static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
     struct request *rq);
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -320,8 +345,10 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
     int stalled_pipe);
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
-static int ub_sync_tur(struct ub_dev *sc);
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret);
+static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_capacity *ret);
+static int ub_probe_lun(struct ub_dev *sc, int lnum);
 
 /*
  */
@@ -342,6 +369,7 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
  */
 #define UB_MAX_HOSTS  26
 static char ub_hostv[UB_MAX_HOSTS];
+
 static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
 
 /*
@@ -406,6 +434,8 @@ static ssize_t ub_diag_show(struct device *dev, char *page)
 {
        struct usb_interface *intf;
        struct ub_dev *sc;
+       struct list_head *p;
+       struct ub_lun *lun;
        int cnt;
        unsigned long flags;
        int nc, nh;
@@ -421,9 +451,15 @@ static ssize_t ub_diag_show(struct device *dev, char *page)
        spin_lock_irqsave(&sc->lock, flags);
 
        cnt += sprintf(page + cnt,
-           "qlen %d qmax %d changed %d removable %d readonly %d\n",
-           sc->cmd_queue.qlen, sc->cmd_queue.qmax,
-           sc->changed, sc->removable, sc->readonly);
+           "qlen %d qmax %d\n",
+           sc->cmd_queue.qlen, sc->cmd_queue.qmax);
+
+       list_for_each (p, &sc->luns) {
+               lun = list_entry(p, struct ub_lun, link);
+               cnt += sprintf(page + cnt,
+                   "lun %u changed %d removable %d readonly %d\n",
+                   lun->num, lun->changed, lun->removable, lun->readonly);
+       }
 
        if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
        for (j = 0; j < SCMD_TRACE_SZ; j++) {
@@ -523,53 +559,63 @@ static void ub_put(struct ub_dev *sc)
  */
 static void ub_cleanup(struct ub_dev *sc)
 {
+       struct list_head *p;
+       struct ub_lun *lun;
        request_queue_t *q;
 
-       /* I don't think queue can be NULL. But... Stolen from sx8.c */
-       if ((q = sc->disk->queue) != NULL)
-               blk_cleanup_queue(q);
+       while (!list_empty(&sc->luns)) {
+               p = sc->luns.next;
+               lun = list_entry(p, struct ub_lun, link);
+               list_del(p);
 
-       /*
-        * If we zero disk->private_data BEFORE put_disk, we have to check
-        * for NULL all over the place in open, release, check_media and
-        * revalidate, because the block level semaphore is well inside the
-        * put_disk. But we cannot zero after the call, because *disk is gone.
-        * The sd.c is blatantly racy in this area.
-        */
-       /* disk->private_data = NULL; */
-       put_disk(sc->disk);
-       sc->disk = NULL;
+               /* I don't think queue can be NULL. But... Stolen from sx8.c */
+               if ((q = lun->disk->queue) != NULL)
+                       blk_cleanup_queue(q);
+               /*
+                * If we zero disk->private_data BEFORE put_disk, we have
+                * to check for NULL all over the place in open, release,
+                * check_media and revalidate, because the block level
+                * semaphore is well inside the put_disk.
+                * But we cannot zero after the call, because *disk is gone.
+                * The sd.c is blatantly racy in this area.
+                */
+               /* disk->private_data = NULL; */
+               put_disk(lun->disk);
+               lun->disk = NULL;
+
+               ub_id_put(lun->id);
+               kfree(lun);
+       }
 
-       ub_id_put(sc->id);
        kfree(sc);
 }
 
 /*
  * The "command allocator".
  */
-static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc)
+static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun)
 {
        struct ub_scsi_cmd *ret;
 
-       if (sc->cmda[0])
+       if (lun->cmda[0])
                return NULL;
-       ret = &sc->cmdv[0];
-       sc->cmda[0] = 1;
+       ret = &lun->cmdv[0];
+       lun->cmda[0] = 1;
        return ret;
 }
 
-static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd)
 {
-       if (cmd != &sc->cmdv[0]) {
+       if (cmd != &lun->cmdv[0]) {
                printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
-                   sc->name, cmd);
+                   lun->name, cmd);
                return;
        }
-       if (!sc->cmda[0]) {
-               printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name);
+       if (!lun->cmda[0]) {
+               printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name);
                return;
        }
-       sc->cmda[0] = 0;
+       lun->cmda[0] = 0;
 }
 
 /*
@@ -630,29 +676,30 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
 
 static void ub_bd_rq_fn(request_queue_t *q)
 {
-       struct ub_dev *sc = q->queuedata;
+       struct ub_lun *lun = q->queuedata;
        struct request *rq;
 
        while ((rq = elv_next_request(q)) != NULL) {
-               if (ub_bd_rq_fn_1(sc, rq) != 0) {
+               if (ub_bd_rq_fn_1(lun, rq) != 0) {
                        blk_stop_queue(q);
                        break;
                }
        }
 }
 
-static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq)
+static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
 {
+       struct ub_dev *sc = lun->udev;
        struct ub_scsi_cmd *cmd;
        int rc;
 
-       if (atomic_read(&sc->poison) || sc->changed) {
+       if (atomic_read(&sc->poison) || lun->changed) {
                blkdev_dequeue_request(rq);
                ub_end_rq(rq, 0);
                return 0;
        }
 
-       if ((cmd = ub_get_cmd(sc)) == NULL)
+       if ((cmd = ub_get_cmd(lun)) == NULL)
                return -1;
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
@@ -661,32 +708,30 @@ static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq)
        if (blk_pc_request(rq)) {
                rc = ub_cmd_build_packet(sc, cmd, rq);
        } else {
-               rc = ub_cmd_build_block(sc, cmd, rq);
+               rc = ub_cmd_build_block(sc, lun, cmd, rq);
        }
        if (rc != 0) {
-               ub_put_cmd(sc, cmd);
+               ub_put_cmd(lun, cmd);
                ub_end_rq(rq, 0);
-               blk_start_queue(sc->disk->queue);
                return 0;
        }
-
        cmd->state = UB_CMDST_INIT;
+       cmd->lun = lun;
        cmd->done = ub_rw_cmd_done;
        cmd->back = rq;
 
        cmd->tag = sc->tagcnt++;
        if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
-               ub_put_cmd(sc, cmd);
+               ub_put_cmd(lun, cmd);
                ub_end_rq(rq, 0);
-               blk_start_queue(sc->disk->queue);
                return 0;
        }
 
        return 0;
 }
 
-static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq)
+static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq)
 {
        int ub_dir;
 #if 0 /* We use rq->buffer for now */
@@ -707,7 +752,7 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
        sg = &cmd->sgv[0];
        n_elem = blk_rq_map_sg(q, rq, sg);
        if (n_elem <= 0) {
-               ub_put_cmd(sc, cmd);
+               ub_put_cmd(lun, cmd);
                ub_end_rq(rq, 0);
                blk_start_queue(q);
                return 0;               /* request with no s/g entries? */
@@ -716,7 +761,7 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
        if (n_elem != 1) {              /* Paranoia */
                printk(KERN_WARNING "%s: request with %d segments\n",
                    sc->name, n_elem);
-               ub_put_cmd(sc, cmd);
+               ub_put_cmd(lun, cmd);
                ub_end_rq(rq, 0);
                blk_start_queue(q);
                return 0;
@@ -748,8 +793,8 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
         * The call to blk_queue_hardsect_size() guarantees that request
         * is aligned, but it is given in terms of 512 byte units, always.
         */
-       block = rq->sector >> sc->capacity.bshift;
-       nblks = rq->nr_sectors >> sc->capacity.bshift;
+       block = rq->sector >> lun->capacity.bshift;
+       nblks = rq->nr_sectors >> lun->capacity.bshift;
 
        cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
        /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
@@ -803,7 +848,8 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
        struct request *rq = cmd->back;
-       struct gendisk *disk = sc->disk;
+       struct ub_lun *lun = cmd->lun;
+       struct gendisk *disk = lun->disk;
        request_queue_t *q = disk->queue;
        int uptodate;
 
@@ -818,7 +864,7 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        else
                uptodate = 0;
 
-       ub_put_cmd(sc, cmd);
+       ub_put_cmd(lun, cmd);
        ub_end_rq(rq, uptodate);
        blk_start_queue(q);
 }
@@ -887,7 +933,7 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        bcb->Tag = cmd->tag;            /* Endianness is not important */
        bcb->DataTransferLength = cpu_to_le32(cmd->len);
        bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
-       bcb->Lun = 0;                   /* No multi-LUN yet */
+       bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;
        bcb->Length = cmd->cdb_len;
 
        /* copy the command payload */
@@ -1002,9 +1048,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         * The control pipe clears itself - nothing to do.
                         * XXX Might try to reset the device here and retry.
                         */
-                       printk(KERN_NOTICE "%s: "
-                           "stall on control pipe for device %u\n",
-                           sc->name, sc->dev->devnum);
+                       printk(KERN_NOTICE "%s: stall on control pipe\n",
+                           sc->name);
                        goto Bad_End;
                }
 
@@ -1025,9 +1070,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         * The control pipe clears itself - nothing to do.
                         * XXX Might try to reset the device here and retry.
                         */
-                       printk(KERN_NOTICE "%s: "
-                           "stall on control pipe for device %u\n",
-                           sc->name, sc->dev->devnum);
+                       printk(KERN_NOTICE "%s: stall on control pipe\n",
+                           sc->name);
                        goto Bad_End;
                }
 
@@ -1046,9 +1090,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
                        if (rc != 0) {
                                printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear for device %u"
-                                   " (code %d)\n",
-                                   sc->name, sc->dev->devnum, rc);
+                                   "unable to submit clear (%d)\n",
+                                   sc->name, rc);
                                /*
                                 * This is typically ENOMEM or some other such shit.
                                 * Retrying is pointless. Just do Bad End on it...
@@ -1107,9 +1150,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
                        if (rc != 0) {
                                printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear for device %u"
-                                   " (code %d)\n",
-                                   sc->name, sc->dev->devnum, rc);
+                                   "unable to submit clear (%d)\n",
+                                   sc->name, rc);
                                /*
                                 * This is typically ENOMEM or some other such shit.
                                 * Retrying is pointless. Just do Bad End on it...
@@ -1140,9 +1182,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
                        if (rc != 0) {
                                printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear for device %u"
-                                   " (code %d)\n",
-                                   sc->name, sc->dev->devnum, rc);
+                                   "unable to submit clear (%d)\n",
+                                   sc->name, rc);
                                /*
                                 * This is typically ENOMEM or some other such shit.
                                 * Retrying is pointless. Just do Bad End on it...
@@ -1164,9 +1205,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         * encounter such a thing, try to read the CSW again.
                         */
                        if (++cmd->stat_count >= 4) {
-                               printk(KERN_NOTICE "%s: "
-                                   "unable to get CSW on device %u\n",
-                                   sc->name, sc->dev->devnum);
+                               printk(KERN_NOTICE "%s: unable to get CSW\n",
+                                   sc->name);
                                goto Bad_End;
                        }
                        __ub_state_stat(sc, cmd);
@@ -1207,10 +1247,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         */
                        if (++cmd->stat_count >= 4) {
                                printk(KERN_NOTICE "%s: "
-                                   "tag mismatch orig 0x%x reply 0x%x "
-                                   "on device %u\n",
-                                   sc->name, cmd->tag, bcs->Tag,
-                                   sc->dev->devnum);
+                                   "tag mismatch orig 0x%x reply 0x%x\n",
+                                   sc->name, cmd->tag, bcs->Tag);
                                goto Bad_End;
                        }
                        __ub_state_stat(sc, cmd);
@@ -1244,8 +1282,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
        } else {
                printk(KERN_WARNING "%s: "
-                   "wrong command state %d on device %u\n",
-                   sc->name, cmd->state, sc->dev->devnum);
+                   "wrong command state %d\n",
+                   sc->name, cmd->state);
                goto Bad_End;
        }
        return;
@@ -1288,7 +1326,6 @@ static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                /* XXX Clear stalls */
-               printk("%s: CSW #%d submit failed (%d)\n", sc->name, cmd->tag, rc); /* P3 */
                ub_complete(&sc->work_done);
                ub_state_done(sc, cmd, rc);
                return;
@@ -1333,6 +1370,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        scmd->state = UB_CMDST_INIT;
        scmd->data = sc->top_sense;
        scmd->len = UB_SENSE_SIZE;
+       scmd->lun = cmd->lun;
        scmd->done = ub_top_sense_done;
        scmd->back = cmd;
 
@@ -1411,14 +1449,14 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
        }
        if (cmd != scmd->back) {
                printk(KERN_WARNING "%s: "
-                   "sense done for wrong command 0x%x on device %u\n",
-                   sc->name, cmd->tag, sc->dev->devnum);
+                   "sense done for wrong command 0x%x\n",
+                   sc->name, cmd->tag);
                return;
        }
        if (cmd->state != UB_CMDST_SENSE) {
                printk(KERN_WARNING "%s: "
-                   "sense done with bad cmd state %d on device %u\n",
-                   sc->name, cmd->state, sc->dev->devnum);
+                   "sense done with bad cmd state %d\n",
+                   sc->name, cmd->state);
                return;
        }
 
@@ -1429,68 +1467,32 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
        ub_scsi_urb_compl(sc, cmd);
 }
 
-#if 0
-/* Determine what the maximum LUN supported is */
-int usb_stor_Bulk_max_lun(struct us_data *us)
-{
-       int result;
-
-       /* issue the command */
-       result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
-                                US_BULK_GET_MAX_LUN, 
-                                USB_DIR_IN | USB_TYPE_CLASS | 
-                                USB_RECIP_INTERFACE,
-                                0, us->ifnum, us->iobuf, 1, HZ);
-
-       /* 
-        * Some devices (i.e. Iomega Zip100) need this -- apparently
-        * the bulk pipes get STALLed when the GetMaxLUN request is
-        * processed.   This is, in theory, harmless to all other devices
-        * (regardless of if they stall or not).
-        */
-       if (result < 0) {
-               usb_stor_clear_halt(us, us->recv_bulk_pipe);
-               usb_stor_clear_halt(us, us->send_bulk_pipe);
-       }
-
-       US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
-                 result, us->iobuf[0]);
-
-       /* if we have a successful request, return the result */
-       if (result == 1)
-               return us->iobuf[0];
-
-       /* return the default -- no LUNs */
-       return 0;
-}
-#endif
-
 /*
  * This is called from a process context.
  */
-static void ub_revalidate(struct ub_dev *sc)
+static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
 {
 
-       sc->readonly = 0;       /* XXX Query this from the device */
+       lun->readonly = 0;      /* XXX Query this from the device */
 
-       sc->capacity.nsec = 0;
-       sc->capacity.bsize = 512;
-       sc->capacity.bshift = 0;
+       lun->capacity.nsec = 0;
+       lun->capacity.bsize = 512;
+       lun->capacity.bshift = 0;
 
-       if (ub_sync_tur(sc) != 0)
+       if (ub_sync_tur(sc, lun) != 0)
                return;                 /* Not ready */
-       sc->changed = 0;
+       lun->changed = 0;
 
-       if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
+       if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
                /*
                 * The retry here means something is wrong, either with the
                 * device, with the transport, or with our code.
                 * We keep this because sd.c has retries for capacity.
                 */
-               if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
-                       sc->capacity.nsec = 0;
-                       sc->capacity.bsize = 512;
-                       sc->capacity.bshift = 0;
+               if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
+                       lun->capacity.nsec = 0;
+                       lun->capacity.bsize = 512;
+                       lun->capacity.bshift = 0;
                }
        }
 }
@@ -1503,12 +1505,15 @@ static void ub_revalidate(struct ub_dev *sc)
 static int ub_bd_open(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ub_lun *lun;
        struct ub_dev *sc;
        unsigned long flags;
        int rc;
 
-       if ((sc = disk->private_data) == NULL)
+       if ((lun = disk->private_data) == NULL)
                return -ENXIO;
+       sc = lun->udev;
+
        spin_lock_irqsave(&ub_lock, flags);
        if (atomic_read(&sc->poison)) {
                spin_unlock_irqrestore(&ub_lock, flags);
@@ -1529,15 +1534,15 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
         * The bottom line is, Al Viro says that we should not allow
         * bdev->bd_invalidated to be set when doing add_disk no matter what.
         */
-       if (sc->first_open) {
-               if (sc->changed) {
-                       sc->first_open = 0;
+       if (lun->first_open) {
+               lun->first_open = 0;
+               if (lun->changed) {
                        rc = -ENOMEDIUM;
                        goto err_open;
                }
        }
 
-       if (sc->removable || sc->readonly)
+       if (lun->removable || lun->readonly)
                check_disk_change(inode->i_bdev);
 
        /*
@@ -1545,12 +1550,12 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
         * under some pretty murky conditions (a failure of READ CAPACITY).
         * We may need it one day.
         */
-       if (sc->removable && sc->changed && !(filp->f_flags & O_NDELAY)) {
+       if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {
                rc = -ENOMEDIUM;
                goto err_open;
        }
 
-       if (sc->readonly && (filp->f_mode & FMODE_WRITE)) {
+       if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {
                rc = -EROFS;
                goto err_open;
        }
@@ -1567,7 +1572,8 @@ err_open:
 static int ub_bd_release(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct ub_dev *sc = disk->private_data;
+       struct ub_lun *lun = disk->private_data;
+       struct ub_dev *sc = lun->udev;
 
        ub_put(sc);
        return 0;
@@ -1597,20 +1603,14 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
  */
 static int ub_bd_revalidate(struct gendisk *disk)
 {
-       struct ub_dev *sc = disk->private_data;
-
-       ub_revalidate(sc);
-       /* This is pretty much a long term P3 */
-       if (!atomic_read(&sc->poison)) {                /* Cover sc->dev */
-               printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
-                   sc->name, sc->dev->devnum,
-                   sc->capacity.nsec, sc->capacity.bsize);
-       }
+       struct ub_lun *lun = disk->private_data;
+
+       ub_revalidate(lun->udev, lun);
 
        /* XXX Support sector size switching like in sr.c */
-       blk_queue_hardsect_size(disk->queue, sc->capacity.bsize);
-       set_capacity(disk, sc->capacity.nsec);
-       // set_disk_ro(sdkp->disk, sc->readonly);
+       blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
+       set_capacity(disk, lun->capacity.nsec);
+       // set_disk_ro(sdkp->disk, lun->readonly);
 
        return 0;
 }
@@ -1626,9 +1626,9 @@ static int ub_bd_revalidate(struct gendisk *disk)
  */
 static int ub_bd_media_changed(struct gendisk *disk)
 {
-       struct ub_dev *sc = disk->private_data;
+       struct ub_lun *lun = disk->private_data;
 
-       if (!sc->removable)
+       if (!lun->removable)
                return 0;
 
        /*
@@ -1640,12 +1640,12 @@ static int ub_bd_media_changed(struct gendisk *disk)
         * will fail, then block layer discards the data. Since we never
         * spin drives up, such devices simply cannot be used with ub anyway.
         */
-       if (ub_sync_tur(sc) != 0) {
-               sc->changed = 1;
+       if (ub_sync_tur(lun->udev, lun) != 0) {
+               lun->changed = 1;
                return 1;
        }
 
-       return sc->changed;
+       return lun->changed;
 }
 
 static struct block_device_operations ub_bd_fops = {
@@ -1669,7 +1669,7 @@ static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 /*
  * Test if the device has a check condition on it, synchronously.
  */
-static int ub_sync_tur(struct ub_dev *sc)
+static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
 {
        struct ub_scsi_cmd *cmd;
        enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };
@@ -1688,6 +1688,7 @@ static int ub_sync_tur(struct ub_dev *sc)
        cmd->cdb_len = 6;
        cmd->dir = UB_DIR_NONE;
        cmd->state = UB_CMDST_INIT;
+       cmd->lun = lun;                 /* This may be NULL, but that's ok */
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
@@ -1718,7 +1719,8 @@ err_alloc:
 /*
  * Read the SCSI capacity synchronously (for probing).
  */
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret)
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_capacity *ret)
 {
        struct ub_scsi_cmd *cmd;
        char *p;
@@ -1743,6 +1745,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret)
        cmd->state = UB_CMDST_INIT;
        cmd->data = p;
        cmd->len = 8;
+       cmd->lun = lun;
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
@@ -1811,6 +1814,90 @@ static void ub_probe_timeout(unsigned long arg)
        complete(cop);
 }
 
+/*
+ * Get number of LUNs by the way of Bulk GetMaxLUN command.
+ */
+static int ub_sync_getmaxlun(struct ub_dev *sc)
+{
+       int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
+       unsigned char *p;
+       enum { ALLOC_SIZE = 1 };
+       struct usb_ctrlrequest *cr;
+       struct completion compl;
+       struct timer_list timer;
+       int nluns;
+       int rc;
+
+       init_completion(&compl);
+
+       rc = -ENOMEM;
+       if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+               goto err_alloc;
+       *p = 55;
+
+       cr = &sc->work_cr;
+       cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+       cr->bRequest = US_BULK_GET_MAX_LUN;
+       cr->wValue = cpu_to_le16(0);
+       cr->wIndex = cpu_to_le16(ifnum);
+       cr->wLength = cpu_to_le16(1);
+
+       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
+           (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
+       sc->work_urb.transfer_flags = 0;
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+               if (rc == -EPIPE) {
+                       printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
+                            sc->name); /* P3 */
+               } else {
+                       printk(KERN_WARNING
+                            "%s: Unable to submit GetMaxLUN (%d)\n",
+                            sc->name, rc);
+               }
+               goto err_submit;
+       }
+
+       init_timer(&timer);
+       timer.function = ub_probe_timeout;
+       timer.data = (unsigned long) &compl;
+       timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&timer);
+
+       wait_for_completion(&compl);
+
+       del_timer_sync(&timer);
+       usb_kill_urb(&sc->work_urb);
+
+       if (sc->work_urb.actual_length != 1) {
+               printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
+                   sc->work_urb.actual_length); /* P3 */
+               nluns = 0;
+       } else {
+               if ((nluns = *p) == 55) {
+                       nluns = 0;
+               } else {
+                       /* GetMaxLUN returns the maximum LUN number */
+                       nluns += 1;
+                       if (nluns > UB_MAX_LUNS)
+                               nluns = UB_MAX_LUNS;
+               }
+               printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name,
+                   *p, nluns); /* P3 */
+       }
+
+       kfree(p);
+       return nluns;
+
+err_submit:
+       kfree(p);
+err_alloc:
+       return rc;
+}
+
 /*
  * Clear initial stalls.
  */
@@ -1897,8 +1984,8 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
        }
 
        if (ep_in == NULL || ep_out == NULL) {
-               printk(KERN_NOTICE "%s: device %u failed endpoint check\n",
-                   sc->name, sc->dev->devnum);
+               printk(KERN_NOTICE "%s: failed endpoint check\n",
+                   sc->name);
                return -EIO;
        }
 
@@ -1921,8 +2008,7 @@ static int ub_probe(struct usb_interface *intf,
     const struct usb_device_id *dev_id)
 {
        struct ub_dev *sc;
-       request_queue_t *q;
-       struct gendisk *disk;
+       int nluns;
        int rc;
        int i;
 
@@ -1931,6 +2017,7 @@ static int ub_probe(struct usb_interface *intf,
                goto err_core;
        memset(sc, 0, sizeof(struct ub_dev));
        spin_lock_init(&sc->lock);
+       INIT_LIST_HEAD(&sc->luns);
        usb_init_urb(&sc->work_urb);
        tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
        atomic_set(&sc->poison, 0);
@@ -1942,19 +2029,16 @@ static int ub_probe(struct usb_interface *intf,
        ub_init_completion(&sc->work_done);
        sc->work_done.done = 1;         /* A little yuk, but oh well... */
 
-       rc = -ENOSR;
-       if ((sc->id = ub_id_get()) == -1)
-               goto err_id;
-       snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a');
-
        sc->dev = interface_to_usbdev(intf);
        sc->intf = intf;
        // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
        usb_set_intfdata(intf, sc);
        usb_get_dev(sc->dev);
        // usb_get_intf(sc->intf);      /* Do we need this? */
 
+       snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
+           sc->dev->bus->busnum, sc->dev->devnum);
+
        /* XXX Verify that we can handle the device (from descriptors) */
 
        ub_get_pipes(sc, sc->dev, intf);
@@ -1992,35 +2076,88 @@ static int ub_probe(struct usb_interface *intf,
         * In any case it's not our business how revaliadation is implemented.
         */
        for (i = 0; i < 3; i++) {       /* Retries for benh's key */
-               if ((rc = ub_sync_tur(sc)) <= 0) break;
+               if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
                if (rc != 0x6) break;
                msleep(10);
        }
 
-       sc->removable = 1;              /* XXX Query this from the device */
-       sc->changed = 1;                /* ub_revalidate clears only */
-       sc->first_open = 1;
+       nluns = 1;
+       for (i = 0; i < 3; i++) {
+               if ((rc = ub_sync_getmaxlun(sc)) < 0) {
+                       /* 
+                        * Some devices (i.e. Iomega Zip100) need this --
+                        * apparently the bulk pipes get STALLed when the
+                        * GetMaxLUN request is processed.
+                        * XXX I have a ZIP-100, verify it does this.
+                        */
+                       if (rc == -EPIPE) {
+                               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+                               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+                       }
+                       break;
+               }
+               if (rc != 0) {
+                       nluns = rc;
+                       break;
+               }
+               mdelay(100);
+       }
 
-       ub_revalidate(sc);
-       /* This is pretty much a long term P3 */
-       printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
-           sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize);
+       for (i = 0; i < nluns; i++) {
+               ub_probe_lun(sc, i);
+       }
+       return 0;
+
+       /* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
+err_diag:
+       usb_set_intfdata(intf, NULL);
+       // usb_put_intf(sc->intf);
+       usb_put_dev(sc->dev);
+       kfree(sc);
+err_core:
+       return rc;
+}
+
+static int ub_probe_lun(struct ub_dev *sc, int lnum)
+{
+       struct ub_lun *lun;
+       request_queue_t *q;
+       struct gendisk *disk;
+       int rc;
+
+       rc = -ENOMEM;
+       if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+               goto err_alloc;
+       memset(lun, 0, sizeof(struct ub_lun));
+       lun->num = lnum;
+
+       rc = -ENOSR;
+       if ((lun->id = ub_id_get()) == -1)
+               goto err_id;
+
+       lun->udev = sc;
+       list_add(&lun->link, &sc->luns);
+
+       snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
+           lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
+
+       lun->removable = 1;             /* XXX Query this from the device */
+       lun->changed = 1;               /* ub_revalidate clears only */
+       lun->first_open = 1;
+       ub_revalidate(sc, lun);
 
-       /*
-        * Just one disk per sc currently, but maybe more.
-        */
        rc = -ENOMEM;
        if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL)
                goto err_diskalloc;
 
-       sc->disk = disk;
-       sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a');
-       sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a');
+       lun->disk = disk;
+       sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
+       sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
        disk->major = UB_MAJOR;
-       disk->first_minor = sc->id * UB_MINORS_PER_MAJOR;
+       disk->first_minor = lun->id * UB_MINORS_PER_MAJOR;
        disk->fops = &ub_bd_fops;
-       disk->private_data = sc;
-       disk->driverfs_dev = &intf->dev;
+       disk->private_data = lun;
+       disk->driverfs_dev = &sc->intf->dev;    /* XXX Many to one ok? */
 
        rc = -ENOMEM;
        if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
@@ -2028,28 +2165,17 @@ static int ub_probe(struct usb_interface *intf,
 
        disk->queue = q;
 
-        // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+       blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
        blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
        blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
-       // blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
+       blk_queue_segment_boundary(q, 0xffffffff);      /* Dubious. */
        blk_queue_max_sectors(q, UB_MAX_SECTORS);
-       blk_queue_hardsect_size(q, sc->capacity.bsize);
-
-       /*
-        * This is a serious infraction, caused by a deficiency in the
-        * USB sg interface (usb_sg_wait()). We plan to remove this once
-        * we get mileage on the driver and can justify a change to USB API.
-        * See blk_queue_bounce_limit() to understand this part.
-        *
-        * XXX And I still need to be aware of the DMA mask in the HC.
-        */
-       q->bounce_pfn = blk_max_low_pfn;
-       q->bounce_gfp = GFP_NOIO;
+       blk_queue_hardsect_size(q, lun->capacity.bsize);
 
-       q->queuedata = sc;
+       q->queuedata = lun;
 
-       set_capacity(disk, sc->capacity.nsec);
-       if (sc->removable)
+       set_capacity(disk, lun->capacity.nsec);
+       if (lun->removable)
                disk->flags |= GENHD_FL_REMOVABLE;
 
        add_disk(disk);
@@ -2059,22 +2185,20 @@ static int ub_probe(struct usb_interface *intf,
 err_blkqinit:
        put_disk(disk);
 err_diskalloc:
-       device_remove_file(&sc->intf->dev, &dev_attr_diag);
-err_diag:
-       usb_set_intfdata(intf, NULL);
-       // usb_put_intf(sc->intf);
-       usb_put_dev(sc->dev);
-       ub_id_put(sc->id);
+       list_del(&lun->link);
+       ub_id_put(lun->id);
 err_id:
-       kfree(sc);
-err_core:
+       kfree(lun);
+err_alloc:
        return rc;
 }
 
 static void ub_disconnect(struct usb_interface *intf)
 {
        struct ub_dev *sc = usb_get_intfdata(intf);
-       struct gendisk *disk = sc->disk;
+       struct list_head *p;
+       struct ub_lun *lun;
+       struct gendisk *disk;
        unsigned long flags;
 
        /*
@@ -2124,14 +2248,18 @@ static void ub_disconnect(struct usb_interface *intf)
        /*
         * Unregister the upper layer.
         */
-       if (disk->flags & GENHD_FL_UP)
-               del_gendisk(disk);
-       /*
-        * I wish I could do:
-        *    set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
-        * As it is, we rely on our internal poisoning and let
-        * the upper levels to spin furiously failing all the I/O.
-        */
+       list_for_each (p, &sc->luns) {
+               lun = list_entry(p, struct ub_lun, link);
+               disk = lun->disk;
+               if (disk->flags & GENHD_FL_UP)
+                       del_gendisk(disk);
+               /*
+                * I wish I could do:
+                *    set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+                * As it is, we rely on our internal poisoning and let
+                * the upper levels to spin furiously failing all the I/O.
+                */
+       }
 
        /*
         * Taking a lock on a structure which is about to be freed
@@ -2182,8 +2310,8 @@ static int __init ub_init(void)
 {
        int rc;
 
-       /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n",
-                       sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev));
+       /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu ub_lun %zu\n",
+                       sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev), sizeof(struct ub_lun));
 
        if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
                goto err_regblkdev;
index 1c563f905a5964fb094d40ab6626e4b590a6bcb2..a7f15d9f13e5ccd04faa36b6dda826c20e750fbb 100644 (file)
@@ -374,29 +374,6 @@ static inline void do_kiss_params(struct baycom_state *bc,
 }
 
 /* --------------------------------------------------------------------- */
-/*
- * high performance HDLC encoder
- * yes, it's ugly, but generates pretty good code
- */
-
-#define ENCODEITERA(j)                         \
-({                                             \
-        if (!(notbitstream & (0x1f0 << j)))    \
-                goto stuff##j;                 \
-  encodeend##j:        ;                      \
-})
-
-#define ENCODEITERB(j)                                          \
-({                                                              \
-  stuff##j:                                                     \
-        bitstream &= ~(0x100 << j);                             \
-        bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |        \
-                ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);  \
-        numbit++;                                               \
-        notbitstream = ~bitstream;                              \
-        goto encodeend##j;                                      \
-})
-
 
 static void encode_hdlc(struct baycom_state *bc)
 {
@@ -405,6 +382,7 @@ static void encode_hdlc(struct baycom_state *bc)
        int pkt_len;
         unsigned bitstream, notbitstream, bitbuf, numbit, crc;
        unsigned char crcarr[2];
+       int j;
        
        if (bc->hdlctx.bufcnt > 0)
                return;
@@ -429,24 +407,14 @@ static void encode_hdlc(struct baycom_state *bc)
                pkt_len--;
                if (!pkt_len)
                        bp = crcarr;
-               ENCODEITERA(0);
-               ENCODEITERA(1);
-               ENCODEITERA(2);
-               ENCODEITERA(3);
-               ENCODEITERA(4);
-               ENCODEITERA(5);
-               ENCODEITERA(6);
-               ENCODEITERA(7);
-               goto enditer;
-               ENCODEITERB(0);
-               ENCODEITERB(1);
-               ENCODEITERB(2);
-               ENCODEITERB(3);
-               ENCODEITERB(4);
-               ENCODEITERB(5);
-               ENCODEITERB(6);
-               ENCODEITERB(7);
-       enditer:
+               for (j = 0; j < 8; j++)
+                       if (unlikely(!(notbitstream & (0x1f0 << j)))) {
+                               bitstream &= ~(0x100 << j);
+                               bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
+                                       ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);
+                               numbit++;
+                               notbitstream = ~bitstream;
+                       }
                numbit += 8;
                while (numbit >= 8) {
                        *wp++ = bitbuf;
@@ -610,37 +578,6 @@ static void do_rxpacket(struct net_device *dev)
        bc->stats.rx_packets++;
 }
 
-#define DECODEITERA(j)                                                        \
-({                                                                            \
-        if (!(notbitstream & (0x0fc << j)))              /* flag or abort */  \
-                goto flgabrt##j;                                              \
-        if ((bitstream & (0x1f8 << j)) == (0xf8 << j))   /* stuffed bit */    \
-                goto stuff##j;                                                \
-  enditer##j:      ;                                                           \
-})
-
-#define DECODEITERB(j)                                                                 \
-({                                                                                     \
-  flgabrt##j:                                                                          \
-        if (!(notbitstream & (0x1fc << j))) {              /* abort received */        \
-                state = 0;                                                             \
-                goto enditer##j;                                                       \
-        }                                                                              \
-        if ((bitstream & (0x1fe << j)) != (0x0fc << j))   /* flag received */          \
-                goto enditer##j;                                                       \
-        if (state)                                                                     \
-                do_rxpacket(dev);                                                      \
-        bc->hdlcrx.bufcnt = 0;                                                         \
-        bc->hdlcrx.bufptr = bc->hdlcrx.buf;                                            \
-        state = 1;                                                                     \
-        numbits = 7-j;                                                                 \
-        goto enditer##j;                                                               \
-  stuff##j:                                                                            \
-        numbits--;                                                                     \
-        bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);        \
-        goto enditer##j;                                                               \
-})
-        
 static int receive(struct net_device *dev, int cnt)
 {
        struct baycom_state *bc = netdev_priv(dev);
@@ -649,6 +586,7 @@ static int receive(struct net_device *dev, int cnt)
        unsigned char tmp[128];
         unsigned char *cp;
        int cnt2, ret = 0;
+       int j;
         
         numbits = bc->hdlcrx.numbits;
        state = bc->hdlcrx.state;
@@ -669,24 +607,32 @@ static int receive(struct net_device *dev, int cnt)
                        bitbuf |= (*cp) << 8;
                        numbits += 8;
                        notbitstream = ~bitstream;
-                       DECODEITERA(0);
-                       DECODEITERA(1);
-                       DECODEITERA(2);
-                       DECODEITERA(3);
-                       DECODEITERA(4);
-                       DECODEITERA(5);
-                       DECODEITERA(6);
-                       DECODEITERA(7);
-                       goto enddec;
-                       DECODEITERB(0);
-                       DECODEITERB(1);
-                       DECODEITERB(2);
-                       DECODEITERB(3);
-                       DECODEITERB(4);
-                       DECODEITERB(5);
-                       DECODEITERB(6);
-                       DECODEITERB(7);
-               enddec:
+                       for (j = 0; j < 8; j++) {
+
+                               /* flag or abort */
+                               if (unlikely(!(notbitstream & (0x0fc << j)))) {
+
+                                       /* abort received */
+                                       if (!(notbitstream & (0x1fc << j)))
+                                               state = 0;
+
+                                       /* not flag received */
+                                       else if (!(bitstream & (0x1fe << j)) != (0x0fc << j)) {
+                                               if (state)
+                                                       do_rxpacket(dev);
+                                               bc->hdlcrx.bufcnt = 0;
+                                               bc->hdlcrx.bufptr = bc->hdlcrx.buf;
+                                               state = 1;
+                                               numbits = 7-j;
+                                               }
+                                       }
+
+                               /* stuffed bit */
+                               else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) {
+                                       numbits--;
+                                       bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);
+                                       }
+                               }
                        while (state && numbits >= 8) {
                                if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
                                        state = 0;
index 41e517114807052707dad7bace8529f7080ba25a..c6e8b25f968529837ec3987baac52e7f55d73dea 100644 (file)
@@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *dev)
                spin_lock_irqsave(&lp->window_lock, flags);
                update_stats(dev);
                spin_unlock_irqrestore(&lp->window_lock, flags);
+
+               /* force interrupts off */
+               outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
        }
 
        link->open--;
index c59507f8a76befe001f1313f55b6780423d1e778..b3768d84474700296bf04aab92513b15f216eddb 100644 (file)
@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
        RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
        RTL_W8(EarlyTxThres, EarlyTxThld);
 
-       /* For gigabit rtl8169, MTU + header + CRC + VLAN */
-       RTL_W16(RxMaxSize, tp->rx_buf_sz);
+       /* Low hurts. Let's disable the filtering. */
+       RTL_W16(RxMaxSize, 16383);
 
        /* Set Rx Config register */
        i = rtl8169_rx_config |
@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
        }
 }
 
+static inline int rtl8169_fragmented_frame(u32 status)
+{
+       return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
+}
+
 static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
 {
        u32 opts1 = le32_to_cpu(desc->opts1);
@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 
        while (rx_left > 0) {
                unsigned int entry = cur_rx % NUM_RX_DESC;
+               struct RxDesc *desc = tp->RxDescArray + entry;
                u32 status;
 
                rmb();
-               status = le32_to_cpu(tp->RxDescArray[entry].opts1);
+               status = le32_to_cpu(desc->opts1);
 
                if (status & DescOwn)
                        break;
                if (status & RxRES) {
-                       printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
+                       printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
+                              dev->name, status);
                        tp->stats.rx_errors++;
                        if (status & (RxRWT | RxRUNT))
                                tp->stats.rx_length_errors++;
                        if (status & RxCRC)
                                tp->stats.rx_crc_errors++;
+                       rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                } else {
-                       struct RxDesc *desc = tp->RxDescArray + entry;
                        struct sk_buff *skb = tp->Rx_skbuff[entry];
                        int pkt_size = (status & 0x00001FFF) - 4;
                        void (*pci_action)(struct pci_dev *, dma_addr_t,
                                size_t, int) = pci_dma_sync_single_for_device;
 
+                       /*
+                        * The driver does not support incoming fragmented
+                        * frames. They are seen as a symptom of over-mtu
+                        * sized frames.
+                        */
+                       if (unlikely(rtl8169_fragmented_frame(status))) {
+                               tp->stats.rx_dropped++;
+                               tp->stats.rx_length_errors++;
+                               rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+                               goto move_on;
+                       }
+
                        rtl8169_rx_csum(skb, desc);
                        
                        pci_dma_sync_single_for_cpu(tp->pci_dev,
@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                        tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
                }
-               
+move_on:               
                cur_rx++; 
                rx_left--;
        }
index e68cf5fb4920fe70bfbcfb5c43680af523f7e24a..20edeb3457921e5377c68a6e7d69681682fca135 100644 (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"
 
-/*
- *     Locking
- */
-static int shaper_lock(struct shaper *sh)
-{
-       /*
-        *      Lock in an interrupt must fail
-        */
-       while (test_and_set_bit(0, &sh->locked))
-       {
-               if (!in_interrupt())
-                       sleep_on(&sh->wait_queue);
-               else
-                       return 0;
-                       
-       }
-       return 1;
-}
-
 static void shaper_kick(struct shaper *sh);
 
-static void shaper_unlock(struct shaper *sh)
-{
-       clear_bit(0, &sh->locked);
-       wake_up(&sh->wait_queue);
-       shaper_kick(sh);
-}
-
 /*
  *     Compute clocks on a buffer
  */
@@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
  *     Throw a frame at a shaper.
  */
   
-static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
+
+static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+       struct shaper *shaper = dev->priv;
        struct sk_buff *ptr;
    
-       /*
-        *      Get ready to work on this shaper. Lock may fail if its
-        *      an interrupt and locked.
-        */
-        
-       if(!shaper_lock(shaper))
-               return -1;
+       if (down_trylock(&shaper->sem))
+               return -1;
+
        ptr=shaper->sendq.prev;
        
        /*
@@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
                 dev_kfree_skb(ptr);
                 shaper->stats.collisions++;
        }
-       shaper_unlock(shaper);
+       shaper_kick(shaper);
+       up(&shaper->sem);
        return 0;
 }
 
@@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
  
 static void shaper_timer(unsigned long data)
 {
-       struct shaper *sh=(struct shaper *)data;
-       shaper_kick(sh);
+       struct shaper *shaper = (struct shaper *)data;
+
+       if (!down_trylock(&shaper->sem)) {
+               shaper_kick(shaper);
+               up(&shaper->sem);
+       } else
+               mod_timer(&shaper->timer, jiffies);
 }
 
 /*
@@ -310,19 +287,6 @@ static void shaper_kick(struct shaper *shaper)
 {
        struct sk_buff *skb;
        
-       /*
-        *      Shaper unlock will kick
-        */
-        
-       if (test_and_set_bit(0, &shaper->locked))
-       {
-               if(sh_debug)
-                       printk("Shaper locked.\n");
-               mod_timer(&shaper->timer, jiffies);
-               return;
-       }
-
-               
        /*
         *      Walk the list (may be empty)
         */
@@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper)
         
        if(skb!=NULL)
                mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
-
-       clear_bit(0, &shaper->locked);
 }
 
 
@@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *shaper)
 static void shaper_flush(struct shaper *shaper)
 {
        struct sk_buff *skb;
-       if(!shaper_lock(shaper))
-       {
-               printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n");
-               return;
-       }
+
+       down(&shaper->sem);
        while((skb=skb_dequeue(&shaper->sendq))!=NULL)
                dev_kfree_skb(skb);
-       shaper_unlock(shaper);
+       shaper_kick(shaper);
+       up(&shaper->sem);
 }
 
 /*
@@ -426,13 +386,6 @@ static int shaper_close(struct net_device *dev)
  *     ARP and other resolutions and not before.
  */
 
-
-static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct shaper *sh=dev->priv;
-       return shaper_qframe(sh, skb);
-}
-
 static struct net_device_stats *shaper_get_stats(struct net_device *dev)
 {
        struct shaper *sh=dev->priv;
@@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev)
        init_timer(&sh->timer);
        sh->timer.function=shaper_timer;
        sh->timer.data=(unsigned long)sh;
-       init_waitqueue_head(&sh->wait_queue);
 }
 
 /*
index 54c52349adc53297971c6e04067d931aabf3148d..3be546439252332131fac6aca81cbdea71d9934a 100644 (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);
 }
 
-/**
- *     piix_init -
- *
- *     LOCKING:
- *
- *     RETURNS:
- *
- */
-
 static int __init piix_init(void)
 {
        int rc;
@@ -689,13 +680,6 @@ static int __init piix_init(void)
        return 0;
 }
 
-/**
- *     piix_exit -
- *
- *     LOCKING:
- *
- */
-
 static void __exit piix_exit(void)
 {
        pci_unregister_driver(&piix_pci_driver);
index 30a88f0e7bd61b4c6a1c2f5919da0c4df656e87e..21d194c6ace38b8595b4d6fb6fcfe8fe2cdf341b 100644 (file)
@@ -186,6 +186,28 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
        ata_wait_idle(ap);
 }
 
+
+/**
+ *     ata_tf_load - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller using MMIO
+ *     or PIO as indicated by the ATA_FLAG_MMIO flag.
+ *     Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ *     Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ *     hob_lbal, hob_lbam, and hob_lbah.
+ *
+ *     This function waits for idle (!BUSY and !DRQ) after writing
+ *     registers.  If the control register has a new value, this
+ *     function also waits for idle after writing control and before
+ *     writing the remaining registers.
+ *
+ *     May be used as the tf_load() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -195,11 +217,11 @@ void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
 }
 
 /**
- *     ata_exec_command - issue ATA command to host controller
+ *     ata_exec_command_pio - issue ATA command to host controller
  *     @ap: port to which command is being issued
  *     @tf: ATA taskfile register set
  *
- *     Issues PIO/MMIO write to ATA command register, with proper
+ *     Issues PIO write to ATA command register, with proper
  *     synchronization with interrupt handler / other threads.
  *
  *     LOCKING:
@@ -235,6 +257,18 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
        ata_pause(ap);
 }
 
+
+/**
+ *     ata_exec_command - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues PIO/MMIO write to ATA command register, with proper
+ *     synchronization with interrupt handler / other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -305,7 +339,7 @@ void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
 }
 
 /**
- *     ata_tf_read - input device's ATA taskfile shadow registers
+ *     ata_tf_read_pio - input device's ATA taskfile shadow registers
  *     @ap: Port from which input is read
  *     @tf: ATA taskfile register set for storing input
  *
@@ -368,6 +402,23 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
        }
 }
 
+
+/**
+ *     ata_tf_read - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf.
+ *
+ *     Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
+ *     is set, also reads the hob registers.
+ *
+ *     May be used as the tf_read() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -381,7 +432,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
  *     @ap: port where the device is
  *
  *     Reads ATA taskfile status register for currently-selected device
- *     and return it's value. This also clears pending interrupts
+ *     and return its value. This also clears pending interrupts
  *      from this device
  *
  *     LOCKING:
@@ -397,7 +448,7 @@ static u8 ata_check_status_pio(struct ata_port *ap)
  *     @ap: port where the device is
  *
  *     Reads ATA taskfile status register for currently-selected device
- *     via MMIO and return it's value. This also clears pending interrupts
+ *     via MMIO and return its value. This also clears pending interrupts
  *      from this device
  *
  *     LOCKING:
@@ -408,6 +459,20 @@ static u8 ata_check_status_mmio(struct ata_port *ap)
                return readb((void __iomem *) ap->ioaddr.status_addr);
 }
 
+
+/**
+ *     ata_check_status - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile status register for currently-selected device
+ *     and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *     May be used as the check_status() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_check_status(struct ata_port *ap)
 {
        if (ap->flags & ATA_FLAG_MMIO)
@@ -415,6 +480,20 @@ u8 ata_check_status(struct ata_port *ap)
        return ata_check_status_pio(ap);
 }
 
+
+/**
+ *     ata_altstatus - Read device alternate status reg
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile alternate status register for
+ *     currently-selected device and return its value.
+ *
+ *     Note: may NOT be used as the check_altstatus() entry in
+ *     ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_altstatus(struct ata_port *ap)
 {
        if (ap->ops->check_altstatus)
@@ -425,6 +504,20 @@ u8 ata_altstatus(struct ata_port *ap)
        return inb(ap->ioaddr.altstatus_addr);
 }
 
+
+/**
+ *     ata_chk_err - Read device error reg
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile error register for
+ *     currently-selected device and return its value.
+ *
+ *     Note: may NOT be used as the check_err() entry in
+ *     ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
 u8 ata_chk_err(struct ata_port *ap)
 {
        if (ap->ops->check_err)
@@ -873,10 +966,24 @@ void ata_dev_id_string(u16 *id, unsigned char *s,
        }
 }
 
+
+/**
+ *     ata_noop_dev_select - Select device 0/1 on ATA bus
+ *     @ap: ATA channel to manipulate
+ *     @device: ATA device (numbered from zero) to select
+ *
+ *     This function performs no actual function.
+ *
+ *     May be used as the dev_select() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     caller.
+ */
 void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
 {
 }
 
+
 /**
  *     ata_std_dev_select - Select device 0/1 on ATA bus
  *     @ap: ATA channel to manipulate
@@ -884,7 +991,9 @@ void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
  *
  *     Use the method defined in the ATA specification to
  *     make either device 0, or device 1, active on the
- *     ATA channel.
+ *     ATA channel.  Works with both PIO and MMIO.
+ *
+ *     May be used as the dev_select() entry in ata_port_operations.
  *
  *     LOCKING:
  *     caller.
@@ -1190,7 +1299,12 @@ err_out:
  *     ata_bus_probe - Reset and probe ATA bus
  *     @ap: Bus to probe
  *
+ *     Master ATA bus probing function.  Initiates a hardware-dependent
+ *     bus reset, then attempts to identify any devices found on
+ *     the bus.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
  *     Zero on success, non-zero on error.
@@ -1229,10 +1343,14 @@ err_out:
 }
 
 /**
- *     ata_port_probe -
- *     @ap:
+ *     ata_port_probe - Mark port as enabled
+ *     @ap: Port for which we indicate enablement
  *
- *     LOCKING:
+ *     Modify @ap data structure such that the system
+ *     thinks that the entire port is enabled.
+ *
+ *     LOCKING: host_set lock, or some other form of
+ *     serialization.
  */
 
 void ata_port_probe(struct ata_port *ap)
@@ -1241,10 +1359,15 @@ void ata_port_probe(struct ata_port *ap)
 }
 
 /**
- *     __sata_phy_reset -
- *     @ap:
+ *     __sata_phy_reset - Wake/reset a low-level SATA PHY
+ *     @ap: SATA port associated with target SATA PHY.
+ *
+ *     This function issues commands to standard SATA Sxxx
+ *     PHY registers, to wake up the phy (and device), and
+ *     clear any reset condition.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 void __sata_phy_reset(struct ata_port *ap)
@@ -1289,10 +1412,14 @@ void __sata_phy_reset(struct ata_port *ap)
 }
 
 /**
- *     __sata_phy_reset -
- *     @ap:
+ *     sata_phy_reset - Reset SATA bus.
+ *     @ap: SATA port associated with target SATA PHY.
+ *
+ *     This function resets the SATA bus, and then probes
+ *     the bus for devices.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 void sata_phy_reset(struct ata_port *ap)
@@ -1304,10 +1431,16 @@ void sata_phy_reset(struct ata_port *ap)
 }
 
 /**
- *     ata_port_disable -
- *     @ap:
+ *     ata_port_disable - Disable port.
+ *     @ap: Port to be disabled.
  *
- *     LOCKING:
+ *     Modify @ap data structure such that the system
+ *     thinks that the entire port is disabled, and should
+ *     never attempt to probe or communicate with devices
+ *     on this port.
+ *
+ *     LOCKING: host_set lock, or some other form of
+ *     serialization.
  */
 
 void ata_port_disable(struct ata_port *ap)
@@ -1416,7 +1549,10 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
  *     ata_set_mode - Program timings and issue SET FEATURES - XFER
  *     @ap: port on which timings will be programmed
  *
+ *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 static void ata_set_mode(struct ata_port *ap)
@@ -1467,7 +1603,10 @@ err_out:
  *     @tmout_pat: impatience timeout
  *     @tmout: overall timeout
  *
- *     LOCKING:
+ *     Sleep until ATA Status register bit BSY clears,
+ *     or a timeout occurs.
+ *
+ *     LOCKING: None.
  *
  */
 
@@ -1553,10 +1692,14 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
 }
 
 /**
- *     ata_bus_edd -
- *     @ap:
+ *     ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command.
+ *     @ap: Port to reset and probe
+ *
+ *     Use the EXECUTE DEVICE DIAGNOSTIC command to reset and
+ *     probe the bus.  Not often used these days.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  */
 
@@ -1633,8 +1776,8 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
  *     the device is ATA or ATAPI.
  *
  *     LOCKING:
- *     Inherited from caller.  Some functions called by this function
- *     obtain the host_set lock.
+ *     PCI/etc. bus probe sem.
+ *     Obtains host_set lock.
  *
  *     SIDE EFFECTS:
  *     Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
@@ -1876,7 +2019,11 @@ static int fgb(u32 bitmap)
  *     @xfer_mode_out: (output) SET FEATURES - XFER MODE code
  *     @xfer_shift_out: (output) bit shift that selects this mode
  *
+ *     Based on host and device capabilities, determine the
+ *     maximum transfer mode that is amenable to all.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
  *     Zero on success, negative on error.
@@ -1909,7 +2056,11 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
  *     @ap: Port associated with device @dev
  *     @dev: Device to which command will be sent
  *
+ *     Issue SET FEATURES - XFER MODE command to device @dev
+ *     on port @ap.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  */
 
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
@@ -1947,10 +2098,13 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
 }
 
 /**
- *     ata_sg_clean -
- *     @qc:
+ *     ata_sg_clean - Unmap DMA memory associated with command
+ *     @qc: Command containing DMA memory to be released
+ *
+ *     Unmap all mapped DMA memory associated with this command.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  */
 
 static void ata_sg_clean(struct ata_queued_cmd *qc)
@@ -1981,7 +2135,11 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
  *     ata_fill_sg - Fill PCI IDE PRD table
  *     @qc: Metadata associated with taskfile to be transferred
  *
+ *     Fill PCI IDE PRD (scatter-gather) table with segments
+ *     associated with the current disk command.
+ *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 static void ata_fill_sg(struct ata_queued_cmd *qc)
@@ -2028,7 +2186,13 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
  *     ata_check_atapi_dma - Check whether ATAPI DMA can be supported
  *     @qc: Metadata associated with taskfile to check
  *
+ *     Allow low-level driver to filter ATA PACKET commands, returning
+ *     a status indicating whether or not it is OK to use DMA for the
+ *     supplied PACKET command.
+ *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ *
  *     RETURNS: 0 when ATAPI DMA can be used
  *               nonzero otherwise
  */
@@ -2046,6 +2210,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
  *     ata_qc_prep - Prepare taskfile for submission
  *     @qc: Metadata associated with taskfile to be prepared
  *
+ *     Prepare ATA taskfile for submission.
+ *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  */
@@ -2057,6 +2223,32 @@ void ata_qc_prep(struct ata_queued_cmd *qc)
        ata_fill_sg(qc);
 }
 
+/**
+ *     ata_sg_init_one - Associate command with memory buffer
+ *     @qc: Command to be associated
+ *     @buf: Memory buffer
+ *     @buflen: Length of memory buffer, in bytes.
+ *
+ *     Initialize the data-related elements of queued_cmd @qc
+ *     to point to a single memory buffer, @buf of byte length @buflen.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+
+
+/**
+ *     ata_sg_init_one - Prepare a one-entry scatter-gather list.
+ *     @qc:  Queued command
+ *     @buf:  transfer buffer
+ *     @buflen:  length of buf
+ *
+ *     Builds a single-entry scatter-gather list to initiate a
+ *     transfer utilizing the specified buffer.
+ *
+ *     LOCKING:
+ */
 void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
 {
        struct scatterlist *sg;
@@ -2074,6 +2266,32 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
        sg->length = buflen;
 }
 
+/**
+ *     ata_sg_init - Associate command with scatter-gather table.
+ *     @qc: Command to be associated
+ *     @sg: Scatter-gather table.
+ *     @n_elem: Number of elements in s/g table.
+ *
+ *     Initialize the data-related elements of queued_cmd @qc
+ *     to point to a scatter-gather table @sg, containing @n_elem
+ *     elements.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+
+/**
+ *     ata_sg_init - Assign a scatter gather list to a queued command
+ *     @qc:  Queued command
+ *     @sg:  Scatter-gather list
+ *     @n_elem:  length of sg list
+ *
+ *     Attaches a scatter-gather list to a queued command.
+ *
+ *     LOCKING:
+ */
+
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem)
 {
@@ -2083,14 +2301,16 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
 }
 
 /**
- *     ata_sg_setup_one -
- *     @qc:
+ *     ata_sg_setup_one - DMA-map the memory buffer associated with a command.
+ *     @qc: Command with memory buffer to be mapped.
+ *
+ *     DMA-map the memory buffer associated with queued_cmd @qc.
  *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
- *
+ *     Zero on success, negative on error.
  */
 
 static int ata_sg_setup_one(struct ata_queued_cmd *qc)
@@ -2115,13 +2335,16 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
 }
 
 /**
- *     ata_sg_setup -
- *     @qc:
+ *     ata_sg_setup - DMA-map the scatter-gather table associated with a command.
+ *     @qc: Command with scatter-gather table to be mapped.
+ *
+ *     DMA-map the scatter-gather table associated with queued_cmd @qc.
  *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
+ *     Zero on success, negative on error.
  *
  */
 
@@ -2151,6 +2374,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  *
  *     RETURNS:
  *
@@ -2198,6 +2422,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  */
 
 static void ata_pio_complete (struct ata_port *ap)
@@ -2240,6 +2465,18 @@ static void ata_pio_complete (struct ata_port *ap)
        ata_qc_complete(qc, drv_stat);
 }
 
+
+/**
+ *     swap_buf_le16 -
+ *     @buf:  Buffer to swap
+ *     @buf_words:  Number of 16-bit words in buffer.
+ *
+ *     Swap halves of 16-bit words if needed to convert from
+ *     little-endian byte order to native cpu byte order, or
+ *     vice-versa.
+ *
+ *     LOCKING:
+ */
 void swap_buf_le16(u16 *buf, unsigned int buf_words)
 {
 #ifdef __BIG_ENDIAN
@@ -2415,6 +2652,7 @@ err_out:
  *     @ap:
  *
  *     LOCKING:
+ *     None.  (executing in kernel thread context)
  */
 
 static void ata_pio_block(struct ata_port *ap)
@@ -2583,6 +2821,7 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
  *     transaction completed successfully.
  *
  *     LOCKING:
+ *     Inherited from SCSI layer (none, can sleep)
  */
 
 static void ata_qc_timeout(struct ata_queued_cmd *qc)
@@ -2692,6 +2931,7 @@ out:
  *     @dev: Device from whom we request an available command structure
  *
  *     LOCKING:
+ *     None.
  */
 
 static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
@@ -2717,6 +2957,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
  *     @dev: Device from whom we request an available command structure
  *
  *     LOCKING:
+ *     None.
  */
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
@@ -2781,6 +3022,7 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc)
  *     in case something prevents using it.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 void ata_qc_free(struct ata_queued_cmd *qc)
@@ -2794,9 +3036,13 @@ void ata_qc_free(struct ata_queued_cmd *qc)
 /**
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
- *     @drv_stat: ATA status register contents
+ *     @drv_stat: ATA Status register contents
+ *
+ *     Indicate to the mid and upper layers that an ATA
+ *     command has completed, with either an ok or not-ok status.
  *
  *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
  *
  */
 
@@ -2892,6 +3138,7 @@ err_out:
        return -1;
 }
 
+
 /**
  *     ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
  *     @qc: command to issue to device
@@ -2901,6 +3148,8 @@ err_out:
  *     classes called "protocols", and issuing each type of protocol
  *     is slightly different.
  *
+ *     May be used as the qc_issue() entry in ata_port_operations.
+ *
  *     LOCKING:
  *     spin_lock_irqsave(host_set lock)
  *
@@ -2958,7 +3207,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 }
 
 /**
- *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *     ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
  *     @qc: Info associated with this ATA transaction.
  *
  *     LOCKING:
@@ -3065,6 +3314,18 @@ static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
             ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+
+/**
+ *     ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Writes the ATA_DMA_START flag to the DMA command register.
+ *
+ *     May be used as the bmdma_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_start(struct ata_queued_cmd *qc)
 {
        if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3073,6 +3334,20 @@ void ata_bmdma_start(struct ata_queued_cmd *qc)
                ata_bmdma_start_pio(qc);
 }
 
+
+/**
+ *     ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Writes address of PRD table to device's PRD Table Address
+ *     register, sets the DMA control register, and calls
+ *     ops->exec_command() to start the transfer.
+ *
+ *     May be used as the bmdma_setup() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
 void ata_bmdma_setup(struct ata_queued_cmd *qc)
 {
        if (qc->ap->flags & ATA_FLAG_MMIO)
@@ -3081,6 +3356,19 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
                ata_bmdma_setup_pio(qc);
 }
 
+
+/**
+ *     ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clear interrupt and error flags in DMA status register.
+ *
+ *     May be used as the irq_clear() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_irq_clear(struct ata_port *ap)
 {
     if (ap->flags & ATA_FLAG_MMIO) {
@@ -3093,6 +3381,19 @@ void ata_bmdma_irq_clear(struct ata_port *ap)
 
 }
 
+
+/**
+ *     ata_bmdma_status - Read PCI IDE BMDMA status
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Read and return BMDMA status register.
+ *
+ *     May be used as the bmdma_status() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 u8 ata_bmdma_status(struct ata_port *ap)
 {
        u8 host_stat;
@@ -3104,6 +3405,19 @@ u8 ata_bmdma_status(struct ata_port *ap)
        return host_stat;
 }
 
+
+/**
+ *     ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Clears the ATA_DMA_START flag in the dma control register
+ *
+ *     May be used as the bmdma_stop() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
 void ata_bmdma_stop(struct ata_port *ap)
 {
        if (ap->flags & ATA_FLAG_MMIO) {
@@ -3203,13 +3517,18 @@ idle_irq:
 
 /**
  *     ata_interrupt - Default ATA host interrupt handler
- *     @irq: irq line
- *     @dev_instance: pointer to our host information structure
+ *     @irq: irq line (unused)
+ *     @dev_instance: pointer to our ata_host_set information structure
  *     @regs: unused
  *
+ *     Default interrupt handler for PCI IDE devices.  Calls
+ *     ata_host_intr() for each port that is not disabled.
+ *
  *     LOCKING:
+ *     Obtains host_set lock during operation.
  *
  *     RETURNS:
+ *     IRQ_NONE or IRQ_HANDLED.
  *
  */
 
@@ -3302,6 +3621,19 @@ err_out:
        ata_qc_complete(qc, ATA_ERR);
 }
 
+
+/**
+ *     ata_port_start - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.  Allocates space for PRD table.
+ *
+ *     May be used as the port_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ */
+
 int ata_port_start (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -3315,6 +3647,18 @@ int ata_port_start (struct ata_port *ap)
        return 0;
 }
 
+
+/**
+ *     ata_port_stop - Undo ata_port_start()
+ *     @ap: Port to shut down
+ *
+ *     Frees the PRD table.
+ *
+ *     May be used as the port_stop() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ */
+
 void ata_port_stop (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -3357,7 +3701,11 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
  *     @ent: Probe information provided by low-level driver
  *     @port_no: Port number associated with this ata_port
  *
+ *     Initialize a new ata_port structure, and its associated
+ *     scsi_host.
+ *
  *     LOCKING:
+ *     Inherited from caller.
  *
  */
 
@@ -3412,9 +3760,13 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
  *     @host_set: Collections of ports to which we add
  *     @port_no: Port number associated with this host
  *
+ *     Attach low-level ATA driver to system.
+ *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
+ *     New ata_port on success, for NULL on error.
  *
  */
 
@@ -3447,12 +3799,22 @@ err_out:
 }
 
 /**
- *     ata_device_add -
- *     @ent:
+ *     ata_device_add - Register hardware device with ATA and SCSI layers
+ *     @ent: Probe information describing hardware device to be registered
+ *
+ *     This function processes the information provided in the probe
+ *     information struct @ent, allocates the necessary ATA and SCSI
+ *     host information structures, initializes them, and registers
+ *     everything with requisite kernel subsystems.
+ *
+ *     This function requests irqs, probes the ATA bus, and probes
+ *     the SCSI bus.
  *
  *     LOCKING:
+ *     PCI/etc. bus probe sem.
  *
  *     RETURNS:
+ *     Number of ports registered.  Zero on error (no ports registered).
  *
  */
 
@@ -3604,7 +3966,15 @@ int ata_scsi_release(struct Scsi_Host *host)
 /**
  *     ata_std_ports - initialize ioaddr with standard port offsets.
  *     @ioaddr: IO address structure to be initialized
+ *
+ *     Utility function which initializes data_addr, error_addr,
+ *     feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
+ *     device_addr, status_addr, and command_addr to standard offsets
+ *     relative to cmd_addr.
+ *
+ *     Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
  */
+
 void ata_std_ports(struct ata_ioports *ioaddr)
 {
        ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
@@ -3646,6 +4016,20 @@ ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
        return probe_ent;
 }
 
+
+
+/**
+ *     ata_pci_init_native_mode - Initialize native-mode driver
+ *     @pdev:  pci device to be initialized
+ *     @port:  array[2] of pointers to port info structures.
+ *
+ *     Utility function which allocates and initializes an
+ *     ata_probe_ent structure for a standard dual-port
+ *     PIO-based IDE controller.  The returned ata_probe_ent
+ *     structure can be passed to ata_device_add().  The returned
+ *     ata_probe_ent structure should then be freed with kfree().
+ */
+
 #ifdef CONFIG_PCI
 struct ata_probe_ent *
 ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
@@ -3727,10 +4111,19 @@ ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port,
  *     @port_info: Information from low-level host driver
  *     @n_ports: Number of ports attached to host controller
  *
+ *     This is a helper function which can be called from a driver's
+ *     xxx_init_one() probe function if the hardware uses traditional
+ *     IDE taskfile registers.
+ *
+ *     This function calls pci_enable_device(), reserves its register
+ *     regions, sets the dma mask, enables bus master mode, and calls
+ *     ata_device_add()
+ *
  *     LOCKING:
  *     Inherited from PCI layer (may sleep).
  *
  *     RETURNS:
+ *     Zero on success, negative on errno-based value on error.
  *
  */
 
@@ -3949,15 +4342,6 @@ int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits)
 #endif /* CONFIG_PCI */
 
 
-/**
- *     ata_init -
- *
- *     LOCKING:
- *
- *     RETURNS:
- *
- */
-
 static int __init ata_init(void)
 {
        ata_wq = create_workqueue("ata");
index 416ba67ba9ee37b1fa0b7cad9ca0bc431e973017..7a4adc4c8f09d6ef9cdb7460f4e6846d0def4647 100644 (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.
  *     @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
  *     @buflen: Response buffer length.
index 579448222d691d77bd656a35fa536d58be3ad417..3c97aa45772dc4aea2b7c4dbd759e76fa46c1745 100644 (file)
@@ -507,6 +507,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        int ret, i;
        unsigned int id, lun;
        unsigned long serial;
+       unsigned long flags;
 
        if (!CMD_SP(cmd))
                return FAILED;
@@ -519,7 +520,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 
        /* Check active list for command command. */
        spin_unlock_irq(ha->host->host_lock);
-       spin_lock(&ha->hardware_lock);
+       spin_lock_irqsave(&ha->hardware_lock, flags);
        for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
                sp = ha->outstanding_cmds[i];
 
@@ -534,7 +535,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                    sp->state));
                DEBUG3(qla2x00_print_scsi_cmd(cmd);)
 
-               spin_unlock(&ha->hardware_lock);
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
                if (qla2x00_abort_command(ha, sp)) {
                        DEBUG2(printk("%s(%ld): abort_command "
                            "mbx failed.\n", __func__, ha->host_no));
@@ -543,20 +544,19 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                            "mbx success.\n", __func__, ha->host_no));
                        ret = SUCCESS;
                }
-               spin_lock(&ha->hardware_lock);
+               spin_lock_irqsave(&ha->hardware_lock, flags);
 
                break;
        }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        /* Wait for the command to be returned. */
        if (ret == SUCCESS) {
-               spin_unlock(&ha->hardware_lock);
                if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
                        qla_printk(KERN_ERR, ha, 
                            "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
                            "%x.\n", ha->host_no, id, lun, serial, ret);
                }
-               spin_lock(&ha->hardware_lock);
        }
        spin_lock_irq(ha->host->host_lock);
 
@@ -588,6 +588,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
        int     status;
        srb_t           *sp;
        struct scsi_cmnd *cmd;
+       unsigned long flags;
 
        status = 0;
 
@@ -596,11 +597,11 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
         * array
         */
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-               spin_lock(&ha->hardware_lock);
+               spin_lock_irqsave(&ha->hardware_lock, flags);
                sp = ha->outstanding_cmds[cnt];
                if (sp) {
                        cmd = sp->cmd;
-                       spin_unlock(&ha->hardware_lock);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
                        if (cmd->device->id == t) {
                                if (!qla2x00_eh_wait_on_command(ha, cmd)) {
                                        status = 1;
@@ -608,7 +609,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
                                }
                        }
                } else {
-                       spin_unlock(&ha->hardware_lock);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
                }
        }
        return (status);
@@ -740,6 +741,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
        int     status;
        srb_t           *sp;
        struct scsi_cmnd *cmd;
+       unsigned long flags;
 
        status = 1;
 
@@ -748,17 +750,17 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
         * array
         */
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-               spin_lock(&ha->hardware_lock);
+               spin_lock_irqsave(&ha->hardware_lock, flags);
                sp = ha->outstanding_cmds[cnt];
                if (sp) {
                        cmd = sp->cmd;
-                       spin_unlock(&ha->hardware_lock);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
                        status = qla2x00_eh_wait_on_command(ha, cmd);
                        if (status == 0)
                                break;
                }
                else {
-                       spin_unlock(&ha->hardware_lock);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
                }
        }
        return (status);
index cca772624ae701ea8278ce770c10c8617e710c5e..8d0d302844a1d5a5c3a9df8530e1be0974f5c4d6 100644 (file)
@@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        if (!starget)
                return ERR_PTR(-ENOMEM);
 
+       get_device(&starget->dev);
        down(&shost->scan_mutex);
        res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
        if (res != SCSI_SCAN_LUN_PRESENT)
index 5d2ceb623e6fcebe34319cac6c4bcd72d2c78739..1f985327b0d485ec8b4648073ef39a80d25d28f1 100644 (file)
@@ -234,7 +234,7 @@ static inline const char *siu_type_name(struct uart_port *port)
                return "DSIU";
        }
 
-       return "unknown";
+       return NULL;
 }
 
 static unsigned int siu_tx_empty(struct uart_port *port)
@@ -482,9 +482,6 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        struct uart_port *port;
        uint8_t iir, lsr;
 
-       if (dev_id == NULL)
-               return IRQ_NONE;
-
        port = (struct uart_port *)dev_id;
 
        iir = siu_read(port, UART_IIR);
@@ -507,6 +504,9 @@ static int siu_startup(struct uart_port *port)
 {
        int retval;
 
+       if (port->membase == NULL)
+               return -ENODEV;
+
        siu_clear_fifo(port);
 
        (void)siu_read(port, UART_LSR);
@@ -545,9 +545,6 @@ static void siu_shutdown(struct uart_port *port)
        unsigned long flags;
        uint8_t lcr;
 
-       if (port->membase == NULL)
-               return;
-
        siu_write(port, UART_IER, 0);
 
        spin_lock_irqsave(&port->lock, flags);
@@ -802,53 +799,6 @@ static int siu_init_ports(void)
 
 #ifdef CONFIG_SERIAL_VR41XX_CONSOLE
 
-static void early_set_termios(struct uart_port *port, struct termios *new,
-                              struct termios *old)
-{
-       tcflag_t c_cflag;
-       uint8_t lcr;
-       unsigned int baud, quot;
-
-       c_cflag = new->c_cflag;
-       switch (c_cflag & CSIZE) {
-       case CS5:
-               lcr = UART_LCR_WLEN5;
-               break;
-       case CS6:
-               lcr = UART_LCR_WLEN6;
-               break;
-       case CS7:
-               lcr = UART_LCR_WLEN7;
-               break;
-       default:
-               lcr = UART_LCR_WLEN8;
-               break;
-       }
-
-       if (c_cflag & CSTOPB)
-               lcr |= UART_LCR_STOP;
-       if (c_cflag & PARENB)
-               lcr |= UART_LCR_PARITY;
-       if ((c_cflag & PARODD) != PARODD)
-               lcr |= UART_LCR_EPAR;
-       if (c_cflag & CMSPAR)
-               lcr |= UART_LCR_SPAR;
-
-       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
-
-       siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
-
-       siu_write(port, UART_DLL, (uint8_t)quot);
-       siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
-
-       siu_write(port, UART_LCR, lcr);
-}
-
-static struct uart_ops early_uart_ops = {
-       .set_termios    = early_set_termios,
-};
-
 #define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
 
 static void wait_for_xmitr(struct uart_port *port)
@@ -915,7 +865,7 @@ static int siu_console_setup(struct console *con, char *options)
        if (port->membase == NULL) {
                if (port->mapbase == 0)
                        return -ENODEV;
-               port->membase = (unsigned char __iomem *)KSEG1ADDR(port->mapbase);
+               port->membase = ioremap(port->mapbase, siu_port_size(port));
        }
 
        vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
@@ -949,7 +899,7 @@ static int __devinit siu_console_init(void)
 
        for (i = 0; i < num; i++) {
                port = &siu_uart_ports[i];
-               port->ops = &early_uart_ops;
+               port->ops = &siu_uart_ops;
        }
 
        register_console(&siu_console);
@@ -994,8 +944,10 @@ static int siu_probe(struct device *dev)
                port->dev = dev;
 
                retval = uart_add_one_port(&siu_uart_driver, port);
-               if (retval)
+               if (retval < 0) {
+                       port->dev = NULL;
                        break;
+               }
        }
 
        if (i == 0 && retval < 0) {
index 4ab50009291d91fb1a54be002e6c9064607da6b6..4d0c9e65cd039e87612dedec707b4d0f4baf0675 100644 (file)
@@ -290,32 +290,30 @@ static ssize_t show_modalias(struct device *dev, char *buf)
 {
        struct usb_interface *intf;
        struct usb_device *udev;
+       int len;
 
        intf = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
-       if (udev->descriptor.bDeviceClass == 0) {
-               struct usb_host_interface *alt = intf->cur_altsetting;
 
-               return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X\n",
+       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,
+                              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 sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*\n",
-                              le16_to_cpu(udev->descriptor.idVendor),
-                              le16_to_cpu(udev->descriptor.idProduct),
-                              le16_to_cpu(udev->descriptor.bcdDevice),
-                              udev->descriptor.bDeviceClass,
-                              udev->descriptor.bDeviceSubClass,
-                              udev->descriptor.bDeviceProtocol);
+               return len + sprintf(buf, "*isc*ip*\n");
        }
-
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
index 869ff73690acebf04655691c4edc01a017a6abe4..2d8bd9dcc6edae2b8d1c4ea112f0c5e66cddc149 100644 (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_VOLITO     0x0060
 #define USB_DEVICE_ID_WACOM_PTU                0x0003
+#define USB_DEVICE_ID_WACOM_INTUOS3    0x00B0
+#define USB_DEVICE_ID_WACOM_CINTIQ     0x003F
 
 #define USB_VENDOR_ID_KBGEAR           0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
@@ -1401,6 +1403,7 @@ void hid_init_reports(struct hid_device *hid)
 
 #define USB_VENDOR_ID_DELORME          0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
@@ -1412,6 +1415,12 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_BTC              0x046e
 #define USB_DEVICE_ID_BTC_KEYBOARD     0x5303
 
+#define USB_VENDOR_ID_VERNIER          0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP     0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
+
 
 /*
  * Alphabetically sorted blacklist by quirk type.
@@ -1437,6 +1446,7 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
@@ -1456,6 +1466,10 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
@@ -1481,6 +1495,10 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 
diff --git a/drivers/usb/media/pwc/ChangeLog b/drivers/usb/media/pwc/ChangeLog
deleted file mode 100644 (file)
index b2eb71a..0000000
+++ /dev/null
@@ -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.
index 85476e76b244c4b166042dfa5e2bdbad368fdc82..4cbb408af72749b5f2f432c10bac69ebe4e2e1b7 100644 (file)
@@ -2765,7 +2765,7 @@ static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf)
                        }
                        /* expect bcdVersion 1.0, ignore */
                        if (memcmp(&desc->bGUID, blan_guid, 16)
-                                   && memcmp(&desc->bGUID, blan_guid, 16) ) {
+                                   && memcmp(&desc->bGUID, safe_guid, 16) ) {
                                /* hey, this one might _really_ be MDLM! */
                                dev_dbg (&intf->dev, "MDLM guid\n");
                                goto bad_desc;
index bc798edf0358828f83ab486bde704d52f9ee1fbf..9438909e87a52bbd7c4ef625ce2f678403648341 100644 (file)
@@ -455,6 +455,17 @@ config USB_SERIAL_XIRCOM
          To compile this driver as a module, choose M here: the
          module will be called keyspan_pda.
 
+config USB_SERIAL_OPTION
+       tristate "USB Option PCMCIA serial driver"
+       depends on USB_SERIAL && USB_OHCI_HCD && PCCARD
+       help
+         Say Y here if you want to use an Option card. This is a
+         GSM card, controlled by three serial ports which are connected
+         via an OHCI adapter located on a PC card.
+
+         To compile this driver as a module, choose M here: the
+         module will be called option.
+
 config USB_SERIAL_OMNINET
        tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
        depends on USB_SERIAL && EXPERIMENTAL
index d56ff6d86cce220860ae63ca7bfbab532956847b..6c7cdcc99a9e2da387a12a352947a22e7ef08d6b 100644 (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_MCT_U232)              += mct_u232.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
+obj-$(CONFIG_USB_SERIAL_OPTION)                        += option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)                        += pl2303.o
 obj-$(CONFIG_USB_SERIAL_SAFE)                  += safe_serial.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
index 7e9bb63eb466d3e09e608b22b4073448845e6802..4ace9964fc6bd36a22c0a82da2fc432be4eef5f7 100644 (file)
@@ -7,6 +7,14 @@
  *     modify it under the terms of the GNU General Public License version
  *     2 as published by the Free Software Foundation.
  *
+ * Support to set flow control line levels using TIOCMGET and TIOCMSET
+ * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
+ * control thanks to Munir Nassar nassarmu@real-time.com
+ *
+ * Outstanding Issues:
+ *  Buffers are not flushed when the port is opened.
+ *  Multiple calls to write() may fail with "Resource temporarily unavailable"
+ *
  */
 
 #include <linux/config.h>
@@ -24,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.03"
+#define DRIVER_VERSION "v0.04"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -35,6 +43,9 @@ static void cp2101_cleanup(struct usb_serial_port*);
 static void cp2101_close(struct usb_serial_port*, struct file*);
 static void cp2101_get_termios(struct usb_serial_port*);
 static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
+static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
+               unsigned int, unsigned int);
 static void cp2101_break_ctl(struct usb_serial_port*, int);
 static int cp2101_startup (struct usb_serial *);
 static void cp2101_shutdown(struct usb_serial*);
@@ -43,9 +54,10 @@ static void cp2101_shutdown(struct usb_serial*);
 static int debug;
 
 static struct usb_device_id id_table [] = {
-       {USB_DEVICE(0x10c4, 0xea60) },  /*Silicon labs factory default*/
-       {USB_DEVICE(0x10ab, 0x10c5) },  /*Siemens MC60 Cable*/
-       { } /* Terminating Entry*/
+       { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
+       { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
+       { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
+       { } /* Terminating Entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table);
@@ -70,32 +82,35 @@ static struct usb_serial_device_type cp2101_device = {
        .close                  = cp2101_close,
        .break_ctl              = cp2101_break_ctl,
        .set_termios            = cp2101_set_termios,
+       .tiocmget               = cp2101_tiocmget,
+       .tiocmset               = cp2101_tiocmset,
        .attach                 = cp2101_startup,
        .shutdown               = cp2101_shutdown,
 };
 
-/*Config request types*/
+/* Config request types */
 #define REQTYPE_HOST_TO_DEVICE 0x41
 #define REQTYPE_DEVICE_TO_HOST 0xc1
 
-/*Config SET requests. To GET, add 1 to the request number*/
-#define CP2101_UART            0x00    /*Enable / Disable*/
-#define CP2101_BAUDRATE                0x01    /*(BAUD_RATE_GEN_FREQ / baudrate)*/
-#define CP2101_BITS            0x03    /*0x(0)(data bits)(parity)(stop bits)*/
-#define CP2101_BREAK           0x05    /*On / Off*/
-#define CP2101_DTRRTS          0x07    /*101 / 202  ???*/
-#define CP2101_CONFIG_16       0x13    /*16 bytes of config data ???*/
-#define CP2101_CONFIG_6                0x19    /*6 bytes of config data ???*/
+/* Config SET requests. To GET, add 1 to the request number */
+#define CP2101_UART            0x00    /* Enable / Disable */
+#define CP2101_BAUDRATE                0x01    /* (BAUD_RATE_GEN_FREQ / baudrate) */
+#define CP2101_BITS            0x03    /* 0x(0)(databits)(parity)(stopbits) */
+#define CP2101_BREAK           0x05    /* On / Off */
+#define CP2101_CONTROL         0x07    /* Flow control line states */
+#define CP2101_MODEMCTL                0x13    /* Modem controls */
+#define CP2101_CONFIG_6                0x19    /* 6 bytes of config data ??? */
 
-/*CP2101_UART*/
+/* CP2101_UART */
 #define UART_ENABLE            0x0001
 #define UART_DISABLE           0x0000
 
-/*CP2101_BAUDRATE*/
+/* CP2101_BAUDRATE */
 #define BAUD_RATE_GEN_FREQ     0x384000
 
-/*CP2101_BITS*/
+/* CP2101_BITS */
 #define BITS_DATA_MASK         0X0f00
+#define BITS_DATA_5            0X0500
 #define BITS_DATA_6            0X0600
 #define BITS_DATA_7            0X0700
 #define BITS_DATA_8            0X0800
@@ -112,64 +127,137 @@ static struct usb_serial_device_type cp2101_device = {
 #define BITS_STOP_1            0x0000
 #define BITS_STOP_1_5          0x0001
 #define BITS_STOP_2            0x0002
+
+/* CP2101_BREAK */
 #define BREAK_ON               0x0000
 #define BREAK_OFF              0x0001
 
+/* CP2101_CONTROL */
+#define CONTROL_DTR            0x0001
+#define CONTROL_RTS            0x0002
+#define CONTROL_CTS            0x0010
+#define CONTROL_DSR            0x0020
+#define CONTROL_RING           0x0040
+#define CONTROL_DCD            0x0080
+#define CONTROL_WRITE_DTR      0x0100
+#define CONTROL_WRITE_RTS      0x0200
 
-static int cp2101_get_config(struct usb_serial_port* port, u8 request)
+/*
+ * cp2101_get_config
+ * Reads from the CP2101 configuration registers
+ * 'size' is specified in bytes.
+ * 'data' is a pointer to a pre-allocated array of integers large
+ * enough to hold 'size' bytes (with 4 bytes to each integer)
+ */
+static int cp2101_get_config(struct usb_serial_port* port, u8 request,
+               unsigned int *data, int size)
 {
        struct usb_serial *serial = port->serial;
-       unsigned char buf[4];
-       unsigned int value;
-       int result, i;
+       u32 *buf;
+       int result, i, length;
+
+       /* 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*/
+       /* For get requests, the request number must be incremented */
        request++;
 
-       /*Issue the request, attempting to read 4 bytes*/
+       /* Issue the request, attempting to read 'size' bytes */
        result = usb_control_msg (serial->dev,usb_rcvctrlpipe (serial->dev, 0),
                                request, REQTYPE_DEVICE_TO_HOST, 0x0000,
-                               0, buf, 4, 300);
+                               0, buf, size, 300);
 
-       if (result < 0) {
-               dev_err(&port->dev, "%s - Unable to send config request, "
-                               "request=0x%x result=%d\n",
-                               __FUNCTION__, request, result);
-               return result;
-       }
+       /* Convert data into an array of integers */
+       for (i=0; i<length; i++)
+               data[i] = le32_to_cpu(buf[i]);
 
-       /*Assemble each byte read into an integer value*/
-       value = 0;
-       for (i=0; i<4 && i<result; i++)
-               value |= (buf[i] << (i * 8));
+       kfree(buf);
 
-       dbg( " %s - request=0x%x result=%d value=0x%x",
-                       __FUNCTION__, request, result, value);
+       if (result != size) {
+               dev_err(&port->dev, "%s - Unable to send config request, "
+                               "request=0x%x size=%d result=%d\n",
+                               __FUNCTION__, request, size, result);
+               return -EPROTO;
+       }
 
-       return value;
+       return 0;
 }
 
-static int cp2101_set_config(struct usb_serial_port* port, u8 request, u16 value)
+/*
+ * 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;
-       int result;
-       result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                       request, REQTYPE_HOST_TO_DEVICE, value,
-                       0, NULL, 0, 300);
+       u32 *buf;
+       int result, i, length;
 
-       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;
+       /* 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);
        }
 
-       dbg(" %s - request=0x%x value=0x%x result=%d",
-                       __FUNCTION__, request, value, result);
+       kfree(buf);
+
+       if ((size > 2 && result != size) || result < 0) {
+               dev_err(&port->dev, "%s - Unable to send request, "
+                               "request=0x%x size=%d result=%d\n",
+                               __FUNCTION__, request, size, result);
+               return -EPROTO;
+       }
 
+       /* Single data value */
+       result = usb_control_msg (serial->dev,
+                       usb_sndctrlpipe(serial->dev, 0),
+                       request, REQTYPE_HOST_TO_DEVICE, data[0],
+                       0, NULL, 0, 300);
        return 0;
 }
 
+/*
+ * cp2101_set_config_single
+ * Convenience function for calling cp2101_set_config on single data values
+ * without requiring an integer pointer
+ */
+static inline int cp2101_set_config_single(struct usb_serial_port* port,
+               u8 request, unsigned int data)
+{
+       return cp2101_set_config(port, request, &data, 2);
+}
+
 static int cp2101_open (struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
@@ -177,7 +265,7 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (cp2101_set_config(port, CP2101_UART, UART_ENABLE)) {
+       if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
                dev_err(&port->dev, "%s - Unable to enable UART\n",
                                __FUNCTION__);
                return -EPROTO;
@@ -198,9 +286,12 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
                return result;
        }
 
-       /*Configure the termios structure*/
+       /* Configure the termios structure */
        cp2101_get_termios(port);
 
+       /* Set the DTR and RTS pins low */
+       cp2101_tiocmset(port, NULL, TIOCM_DTR | TIOCM_RTS, 0);
+
        return 0;
 }
 
@@ -228,16 +319,18 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
 
-       cp2101_set_config(port, CP2101_UART, UART_DISABLE);
+       cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
 }
 
-/* cp2101_get_termios*/
-/* Reads the baud rate, data bits, parity and stop bits from the device*/
-/* Corrects any unsupported values*/
-/* Configures the termios structure to reflect the state of the device*/
+/*
+ * cp2101_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+ * from the device, corrects any unsupported values, and configures the
+ * termios structure to reflect the state of the device
+ */
 static void cp2101_get_termios (struct usb_serial_port *port)
 {
-       unsigned int cflag;
+       unsigned int cflag, modem_ctl[4];
        int baud;
        int bits;
 
@@ -249,15 +342,16 @@ static void cp2101_get_termios (struct usb_serial_port *port)
        }
        cflag = port->tty->termios->c_cflag;
 
-       baud = cp2101_get_config(port, CP2101_BAUDRATE);
-       /*Convert to baudrate*/
+       cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
+       /* Convert to baudrate */
        if (baud)
                baud = BAUD_RATE_GEN_FREQ / baud;
 
        dbg("%s - baud rate = %d", __FUNCTION__, baud);
        cflag &= ~CBAUD;
        switch (baud) {
-               /* The baud rates which are commented out below
+               /*
+                * The baud rates which are commented out below
                 * appear to be supported by the device
                 * but are non-standard
                 */
@@ -284,14 +378,18 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                        dbg("%s - Baud rate is not supported, "
                                        "using 9600 baud", __FUNCTION__);
                        cflag |= B9600;
-                       cp2101_set_config(port, CP2101_BAUDRATE,
+                       cp2101_set_config_single(port, CP2101_BAUDRATE,
                                        (BAUD_RATE_GEN_FREQ/9600));
                        break;
        }
 
-       bits = cp2101_get_config(port, CP2101_BITS);
+       cp2101_get_config(port, CP2101_BITS, &bits, 2);
        cflag &= ~CSIZE;
        switch(bits & BITS_DATA_MASK) {
+               case BITS_DATA_5:
+                       dbg("%s - data bits = 5", __FUNCTION__);
+                       cflag |= CS5;
+                       break;
                case BITS_DATA_6:
                        dbg("%s - data bits = 6", __FUNCTION__);
                        cflag |= CS6;
@@ -310,7 +408,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                        cflag |= CS8;
                        bits &= ~BITS_DATA_MASK;
                        bits |= BITS_DATA_8;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
                default:
                        dbg("%s - Unknown number of data bits, "
@@ -318,7 +416,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                        cflag |= CS8;
                        bits &= ~BITS_DATA_MASK;
                        bits |= BITS_DATA_8;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
        }
 
@@ -341,21 +439,21 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                                        "disabling parity)", __FUNCTION__);
                        cflag &= ~PARENB;
                        bits &= ~BITS_PARITY_MASK;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
                case BITS_PARITY_SPACE:
                        dbg("%s - parity = SPACE (not supported, "
                                        "disabling parity)", __FUNCTION__);
                        cflag &= ~PARENB;
                        bits &= ~BITS_PARITY_MASK;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
                default:
                        dbg("%s - Unknown parity mode, "
                                        "disabling parity", __FUNCTION__);
                        cflag &= ~PARENB;
                        bits &= ~BITS_PARITY_MASK;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
        }
 
@@ -366,9 +464,9 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                        break;
                case BITS_STOP_1_5:
                        dbg("%s - stop bits = 1.5 (not supported, "
-                                       "using 1 stop bit", __FUNCTION__);
+                                       "using 1 stop bit)", __FUNCTION__);
                        bits &= ~BITS_STOP_MASK;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
                case BITS_STOP_2:
                        dbg("%s - stop bits = 2", __FUNCTION__);
@@ -378,10 +476,19 @@ static void cp2101_get_termios (struct usb_serial_port *port)
                        dbg("%s - Unknown number of stop bits, "
                                        "using 1 stop bit", __FUNCTION__);
                        bits &= ~BITS_STOP_MASK;
-                       cp2101_set_config(port, CP2101_BITS, bits);
+                       cp2101_set_config(port, CP2101_BITS, &bits, 2);
                        break;
        }
 
+       cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+       if (modem_ctl[0] & 0x0008) {
+               dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+               cflag |= CRTSCTS;
+       } else {
+               dbg("%s - flow control = NONE", __FUNCTION__);
+               cflag &= ~CRTSCTS;
+       }
+
        port->tty->termios->c_cflag = cflag;
 }
 
@@ -389,8 +496,8 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                struct termios *old_termios)
 {
        unsigned int cflag, old_cflag=0;
-       int baud=0;
-       int bits;
+       int baud=0, bits;
+       unsigned int modem_ctl[4];
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -400,7 +507,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
        }
        cflag = port->tty->termios->c_cflag;
 
-       /* check that they really want us to change something */
+       /* Check that they really want us to change something */
        if (old_termios) {
                if ((cflag == old_termios->c_cflag) &&
                                (RELEVANT_IFLAG(port->tty->termios->c_iflag)
@@ -415,7 +522,8 @@ static void cp2101_set_termios (struct usb_serial_port *port,
        /* If the baud rate is to be updated*/
        if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
                switch (cflag & CBAUD) {
-                       /* The baud rates which are commented out below
+                       /*
+                        * The baud rates which are commented out below
                         * appear to be supported by the device
                         * but are non-standard
                         */
@@ -448,18 +556,22 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                if (baud) {
                        dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
                                        baud);
-                       if (cp2101_set_config(port, CP2101_BAUDRATE,
+                       if (cp2101_set_config_single(port, CP2101_BAUDRATE,
                                                (BAUD_RATE_GEN_FREQ / baud)))
                                dev_err(&port->dev, "Baud rate requested not "
                                                "supported by device\n");
                }
        }
 
-       /*If the number of data bits is to be updated*/
+       /* If the number of data bits is to be updated */
        if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
-               bits = cp2101_get_config(port, CP2101_BITS);
+               cp2101_get_config(port, CP2101_BITS, &bits, 2);
                bits &= ~BITS_DATA_MASK;
                switch (cflag & CSIZE) {
+                       case CS5:
+                               bits |= BITS_DATA_5;
+                               dbg("%s - data bits = 5", __FUNCTION__);
+                               break;
                        case CS6:
                                bits |= BITS_DATA_6;
                                dbg("%s - data bits = 6", __FUNCTION__);
@@ -483,13 +595,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                                bits |= BITS_DATA_8;
                                break;
                }
-               if (cp2101_set_config(port, CP2101_BITS, bits))
+               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
                        dev_err(&port->dev, "Number of data bits requested "
                                        "not supported by device\n");
        }
 
        if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
-               bits = cp2101_get_config(port, CP2101_BITS);
+               cp2101_get_config(port, CP2101_BITS, &bits, 2);
                bits &= ~BITS_PARITY_MASK;
                if (cflag & PARENB) {
                        if (cflag & PARODD) {
@@ -500,13 +612,13 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                                dbg("%s - parity = EVEN", __FUNCTION__);
                        }
                }
-               if (cp2101_set_config(port, CP2101_BITS, bits))
+               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
                        dev_err(&port->dev, "Parity mode not supported "
                                        "by device\n");
        }
 
        if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
-               bits = cp2101_get_config(port, CP2101_BITS);
+               cp2101_get_config(port, CP2101_BITS, &bits, 2);
                bits &= ~BITS_STOP_MASK;
                if (cflag & CSTOPB) {
                        bits |= BITS_STOP_2;
@@ -515,15 +627,90 @@ static void cp2101_set_termios (struct usb_serial_port *port,
                        bits |= BITS_STOP_1;
                        dbg("%s - stop bits = 1", __FUNCTION__);
                }
-               if (cp2101_set_config(port, CP2101_BITS, bits))
+               if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
                        dev_err(&port->dev, "Number of stop bits requested "
                                        "not supported by device\n");
        }
+
+       if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
+               cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+               dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+                               __FUNCTION__, modem_ctl[0], modem_ctl[1],
+                               modem_ctl[2], modem_ctl[3]);
+
+               if (cflag & CRTSCTS) {
+                       modem_ctl[0] &= ~0x7B;
+                       modem_ctl[0] |= 0x09;
+                       modem_ctl[1] = 0x80;
+                       dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+               } else {
+                       modem_ctl[0] &= ~0x7B;
+                       modem_ctl[0] |= 0x01;
+                       modem_ctl[1] |= 0x40;
+                       dbg("%s - flow control = NONE", __FUNCTION__);
+               }
+
+               dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+                               __FUNCTION__, modem_ctl[0], modem_ctl[1],
+                               modem_ctl[2], modem_ctl[3]);
+               cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+       }
+
+}
+
+static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       int control = 0;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (set & TIOCM_RTS) {
+               control |= CONTROL_RTS;
+               control |= CONTROL_WRITE_RTS;
+       }
+       if (set & TIOCM_DTR) {
+               control |= CONTROL_DTR;
+               control |= CONTROL_WRITE_DTR;
+       }
+       if (clear & TIOCM_RTS) {
+               control &= ~CONTROL_RTS;
+               control |= CONTROL_WRITE_RTS;
+       }
+       if (clear & TIOCM_DTR) {
+               control &= ~CONTROL_DTR;
+               control |= CONTROL_WRITE_DTR;
+       }
+
+       dbg("%s - control = 0x%.4x", __FUNCTION__, control);
+
+       return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
+
+}
+
+static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
+{
+       int control, result;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       cp2101_get_config(port, CP2101_CONTROL, &control, 1);
+
+       result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
+               |((control & CONTROL_RTS) ? TIOCM_RTS : 0)
+               |((control & CONTROL_CTS) ? TIOCM_CTS : 0)
+               |((control & CONTROL_DSR) ? TIOCM_DSR : 0)
+               |((control & CONTROL_RING)? TIOCM_RI  : 0)
+               |((control & CONTROL_DCD) ? TIOCM_CD  : 0);
+
+       dbg("%s - control = 0x%.2x", __FUNCTION__, control);
+
+       return result;
 }
 
 static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
 {
-       u16 state;
+       int state;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
        if (break_state == 0)
@@ -532,12 +719,12 @@ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
                state = BREAK_ON;
        dbg("%s - turning break %s", __FUNCTION__,
                        state==BREAK_OFF ? "off" : "on");
-       cp2101_set_config(port, CP2101_BREAK, state);
+       cp2101_set_config(port, CP2101_BREAK, &state, 2);
 }
 
 static int cp2101_startup (struct usb_serial *serial)
 {
-       /*CP2101 buffers behave strangely unless device is reset*/
+       /* CP2101 buffers behave strangely unless device is reset */
        usb_reset_device(serial->dev);
        return 0;
 }
@@ -548,7 +735,7 @@ static void cp2101_shutdown (struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
-       /* stop reads and writes on all ports */
+       /* Stop reads and writes on all ports */
        for (i=0; i < serial->num_ports; ++i) {
                cp2101_cleanup(serial->port[i]);
        }
@@ -560,16 +747,16 @@ static int __init cp2101_init (void)
 
        retval = usb_serial_register(&cp2101_device);
        if (retval)
-               return retval; /*Failed to register*/
+               return retval; /* Failed to register */
 
        retval = usb_register(&cp2101_driver);
        if (retval) {
-               /*Failed to register*/
+               /* Failed to register */
                usb_serial_deregister(&cp2101_device);
                return retval;
        }
 
-       /*Success*/
+       /* Success */
        info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
 }
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
new file mode 100644 (file)
index 0000000..b722175
--- /dev/null
@@ -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");
+
index d2891f475793678078ce6fffa3326d5bbe6bfaa3..9fcc7bd1fbe427f2f55dd1dd4a774cccc617e93b 100644 (file)
@@ -862,6 +862,15 @@ UNUSUAL_DEV(  0x090a, 0x1001, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_BULK, NULL,
                US_FL_NEED_OVERRIDE ),
 
+/* Reported by Filippo Bardelli <filibard@libero.it>
+ * The device reports a subclass of RBC, which is wrong.
+ */
+UNUSUAL_DEV(  0x090a, 0x1050, 0x0100, 0x0100,
+               "Trumpion Microelectronics, Inc.",
+               "33520 USB Digital Voice Recorder",
+               US_SC_UFI, US_PR_DEVICE, NULL,
+               0),
+
 /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
 UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
                "Trumpion",
index 98d830401c56c7e50463e85acfe994f76171bb99..5a97e346bd95a247c12f0edcc5b33d1b065d6419 100644 (file)
@@ -188,7 +188,6 @@ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction)
                } else {
                        jbd_unlock_bh_state(bh);
                }
-               jh = next_jh;
        } while (jh != last_jh);
 
        return ret;
@@ -339,8 +338,10 @@ int log_do_checkpoint(journal_t *journal)
                        }
                } while (jh != last_jh && !retry);
 
-               if (batch_count)
+               if (batch_count) {
                        __flush_batch(journal, bhs, &batch_count);
+                       retry = 1;
+               }
 
                /*
                 * If someone cleaned up this transaction while we slept, we're
index b92c0e64aefa313d74456db2d4c718ad08182dc3..bb9aebe93862d8c03a94990d4b28fc4832e93a1f 100644 (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)
                        prefetchw(&bvec->bv_page->flags);
 
-               if (!uptodate)
+               if (!uptodate){
                        SetPageError(page);
+                       if (page->mapping)
+                               set_bit(AS_EIO, &page->mapping->flags);
+               }
                end_page_writeback(page);
        } while (bvec >= bio->bi_io_vec);
        bio_put(bio);
index 0035efe2db2ba7591fce0f6be861e6f23b7ecfd6..809c634ba1dfa03e41078b737a3f0be4945f7314 100644 (file)
 
 /* Special Purpose Registers (SPRNs)*/
 
-#define        SPRN_CDBCR      0x3D7   /* Cache Debug Control Register */
 #define        SPRN_CTR        0x009   /* Count Register */
 #define        SPRN_DABR       0x3F5   /* Data Address Breakpoint Register */
-#define        SPRN_DAC1       0x3F6   /* Data Address Compare 1 */
-#define        SPRN_DAC2       0x3F7   /* Data Address Compare 2 */
+#define   DABR_TRANSLATION     (1UL << 2)
 #define        SPRN_DAR        0x013   /* Data Address Register */
-#define        SPRN_DBCR       0x3F2   /* Debug Control Regsiter */
-#define          DBCR_EDM      0x80000000
-#define          DBCR_IDM      0x40000000
-#define          DBCR_RST(x)   (((x) & 0x3) << 28)
-#define            DBCR_RST_NONE               0
-#define            DBCR_RST_CORE               1
-#define            DBCR_RST_CHIP               2
-#define            DBCR_RST_SYSTEM             3
-#define          DBCR_IC       0x08000000      /* Instruction Completion Debug Evnt */
-#define          DBCR_BT       0x04000000      /* Branch Taken Debug Event */
-#define          DBCR_EDE      0x02000000      /* Exception Debug Event */
-#define          DBCR_TDE      0x01000000      /* TRAP Debug Event */
-#define          DBCR_FER      0x00F80000      /* First Events Remaining Mask */
-#define          DBCR_FT       0x00040000      /* Freeze Timers on Debug Event */
-#define          DBCR_IA1      0x00020000      /* Instr. Addr. Compare 1 Enable */
-#define          DBCR_IA2      0x00010000      /* Instr. Addr. Compare 2 Enable */
-#define          DBCR_D1R      0x00008000      /* Data Addr. Compare 1 Read Enable */
-#define          DBCR_D1W      0x00004000      /* Data Addr. Compare 1 Write Enable */
-#define          DBCR_D1S(x)   (((x) & 0x3) << 12)     /* Data Adrr. Compare 1 Size */
-#define            DAC_BYTE    0
-#define            DAC_HALF    1
-#define            DAC_WORD    2
-#define            DAC_QUAD    3
-#define          DBCR_D2R      0x00000800      /* Data Addr. Compare 2 Read Enable */
-#define          DBCR_D2W      0x00000400      /* Data Addr. Compare 2 Write Enable */
-#define          DBCR_D2S(x)   (((x) & 0x3) << 8)      /* Data Addr. Compare 2 Size */
-#define          DBCR_SBT      0x00000040      /* Second Branch Taken Debug Event */
-#define          DBCR_SED      0x00000020      /* Second Exception Debug Event */
-#define          DBCR_STD      0x00000010      /* Second Trap Debug Event */
-#define          DBCR_SIA      0x00000008      /* Second IAC Enable */
-#define          DBCR_SDA      0x00000004      /* Second DAC Enable */
-#define          DBCR_JOI      0x00000002      /* JTAG Serial Outbound Int. Enable */
-#define          DBCR_JII      0x00000001      /* JTAG Serial Inbound Int. Enable */
-#define        SPRN_DBCR0      0x3F2   /* Debug Control Register 0 */
-#define        SPRN_DBCR1      0x3BD   /* Debug Control Register 1 */
-#define        SPRN_DBSR       0x3F0   /* Debug Status Register */
-#define        SPRN_DCCR       0x3FA   /* Data Cache Cacheability Register */
-#define          DCCR_NOCACHE          0       /* Noncacheable */
-#define          DCCR_CACHE            1       /* Cacheable */
-#define        SPRN_DCMP       0x3D1   /* Data TLB Compare Register */
-#define        SPRN_DCWR       0x3BA   /* Data Cache Write-thru Register */
-#define          DCWR_COPY             0       /* Copy-back */
-#define          DCWR_WRITE            1       /* Write-through */
-#define        SPRN_DEAR       0x3D5   /* Data Error Address Register */
 #define        SPRN_DEC        0x016   /* Decrement Register */
-#define        SPRN_DMISS      0x3D0   /* Data TLB Miss Register */
 #define        SPRN_DSISR      0x012   /* Data Storage Interrupt Status Register */
 #define   DSISR_NOHPTE         0x40000000      /* no translation found */
 #define   DSISR_PROTFAULT      0x08000000      /* protection fault */
 #define   DSISR_ISSTORE                0x02000000      /* access was a store */
 #define   DSISR_DABRMATCH      0x00400000      /* hit data breakpoint */
 #define   DSISR_NOSEGMENT      0x00200000      /* STAB/SLB miss */
-#define        SPRN_EAR        0x11A   /* External Address Register */
-#define        SPRN_ESR        0x3D4   /* Exception Syndrome Register */
-#define          ESR_IMCP      0x80000000      /* Instr. Machine Check - Protection */
-#define          ESR_IMCN      0x40000000      /* Instr. Machine Check - Non-config */
-#define          ESR_IMCB      0x20000000      /* Instr. Machine Check - Bus error */
-#define          ESR_IMCT      0x10000000      /* Instr. Machine Check - Timeout */
-#define          ESR_PIL       0x08000000      /* Program Exception - Illegal */
-#define          ESR_PPR       0x04000000      /* Program Exception - Priveleged */
-#define          ESR_PTR       0x02000000      /* Program Exception - Trap */
-#define          ESR_DST       0x00800000      /* Storage Exception - Data miss */
-#define          ESR_DIZ       0x00400000      /* Storage Exception - Zone fault */
-#define        SPRN_EVPR       0x3D6   /* Exception Vector Prefix Register */
-#define        SPRN_HASH1      0x3D2   /* Primary Hash Address Register */
-#define        SPRN_HASH2      0x3D3   /* Secondary Hash Address Resgister */
 #define        SPRN_HID0       0x3F0   /* Hardware Implementation Register 0 */
-#define          HID0_EMCP     (1<<31)         /* Enable Machine Check pin */
-#define          HID0_EBA      (1<<29)         /* Enable Bus Address Parity */
-#define          HID0_EBD      (1<<28)         /* Enable Bus Data Parity */
-#define          HID0_SBCLK    (1<<27)
-#define          HID0_EICE     (1<<26)
-#define          HID0_ECLK     (1<<25)
-#define          HID0_PAR      (1<<24)
-#define          HID0_DOZE     (1<<23)
-#define          HID0_NAP      (1<<22)
-#define          HID0_SLEEP    (1<<21)
-#define          HID0_DPM      (1<<20)
-#define          HID0_ICE      (1<<15)         /* Instruction Cache Enable */
-#define          HID0_DCE      (1<<14)         /* Data Cache Enable */
-#define          HID0_ILOCK    (1<<13)         /* Instruction Cache Lock */
-#define          HID0_DLOCK    (1<<12)         /* Data Cache Lock */
-#define          HID0_ICFI     (1<<11)         /* Instr. Cache Flash Invalidate */
-#define          HID0_DCI      (1<<10)         /* Data Cache Invalidate */
-#define   HID0_SPD     (1<<9)          /* Speculative disable */
-#define   HID0_SGE     (1<<7)          /* Store Gathering Enable */
-#define          HID0_SIED     (1<<7)          /* Serial Instr. Execution [Disable] */
-#define   HID0_BTIC    (1<<5)          /* Branch Target Instruction Cache Enable */
-#define   HID0_ABE     (1<<3)          /* Address Broadcast Enable */
-#define          HID0_BHTE     (1<<2)          /* Branch History Table Enable */
-#define          HID0_BTCD     (1<<1)          /* Branch target cache disable */
 #define        SPRN_MSRDORM    0x3F1   /* Hardware Implementation Register 1 */
 #define SPRN_HID1      0x3F1   /* Hardware Implementation Register 1 */
 #define        SPRN_IABR       0x3F2   /* Instruction Address Breakpoint Register */
 #define SPRN_HID5      0x3F6   /* 970 HID5 */
 #define        SPRN_TSC        0x3FD   /* Thread switch control */
 #define        SPRN_TST        0x3FC   /* Thread switch timeout */
-#define        SPRN_IAC1       0x3F4   /* Instruction Address Compare 1 */
-#define        SPRN_IAC2       0x3F5   /* Instruction Address Compare 2 */
-#define        SPRN_ICCR       0x3FB   /* Instruction Cache Cacheability Register */
-#define          ICCR_NOCACHE          0       /* Noncacheable */
-#define          ICCR_CACHE            1       /* Cacheable */
-#define        SPRN_ICDBDR     0x3D3   /* Instruction Cache Debug Data Register */
-#define        SPRN_ICMP       0x3D5   /* Instruction TLB Compare Register */
-#define        SPRN_ICTC       0x3FB   /* Instruction Cache Throttling Control Reg */
-#define        SPRN_IMISS      0x3D4   /* Instruction TLB Miss Register */
-#define        SPRN_IMMR       0x27E   /* Internal Memory Map Register */
 #define        SPRN_L2CR       0x3F9   /* Level 2 Cache Control Regsiter */
 #define        SPRN_LR         0x008   /* Link Register */
-#define        SPRN_PBL1       0x3FC   /* Protection Bound Lower 1 */
-#define        SPRN_PBL2       0x3FE   /* Protection Bound Lower 2 */
-#define        SPRN_PBU1       0x3FD   /* Protection Bound Upper 1 */
-#define        SPRN_PBU2       0x3FF   /* Protection Bound Upper 2 */
-#define        SPRN_PID        0x3B1   /* Process ID */
 #define        SPRN_PIR        0x3FF   /* Processor Identification Register */
 #define        SPRN_PIT        0x3DB   /* Programmable Interval Timer */
 #define        SPRN_PURR       0x135   /* Processor Utilization of Resources Register */
 #define        SPRN_RPA        0x3D6   /* Required Physical Address Register */
 #define        SPRN_SDA        0x3BF   /* Sampled Data Address Register */
 #define        SPRN_SDR1       0x019   /* MMU Hash Base Register */
-#define        SPRN_SGR        0x3B9   /* Storage Guarded Register */
-#define          SGR_NORMAL            0
-#define          SGR_GUARDED           1
 #define        SPRN_SIA        0x3BB   /* Sampled Instruction Address Register */
 #define        SPRN_SPRG0      0x110   /* Special Purpose Register General 0 */
 #define        SPRN_SPRG1      0x111   /* Special Purpose Register General 1 */
 #define        SPRN_TBWL       0x11C   /* Time Base Lower Register (super, W/O) */
 #define        SPRN_TBWU       0x11D   /* Time Base Write Upper Register (super, W/O) */
 #define SPRN_HIOR      0x137   /* 970 Hypervisor interrupt offset */
-#define        SPRN_TCR        0x3DA   /* Timer Control Register */
-#define          TCR_WP(x)             (((x)&0x3)<<30) /* WDT Period */
-#define            WP_2_17             0               /* 2^17 clocks */
-#define            WP_2_21             1               /* 2^21 clocks */
-#define            WP_2_25             2               /* 2^25 clocks */
-#define            WP_2_29             3               /* 2^29 clocks */
-#define          TCR_WRC(x)            (((x)&0x3)<<28) /* WDT Reset Control */
-#define            WRC_NONE            0               /* No reset will occur */
-#define            WRC_CORE            1               /* Core reset will occur */
-#define            WRC_CHIP            2               /* Chip reset will occur */
-#define            WRC_SYSTEM          3               /* System reset will occur */
-#define          TCR_WIE               0x08000000      /* WDT Interrupt Enable */
-#define          TCR_PIE               0x04000000      /* PIT Interrupt Enable */
-#define          TCR_FP(x)             (((x)&0x3)<<24) /* FIT Period */
-#define            FP_2_9              0               /* 2^9 clocks */
-#define            FP_2_13             1               /* 2^13 clocks */
-#define            FP_2_17             2               /* 2^17 clocks */
-#define            FP_2_21             3               /* 2^21 clocks */
-#define          TCR_FIE               0x00800000      /* FIT Interrupt Enable */
-#define          TCR_ARE               0x00400000      /* Auto Reload Enable */
-#define        SPRN_THRM1      0x3FC   /* Thermal Management Register 1 */
-#define          THRM1_TIN             (1<<0)
-#define          THRM1_TIV             (1<<1)
-#define          THRM1_THRES           (0x7f<<2)
-#define          THRM1_TID             (1<<29)
-#define          THRM1_TIE             (1<<30)
-#define          THRM1_V               (1<<31)
-#define        SPRN_THRM2      0x3FD   /* Thermal Management Register 2 */
-#define        SPRN_THRM3      0x3FE   /* Thermal Management Register 3 */
-#define          THRM3_E               (1<<31)
-#define        SPRN_TSR        0x3D8   /* Timer Status Register */
-#define          TSR_ENW               0x80000000      /* Enable Next Watchdog */
-#define          TSR_WIS               0x40000000      /* WDT Interrupt Status */
-#define          TSR_WRS(x)            (((x)&0x3)<<28) /* WDT Reset Status */
-#define            WRS_NONE            0               /* No WDT reset occurred */
-#define            WRS_CORE            1               /* WDT forced core reset */
-#define            WRS_CHIP            2               /* WDT forced chip reset */
-#define            WRS_SYSTEM          3               /* WDT forced system reset */
-#define          TSR_PIS               0x08000000      /* PIT Interrupt Status */
-#define          TSR_FIS               0x04000000      /* FIT Interrupt Status */
 #define        SPRN_USIA       0x3AB   /* User Sampled Instruction Address Register */
 #define        SPRN_XER        0x001   /* Fixed Point Exception Register */
-#define        SPRN_ZPR        0x3B0   /* Zone Protection Register */
 #define SPRN_VRSAVE     0x100   /* Vector save */
+#define SPRN_CTRLF     0x088
+#define SPRN_CTRLT     0x098
+#define   CTRL_RUNLATCH        0x1
 
 /* Performance monitor SPRs */
 #define SPRN_SIAR      780
 #define        CTR     SPRN_CTR        /* Counter Register */
 #define        DAR     SPRN_DAR        /* Data Address Register */
 #define        DABR    SPRN_DABR       /* Data Address Breakpoint Register */
-#define        DCMP    SPRN_DCMP       /* Data TLB Compare Register */
 #define        DEC     SPRN_DEC        /* Decrement Register */
-#define        DMISS   SPRN_DMISS      /* Data TLB Miss Register */
 #define        DSISR   SPRN_DSISR      /* Data Storage Interrupt Status Register */
-#define        EAR     SPRN_EAR        /* External Address Register */
-#define        HASH1   SPRN_HASH1      /* Primary Hash Address Register */
-#define        HASH2   SPRN_HASH2      /* Secondary Hash Address Register */
 #define        HID0    SPRN_HID0       /* Hardware Implementation Register 0 */
 #define        MSRDORM SPRN_MSRDORM    /* MSR Dormant Register */
 #define        NIADORM SPRN_NIADORM    /* NIA Dormant Register */
 #define        TSC     SPRN_TSC        /* Thread switch control */
 #define        TST     SPRN_TST        /* Thread switch timeout */
 #define        IABR    SPRN_IABR       /* Instruction Address Breakpoint Register */
-#define        ICMP    SPRN_ICMP       /* Instruction TLB Compare Register */
-#define        IMISS   SPRN_IMISS      /* Instruction TLB Miss Register */
-#define        IMMR    SPRN_IMMR       /* PPC 860/821 Internal Memory Map Register */
 #define        L2CR    SPRN_L2CR       /* PPC 750 L2 control register */
 #define        __LR    SPRN_LR
 #define        PVR     SPRN_PVR        /* Processor Version */
 #define        PIR     SPRN_PIR        /* Processor ID */
 #define        PURR    SPRN_PURR       /* Processor Utilization of Resource Register */
-//#define      RPA     SPRN_RPA        /* Required Physical Address Register */
 #define        SDR1    SPRN_SDR1       /* MMU hash base register */
 #define        SPR0    SPRN_SPRG0      /* Supervisor Private Registers */
 #define        SPR1    SPRN_SPRG1
 #define        TBRU    SPRN_TBRU       /* Time Base Read Upper Register */
 #define        TBWL    SPRN_TBWL       /* Time Base Write Lower Register */
 #define        TBWU    SPRN_TBWU       /* Time Base Write Upper Register */
-#define ICTC   1019
-#define        THRM1   SPRN_THRM1      /* Thermal Management Register 1 */
-#define        THRM2   SPRN_THRM2      /* Thermal Management Register 2 */
-#define        THRM3   SPRN_THRM3      /* Thermal Management Register 3 */
 #define        XER     SPRN_XER
 
 /* Processor Version Register (PVR) field extraction */
 #define XGLUE(a,b) a##b
 #define GLUE(a,b) XGLUE(a,b)
 
-/* iSeries CTRL register (for runlatch) */
-
-#define CTRLT          0x098
-#define CTRLF          0x088
-#define RUNLATCH       0x0001
-
 #ifdef __ASSEMBLY__
 
 #define _GLOBAL(name) \
@@ -656,6 +496,24 @@ static inline void prefetchw(const void *x)
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
+static inline void ppc64_runlatch_on(void)
+{
+       unsigned long ctrl;
+
+       ctrl = mfspr(SPRN_CTRLF);
+       ctrl |= CTRL_RUNLATCH;
+       mtspr(SPRN_CTRLT, ctrl);
+}
+
+static inline void ppc64_runlatch_off(void)
+{
+       unsigned long ctrl;
+
+       ctrl = mfspr(SPRN_CTRLF);
+       ctrl &= ~CTRL_RUNLATCH;
+       mtspr(SPRN_CTRLT, ctrl);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index 037b5e06083c0c58ca8f2c624c7edd3b6c12df3a..48b7900e90ec2db801de1a22fe50c2b4ff429c33 100644 (file)
@@ -96,7 +96,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_POLLING_NRFLAG     4       /* true if poll_idle() is polling
                                           TIF_NEED_RESCHED */
 #define TIF_32BIT              5       /* 32 bit binary */
-#define TIF_RUN_LIGHT          6       /* iSeries run light */
+/* #define SPARE               6 */
 #define TIF_ABI_PENDING                7       /* 32/64 bit switch needed */
 #define TIF_SYSCALL_AUDIT      8       /* syscall auditing active */
 #define TIF_SINGLESTEP         9       /* singlestepping active */
@@ -110,7 +110,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_32BIT             (1<<TIF_32BIT)
-#define _TIF_RUN_LIGHT         (1<<TIF_RUN_LIGHT)
+/* #define _SPARE              (1<<SPARE) */
 #define _TIF_ABI_PENDING       (1<<TIF_ABI_PENDING)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
index c64f8c181df39b6f8d3890be531645efab24026d..1dc74baf03c4c16027d1811bfd32bf4be00c21b9 100644 (file)
@@ -10,7 +10,7 @@
 #define _S390_USER_H
 
 #include <asm/page.h>
-#include <linux/ptrace.h>
+#include <asm/ptrace.h>
 /* Core file format: The core file is written in such a way that gdb
    can understand it and provide useful information to the user (under
    linux we use the 'trad-core' bfd).  There are quite a number of
index 0485b256d043adbb3c823f9a0369021643695820..004e6f09a6e2daf89387bb2d1794cdd377c0ec1d 100644 (file)
@@ -23,7 +23,7 @@ struct shaper
        __u32 shapeclock;
        unsigned long recovery; /* Time we can next clock a packet out on
                                   an empty queue */
-        unsigned long locked;
+       struct semaphore sem;
         struct net_device_stats stats;
        struct net_device *dev;
        int  (*hard_start_xmit) (struct sk_buff *skb,
@@ -38,7 +38,6 @@ struct shaper
        int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh);
        void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char *  haddr);
        struct net_device_stats* (*get_stats)(struct net_device *dev);
-       wait_queue_head_t  wait_queue;
        struct timer_list timer;
 };
 
index e74f301e9baea59df14efbbd75943a61b496651c..b009f801e7c5880d671668fa31176bf824d4bf31 100644 (file)
@@ -467,12 +467,34 @@ static inline u8 ata_chk_status(struct ata_port *ap)
        return ap->ops->check_status(ap);
 }
 
+
+/**
+ *     ata_pause - Flush writes and pause 400 nanoseconds.
+ *     @ap: Port to wait for.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline void ata_pause(struct ata_port *ap)
 {
        ata_altstatus(ap);
        ndelay(400);
 }
 
+
+/**
+ *     ata_busy_wait - Wait for a port status register
+ *     @ap: Port to wait for.
+ *
+ *     Waits up to max*10 microseconds for the selected bits in the port's
+ *     status register to be cleared.
+ *     Returns final value of status register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
                               unsigned int max)
 {
@@ -487,6 +509,18 @@ static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
        return status;
 }
 
+
+/**
+ *     ata_wait_idle - Wait for a port to be idle.
+ *     @ap: Port to wait for.
+ *
+ *     Waits up to 10ms for port's BUSY and DRQ signals to clear.
+ *     Returns final value of status register.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_wait_idle(struct ata_port *ap)
 {
        u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
@@ -525,6 +559,18 @@ static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, uns
                tf->device = ATA_DEVICE_OBS | ATA_DEV1;
 }
 
+
+/**
+ *     ata_irq_on - Enable interrupts on a port.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Enable interrupts on a legacy IDE device using MMIO or PIO,
+ *     wait for idle, clear any pending interrupts.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 static inline u8 ata_irq_on(struct ata_port *ap)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -544,6 +590,18 @@ static inline u8 ata_irq_on(struct ata_port *ap)
        return tmp;
 }
 
+
+/**
+ *     ata_irq_ack - Acknowledge a device interrupt.
+ *     @ap: Port on which interrupts are enabled.
+ *
+ *     Wait up to 10 ms for legacy IDE device to become idle (BUSY
+ *     or BUSY+DRQ clear).  Obtain dma status and port status from
+ *     device.  Clear the interrupt.  Return port status.
+ *
+ *     LOCKING:
+ */
+
 static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
 {
        unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
index 470af8c1a4a01a680198b53a2fe3da15d3f2c2c0..ba5d1236aa170c75a92c1137e34b3c0fb242f93b 100644 (file)
@@ -204,7 +204,7 @@ struct hh_cache
        /* cached hardware header; allow for machine alignment needs.        */
 #define HH_DATA_MOD    16
 #define HH_DATA_OFF(__len) \
-       (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
+       (HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1))
 #define HH_DATA_ALIGN(__len) \
        (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
        unsigned long   hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
index 41d1a644c9d43aa8206cf2b6e708c4a8173b7fd2..2d1ac5058534cdd8db3ecb86233ab31d247e2c44 100644 (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
  * error_count.  Completion callbacks for ISO transfers will normally
  * (re)submit URBs to ensure a constant transfer rate.
+ *
+ * Note that even fields marked "public" should not be touched by the driver
+ * when the urb is owned by the hcd, that is, since the call to
+ * usb_submit_urb() till the entry into the completion routine.
  */
 struct urb
 {
@@ -803,12 +807,12 @@ struct urb
        struct kref kref;               /* reference count of the URB */
        spinlock_t lock;                /* lock for the URB */
        void *hcpriv;                   /* private data for host controller */
-       struct list_head urb_list;      /* list pointer to all active urbs */
        int bandwidth;                  /* bandwidth for INT/ISO request */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */
 
        /* public, documented fields in the urb that can be used by drivers */
+       struct list_head urb_list;      /* list head for use by the urb owner */
        struct usb_device *dev;         /* (in) pointer to associated device */
        unsigned int pipe;              /* (in) pipe information */
        int status;                     /* (return) non-ISO status */
index a788461a40c9228688dcc42ce72f5a7543339140..30e85de9fffff03662455d2357b5d384135d3db0 100644 (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_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)
 
 
index 253c46252bd5b1dfeae6382c94a2eaf7340278ae..867d4e9c6594c3a62eb70475d6b2c26cfe74c2ca 100644 (file)
@@ -216,9 +216,6 @@ int ip_vs_protocol_init(void)
 #ifdef CONFIG_IP_VS_PROTO_UDP
        REGISTER_PROTOCOL(&ip_vs_protocol_udp);
 #endif
-#ifdef CONFIG_IP_VS_PROTO_ICMP
-       REGISTER_PROTOCOL(&ip_vs_protocol_icmp);
-#endif
 #ifdef CONFIG_IP_VS_PROTO_AH
        REGISTER_PROTOCOL(&ip_vs_protocol_ah);
 #endif
diff --git a/net/ipv4/ipvs/ip_vs_proto_icmp.c b/net/ipv4/ipvs/ip_vs_proto_icmp.c
deleted file mode 100644 (file)
index 191e94a..0000000
+++ /dev/null
@@ -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,
-};
index 2f4c91ddc9a36c12d87cd57042a5d5d3644a1fd2..5ade5a5d199053dc20d349a8c8f313263a240260 100644 (file)
@@ -37,5 +37,4 @@ EXPORT_SYMBOL(in6_dev_finish_destroy);
 EXPORT_SYMBOL(xfrm6_rcv);
 #endif
 EXPORT_SYMBOL(rt6_lookup);
-EXPORT_SYMBOL(fl6_sock_lookup);
 EXPORT_SYMBOL(ipv6_push_nfrag_opts);