Commit ba5ce248 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 9290777f 47245fbf
...@@ -501,7 +501,7 @@ include/linux/version.h: Makefile ...@@ -501,7 +501,7 @@ include/linux/version.h: Makefile
.PHONY: depend dep .PHONY: depend dep
depend dep: depend dep:
@echo'*** Warning: make $@ is unnecessary now.' @echo '*** Warning: make $@ is unnecessary now.'
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Modules # Modules
......
...@@ -792,8 +792,8 @@ ENTRY(sys_call_table) ...@@ -792,8 +792,8 @@ ENTRY(sys_call_table)
.long sys_io_getevents .long sys_io_getevents
.long sys_io_submit .long sys_io_submit
.long sys_io_cancel .long sys_io_cancel
.long sys_ni_syscall /* 250 sys_alloc_hugepages - reuse this */ .long sys_fadvise64 /* 250 */
.long sys_ni_syscall /* was sys_free_hugepages - reuse this */ .long sys_ni_syscall
.long sys_exit_group .long sys_exit_group
.long sys_lookup_dcookie .long sys_lookup_dcookie
.long sys_epoll_create .long sys_epoll_create
......
...@@ -265,6 +265,41 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -265,6 +265,41 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
#endif #endif
} }
/*
* Lost tick detection and compensation
*/
static inline void detect_lost_tick(void)
{
/* read time since last interrupt */
unsigned long delta = timer->get_offset();
static unsigned long dbg_print;
/* check if delta is greater then two ticks */
if(delta >= 2*(1000000/HZ)){
/*
* only print debug info first 5 times
*/
/*
* AKPM: disable this for now; it's nice, but irritating.
*/
if (0 && dbg_print < 5) {
printk(KERN_WARNING "\nWarning! Detected %lu "
"micro-second gap between interrupts.\n",
delta);
printk(KERN_WARNING " Compensating for %lu lost "
"ticks.\n",
delta/(1000000/HZ)-1);
dump_stack();
dbg_print++;
}
/* calculate number of missed ticks */
delta = delta/(1000000/HZ)-1;
jiffies += delta;
}
}
/* /*
* This is the same as the above, except we _also_ save the current * This is the same as the above, except we _also_ save the current
* Time Stamp Counter value at the time of the timer interrupt, so that * Time Stamp Counter value at the time of the timer interrupt, so that
...@@ -281,6 +316,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -281,6 +316,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/ */
write_lock(&xtime_lock); write_lock(&xtime_lock);
detect_lost_tick();
timer->mark_offset(); timer->mark_offset();
do_timer_interrupt(irq, NULL, regs); do_timer_interrupt(irq, NULL, regs);
......
...@@ -283,8 +283,8 @@ int try_to_free_low(int count) ...@@ -283,8 +283,8 @@ int try_to_free_low(int count)
break; break;
} }
page = list_entry(p, struct page, list); page = list_entry(p, struct page, list);
if ((page_zone(page))->name[0] != 'H') // Look for non-Highmem if (!PageHighMem(page))
map = page; map = page;
} }
if (map) { if (map) {
list_del(&map->list); list_del(&map->list);
......
...@@ -508,20 +508,36 @@ void __init mem_init(void) ...@@ -508,20 +508,36 @@ void __init mem_init(void)
#endif #endif
} }
#if CONFIG_X86_PAE #include <linux/slab.h>
struct kmem_cache_s *pae_pgd_cachep;
kmem_cache_t *pmd_cache;
kmem_cache_t *pgd_cache;
void pmd_ctor(void *, kmem_cache_t *, unsigned long);
void pgd_ctor(void *, kmem_cache_t *, unsigned long);
void __init pgtable_cache_init(void) void __init pgtable_cache_init(void)
{ {
if (PTRS_PER_PMD > 1) {
pmd_cache = kmem_cache_create("pae_pmd",
PTRS_PER_PMD*sizeof(pmd_t),
0,
SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
pmd_ctor,
NULL);
if (!pmd_cache)
panic("pgtable_cache_init(): cannot create pmd cache");
}
/* /*
* PAE pgds must be 16-byte aligned: * PAE pgds must be 16-byte aligned:
*/ */
pae_pgd_cachep = kmem_cache_create("pae_pgd", 32, 0, pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), 0,
SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, pgd_ctor, NULL);
if (!pae_pgd_cachep) if (!pgd_cache)
panic("init_pae(): Cannot alloc pae_pgd SLAB cache"); panic("pgtable_cache_init(): Cannot create pgd cache");
} }
#endif
/* Put this after the callers, so that it cannot be inlined */ /* Put this after the callers, so that it cannot be inlined */
static int do_test_wp_bit(void) static int do_test_wp_bit(void)
......
...@@ -166,61 +166,60 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) ...@@ -166,61 +166,60 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
return pte; return pte;
} }
#if CONFIG_X86_PAE extern kmem_cache_t *pmd_cache;
extern kmem_cache_t *pgd_cache;
pgd_t *pgd_alloc(struct mm_struct *mm) void pmd_ctor(void *__pmd, kmem_cache_t *pmd_cache, unsigned long flags)
{ {
int i; clear_page(__pmd);
pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
if (pgd) {
for (i = 0; i < USER_PTRS_PER_PGD; i++) {
unsigned long pmd = __get_free_page(GFP_KERNEL);
if (!pmd)
goto out_oom;
clear_page(pmd);
set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
}
memcpy(pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
}
return pgd;
out_oom:
for (i--; i >= 0; i--)
free_page((unsigned long)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pae_pgd_cachep, pgd);
return NULL;
} }
void pgd_free(pgd_t *pgd) void pgd_ctor(void *__pgd, kmem_cache_t *pgd_cache, unsigned long flags)
{ {
int i; pgd_t *pgd = __pgd;
for (i = 0; i < USER_PTRS_PER_PGD; i++) if (PTRS_PER_PMD == 1)
free_page((unsigned long)__va(pgd_val(pgd[i])-1)); memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
kmem_cache_free(pae_pgd_cachep, pgd); memcpy(pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
} }
#else
pgd_t *pgd_alloc(struct mm_struct *mm) pgd_t *pgd_alloc(struct mm_struct *mm)
{ {
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); int i;
pgd_t *pgd = kmem_cache_alloc(pgd_cache, SLAB_KERNEL);
if (pgd) {
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); if (PTRS_PER_PMD == 1)
memcpy(pgd + USER_PTRS_PER_PGD, return pgd;
swapper_pg_dir + USER_PTRS_PER_PGD, else if (!pgd)
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); return NULL;
for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
pmd_t *pmd = kmem_cache_alloc(pmd_cache, SLAB_KERNEL);
if (!pmd)
goto out_oom;
set_pgd(pgd + i, __pgd(1 + __pa((unsigned long long)((unsigned long)pmd))));
} }
return pgd; return pgd;
out_oom:
for (i--; i >= 0; --i)
kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pgd_cache, (void *)pgd);
return NULL;
} }
void pgd_free(pgd_t *pgd) void pgd_free(pgd_t *pgd)
{ {
free_page((unsigned long)pgd); int i;
}
#endif /* CONFIG_X86_PAE */ if (PTRS_PER_PMD > 1) {
for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
set_pgd(pgd + i, __pgd(0));
}
}
kmem_cache_free(pgd_cache, (void *)pgd);
}
...@@ -35,7 +35,7 @@ struct device_driver cpu_driver = { ...@@ -35,7 +35,7 @@ struct device_driver cpu_driver = {
*/ */
int __init register_cpu(struct cpu *cpu, int num, struct node *root) int __init register_cpu(struct cpu *cpu, int num, struct node *root)
{ {
cpu->node_id = __cpu_to_node(num); cpu->node_id = cpu_to_node(num);
cpu->sysdev.name = "cpu"; cpu->sysdev.name = "cpu";
cpu->sysdev.id = num; cpu->sysdev.id = num;
if (root) if (root)
......
...@@ -36,7 +36,7 @@ struct device_driver memblk_driver = { ...@@ -36,7 +36,7 @@ struct device_driver memblk_driver = {
*/ */
int __init register_memblk(struct memblk *memblk, int num, struct node *root) int __init register_memblk(struct memblk *memblk, int num, struct node *root)
{ {
memblk->node_id = __memblk_to_node(num); memblk->node_id = memblk_to_node(num);
memblk->sysdev.name = "memblk"; memblk->sysdev.name = "memblk";
memblk->sysdev.id = num; memblk->sysdev.id = num;
if (root) if (root)
......
...@@ -72,7 +72,7 @@ int __init register_node(struct node *node, int num, struct node *parent) ...@@ -72,7 +72,7 @@ int __init register_node(struct node *node, int num, struct node *parent)
{ {
int error; int error;
node->cpumap = __node_to_cpu_mask(num); node->cpumap = node_to_cpumask(num);
node->sysroot.id = num; node->sysroot.id = num;
if (parent) if (parent)
node->sysroot.dev.parent = &parent->sysroot.sysdev; node->sysroot.dev.parent = &parent->sysroot.sysdev;
......
This diff is collapsed.
...@@ -2305,6 +2305,8 @@ typedef struct DAC960_Command ...@@ -2305,6 +2305,8 @@ typedef struct DAC960_Command
unsigned int BlockNumber; unsigned int BlockNumber;
unsigned int BlockCount; unsigned int BlockCount;
unsigned int SegmentCount; unsigned int SegmentCount;
int DmaDirection;
struct scatterlist *cmd_sglist;
IO_Request_T *Request; IO_Request_T *Request;
struct pci_dev *PciDevice; struct pci_dev *PciDevice;
union { union {
......
...@@ -274,7 +274,7 @@ void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr) ...@@ -274,7 +274,7 @@ void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
init_emergency_isa_pool(); init_emergency_isa_pool();
q->bounce_gfp = GFP_NOIO | GFP_DMA; q->bounce_gfp = GFP_NOIO | GFP_DMA;
} else } else
q->bounce_gfp = GFP_NOHIGHIO; q->bounce_gfp = GFP_NOIO;
/* /*
* keep this for debugging for now... * keep this for debugging for now...
......
...@@ -992,5 +992,12 @@ config RAW_DRIVER ...@@ -992,5 +992,12 @@ config RAW_DRIVER
Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
See the raw(8) manpage for more details. See the raw(8) manpage for more details.
config HANGCHECK_TIMER
tristate "Hangcheck timer"
help
The hangcheck-timer module detects when the system has gone
out to lunch past a certain margin. It can reboot the system
or merely print a warning.
endmenu endmenu
...@@ -77,6 +77,7 @@ obj-$(CONFIG_DRM) += drm/ ...@@ -77,6 +77,7 @@ obj-$(CONFIG_DRM) += drm/
obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_PCMCIA) += pcmcia/
obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_IPMI_HANDLER) += ipmi/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
# Files generated that shall be removed upon make clean # Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
......
...@@ -47,7 +47,7 @@ static void __attribute__((unused)) global_cache_flush(void) ...@@ -47,7 +47,7 @@ static void __attribute__((unused)) global_cache_flush(void)
flush_agp_cache(); flush_agp_cache();
} }
#else #else
static void global_cache_flush(void) static inline void global_cache_flush(void)
{ {
flush_agp_cache(); flush_agp_cache();
} }
......
/*
* hangcheck-timer.c
*
* Driver for a little io fencing timer.
*
* Copyright (C) 2002 Oracle Corporation. All rights reserved.
*
* Author: Joel Becker <joel.becker@oracle.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have recieved a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
/*
* The hangcheck-timer driver uses the TSC to catch delays that
* jiffies does not notice. A timer is set. When the timer fires, it
* checks whether it was delayed and if that delay exceeds a given
* margin of error. The hangcheck_tick module paramter takes the timer
* duration in seconds. The hangcheck_margin parameter defines the
* margin of error, in seconds. The defaults are 60 seconds for the
* timer and 180 seconds for the margin of error. IOW, a timer is set
* for 60 seconds. When the timer fires, the callback checks the
* actual duration that the timer waited. If the duration exceeds the
* alloted time and margin (here 60 + 180, or 240 seconds), the machine
* is restarted. A healthy machine will have the duration match the
* expected timeout very closely.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#define VERSION_STR "0.5.0"
#define DEFAULT_IOFENCE_MARGIN 60 /* Default fudge factor, in seconds */
#define DEFAULT_IOFENCE_TICK 180 /* Default timer timeout, in seconds */
static int hangcheck_tick = DEFAULT_IOFENCE_TICK;
static int hangcheck_margin = DEFAULT_IOFENCE_MARGIN;
static int hangcheck_reboot; /* Defaults to not reboot */
/* Driver options */
module_param(hangcheck_tick, int, 0);
MODULE_PARM_DESC(hangcheck_tick, "Timer delay.");
module_param(hangcheck_margin, int, 0);
MODULE_PARM_DESC(hangcheck_margin, "If the hangcheck timer has been delayed more than hangcheck_margin seconds, the driver will fire.");
module_param(hangcheck_reboot, int, 0);
MODULE_PARM_DESC(hangcheck_reboot, "If nonzero, the machine will reboot when the timer margin is exceeded.");
MODULE_AUTHOR("Joel Becker");
MODULE_DESCRIPTION("Hangcheck-timer detects when the system has gone out to lunch past a certain margin.");
MODULE_LICENSE("GPL");
/* Last time scheduled */
static unsigned long long hangcheck_tsc, hangcheck_tsc_margin;
static void hangcheck_fire(unsigned long);
static struct timer_list hangcheck_ticktock =
TIMER_INITIALIZER(hangcheck_fire, 0, 0);
static void hangcheck_fire(unsigned long data)
{
unsigned long long cur_tsc, tsc_diff;
cur_tsc = get_cycles();
if (cur_tsc > hangcheck_tsc)
tsc_diff = cur_tsc - hangcheck_tsc;
else
tsc_diff = (cur_tsc + (~0ULL - hangcheck_tsc)); /* or something */
if (tsc_diff > hangcheck_tsc_margin) {
if (hangcheck_reboot) {
printk(KERN_CRIT "Hangcheck: hangcheck is restarting the machine.\n");
machine_restart(NULL);
} else {
printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n");
}
}
mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
hangcheck_tsc = get_cycles();
}
static int __init hangcheck_init(void)
{
printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
VERSION_STR, hangcheck_tick, hangcheck_margin);
hangcheck_tsc_margin = hangcheck_margin + hangcheck_tick;
hangcheck_tsc_margin *= HZ;
hangcheck_tsc_margin *= current_cpu_data.loops_per_jiffy;
hangcheck_tsc = get_cycles();
mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
return 0;
}
static void __exit hangcheck_exit(void)
{
del_timer_sync(&hangcheck_ticktock);
}
module_init(hangcheck_init);
module_exit(hangcheck_exit);
...@@ -247,7 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { ...@@ -247,7 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
},{ },{
.v4l2_id = V4L2_STD_PAL_N, .v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N", .name = "PAL-N",
.Fsc 35468950, .Fsc = 35468950,
.swidth = 768, .swidth = 768,
.sheight = 576, .sheight = 576,
.totalwidth = 1135, .totalwidth = 1135,
......
...@@ -241,12 +241,6 @@ static void attach_inform(struct saa7146 *saa, int id) ...@@ -241,12 +241,6 @@ static void attach_inform(struct saa7146 *saa, int id)
} }
} }
static void detach_inform(struct saa7146 *saa, int id)
{
int i;
i = saa->nr;
}
static void I2CBusScan(struct saa7146 *saa) static void I2CBusScan(struct saa7146 *saa)
{ {
int i; int i;
...@@ -1323,9 +1317,12 @@ static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr) ...@@ -1323,9 +1317,12 @@ static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
clip_draw_rectangle(clipmap, 0, 0, 1024, -(saa->win.y)); clip_draw_rectangle(clipmap, 0, 0, 1024, -(saa->win.y));
} }
static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg) static int saa_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long argl)
{ {
struct saa7146 *saa = (struct saa7146 *) dev; struct saa7146 *saa = file->private_data;
void *arg = (void *)argl;
switch (cmd) { switch (cmd) {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
...@@ -1809,24 +1806,23 @@ static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ...@@ -1809,24 +1806,23 @@ static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0; return 0;
} }
static int saa_mmap(struct video_device *dev, const char *adr, static int saa_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long size)
{ {
struct saa7146 *saa = (struct saa7146 *) dev; struct saa7146 *saa = file->private_data;
printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr); printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
return -EINVAL; return -EINVAL;
} }
static long saa_read(struct video_device *dev, char *buf, static ssize_t saa_read(struct file *file, char *buf,
unsigned long count, int nonblock) size_t count, loff_t *ppos)
{ {
return -EINVAL; return -EINVAL;
} }
static long saa_write(struct video_device *dev, const char *buf, static ssize_t saa_write(struct file *file, const char *buf,
unsigned long count, int nonblock) size_t count, loff_t *ppos)
{ {
struct saa7146 *saa = (struct saa7146 *) dev; struct saa7146 *saa = file->private_data;
unsigned long todo = count; unsigned long todo = count;
int blocksize, split; int blocksize, split;
unsigned long flags; unsigned long flags;
...@@ -1945,11 +1941,23 @@ static long saa_write(struct video_device *dev, const char *buf, ...@@ -1945,11 +1941,23 @@ static long saa_write(struct video_device *dev, const char *buf,
return count; return count;
} }
static int saa_open(struct video_device *dev, int flags) static int saa_open(struct inode *inode, struct file *file)
{ {
struct saa7146 *saa = (struct saa7146 *) dev; struct saa7146 *saa = NULL;
unsigned int minor = minor(inode->i_rdev);
int i;
for (i = 0; i < SAA7146_MAX; i++) {
if (saa7146s[i].video_dev.minor == minor) {
saa = &saa7146s[i];
}
}
if (saa == NULL) {
return -ENODEV;
}
file->private_data = saa;
saa->video_dev.busy = 0; //saa->video_dev.busy = 0; /* old hack to support multiple open */
saa->user++; saa->user++;
if (saa->user > 1) if (saa->user > 1)
return 0; /* device open already, don't reset */ return 0; /* device open already, don't reset */
...@@ -1957,31 +1965,39 @@ static int saa_open(struct video_device *dev, int flags) ...@@ -1957,31 +1965,39 @@ static int saa_open(struct video_device *dev, int flags)
return 0; return 0;
} }
static void saa_close(struct video_device *dev) static int saa_release(struct inode *inode, struct file *file)
{ {
struct saa7146 *saa = (struct saa7146 *) dev; struct saa7146 *saa = file->private_data;
saa->user--; saa->user--;
saa->video_dev.busy = 0; //saa->video_dev.busy = 0; /* old hack to support multiple open */
if (saa->user > 0) /* still someone using device */ if (saa->user > 0) /* still someone using device */
return; return 0;
saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */ saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */
return 0;
} }
/* template for video_device-structure */ static struct file_operations saa_fops =
static struct video_device saa_template =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "SAA7146A",
.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
.hardware = VID_HARDWARE_SAA7146,
.open = saa_open, .open = saa_open,
.close = saa_close, .release = saa_release,
.ioctl = saa_ioctl,
.read = saa_read, .read = saa_read,
.llseek = no_llseek,
.write = saa_write, .write = saa_write,
.ioctl = saa_ioctl,
.mmap = saa_mmap, .mmap = saa_mmap,
}; };
/* template for video_device-structure */
static struct video_device saa_template =
{
.name = "SAA7146A",
.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
.hardware = VID_HARDWARE_SAA7146,
.fops = &saa_fops,
.minor = -1,
};
static int configure_saa7146(struct pci_dev *dev, int num) static int configure_saa7146(struct pci_dev *dev, int num)
{ {
int result; int result;
......
...@@ -212,6 +212,14 @@ config NET_ETHERNET ...@@ -212,6 +212,14 @@ config NET_ETHERNET
kernel: saying N will just cause the configurator to skip all kernel: saying N will just cause the configurator to skip all
the questions about Ethernet network cards. If unsure, say N. the questions about Ethernet network cards. If unsure, say N.
config MII
tristate "generic Media Independent Interface device support"
depends on NET_ETHERNET
help
Most ethernet controllers have MII transceiver either as an external
or internal device. It is safe to say Y or M here even if your
ethernet card lack MII.
config ARM_AM79C961A config ARM_AM79C961A
bool "ARM EBSA110 AM79C961A support" bool "ARM EBSA110 AM79C961A support"
depends on NET_ETHERNET && ARM && ARCH_EBSA110 depends on NET_ETHERNET && ARM && ARCH_EBSA110
......
...@@ -57,6 +57,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o ...@@ -57,6 +57,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
# end link order section # end link order section
# #
obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_AIRONET4500) += aironet4500_core.o obj-$(CONFIG_AIRONET4500) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o
obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o
...@@ -193,3 +194,6 @@ obj-$(CONFIG_NET_WIRELESS) += wireless/ ...@@ -193,3 +194,6 @@ obj-$(CONFIG_NET_WIRELESS) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_IRDA) += irda/
include $(TOPDIR)/drivers/usb/net/Makefile.mii
...@@ -351,7 +351,7 @@ static void aha152x_release_cs(u_long arg) ...@@ -351,7 +351,7 @@ static void aha152x_release_cs(u_long arg)
DEBUG(0, "aha152x_release_cs(0x%p)\n", link); DEBUG(0, "aha152x_release_cs(0x%p)\n", link);
#warning This doesn't protect you. You need some real fix for your races. #warning This does not protect you. You need some real fix for your races.
#if 0 #if 0
if (GET_USE_COUNT(driver_template.module) != 0) { if (GET_USE_COUNT(driver_template.module) != 0) {
DEBUG(1, "aha152x_cs: release postponed, " DEBUG(1, "aha152x_cs: release postponed, "
......
...@@ -314,7 +314,7 @@ static void fdomain_release(u_long arg) ...@@ -314,7 +314,7 @@ static void fdomain_release(u_long arg)
DEBUG(0, "fdomain_release(0x%p)\n", link); DEBUG(0, "fdomain_release(0x%p)\n", link);
#warning This doesn't protect you. You need some real fix for your races. #warning This does not protect you. You need some real fix for your races.
#if 0 #if 0
if (GET_USE_COUNT(&__this_module) != 0) { if (GET_USE_COUNT(&__this_module) != 0) {
DEBUG(1, "fdomain_cs: release postponed, " DEBUG(1, "fdomain_cs: release postponed, "
......
...@@ -330,7 +330,7 @@ static void qlogic_release(u_long arg) ...@@ -330,7 +330,7 @@ static void qlogic_release(u_long arg)
DEBUG(0, "qlogic_release(0x%p)\n", link); DEBUG(0, "qlogic_release(0x%p)\n", link);
#warning This doesn't protect you. You need some real fix for your races. #warning This does not protect you. You need some real fix for your races.
#if 0 #if 0
if (GET_USE_COUNT(&__this_module) != 0) { if (GET_USE_COUNT(&__this_module) != 0) {
DEBUG(0, "qlogic_cs: release postponed, device still open\n"); DEBUG(0, "qlogic_cs: release postponed, device still open\n");
......
...@@ -1594,6 +1594,7 @@ void scsi_error_handler(void *data) ...@@ -1594,6 +1594,7 @@ void scsi_error_handler(void *data)
*/ */
sprintf(current->comm, "scsi_eh_%d", shost->host_no); sprintf(current->comm, "scsi_eh_%d", shost->host_no);
current->flags |= PF_IOTHREAD;
shost->eh_wait = &sem; shost->eh_wait = &sem;
shost->ehandler = current; shost->ehandler = current;
......
...@@ -257,7 +257,7 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) ...@@ -257,7 +257,7 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
if (urb->status) if (urb->status)
dbg("nonzero read bulk status received: %d", urb->status); dbg("nonzero read bulk status received: %d", urb->status);
if (!urb->status & !acm->throttle) { if (!urb->status && !acm->throttle) {
for (i = 0; i < urb->actual_length && !acm->throttle; i++) { for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, /* if we insert more than TTY_FLIPBUF_SIZE characters,
* we drop them. */ * we drop them. */
...@@ -697,6 +697,7 @@ static void acm_disconnect(struct usb_interface *intf) ...@@ -697,6 +697,7 @@ static void acm_disconnect(struct usb_interface *intf)
static struct usb_device_id acm_ids[] = { static struct usb_device_id acm_ids[] = {
{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) }, { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
{ USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
{ } { }
}; };
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
static char *format_topo = static char *format_topo =
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */ /* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
"T: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n"; "\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
static char *format_string_manufacturer = static char *format_string_manufacturer =
/* S: Manufacturer=xxxx */ /* S: Manufacturer=xxxx */
......
...@@ -310,9 +310,9 @@ static int rh_string ( ...@@ -310,9 +310,9 @@ static int rh_string (
} else } else
return 0; return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2); data [0] = 2 * (strlen (buf) + 1);
data [1] = 3; /* type == string */ data [1] = 3; /* type == string */
return data [0]; return 2 + ascii2utf (buf, data + 2, len - 2);
} }
...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
return status; return status;
} }
/* lower level hcd code should use *_dma exclusively */ /* lower level hcd code should use *_dma exclusively,
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { * unless it uses pio or talks to another transport.
*/
if (!(urb->transfer_flags & URB_NO_DMA_MAP)
&& hcd->controller->dma_mask) {
if (usb_pipecontrol (urb->pipe)) if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single ( urb->setup_dma = dma_map_single (
hcd->controller, hcd->controller,
......
...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
*/ */
}; };
/* 2.4 does this a bit differently ... */
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{
return &hcd->self;
}
struct hcd_dev { /* usb_device.hcpriv points to this */ struct hcd_dev { /* usb_device.hcpriv points to this */
struct list_head dev_list; /* on this hcd */ struct list_head dev_list; /* on this hcd */
struct list_head urb_list; /* pending on this dev */ struct list_head urb_list; /* pending on this dev */
...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *); ...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_dev, extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev); struct device *parent_dev);
/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->controller);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* exported only within usbcore */ /* exported only within usbcore */
......
...@@ -206,7 +206,8 @@ static void sg_clean (struct usb_sg_request *io) ...@@ -206,7 +206,8 @@ static void sg_clean (struct usb_sg_request *io)
kfree (io->urbs); kfree (io->urbs);
io->urbs = 0; io->urbs = 0;
} }
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0; io->dev = 0;
} }
...@@ -301,6 +302,7 @@ int usb_sg_init ( ...@@ -301,6 +302,7 @@ int usb_sg_init (
{ {
int i; int i;
int urb_flags; int urb_flags;
int dma;
if (!io || !dev || !sg if (!io || !dev || !sg
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
...@@ -314,8 +316,16 @@ int usb_sg_init ( ...@@ -314,8 +316,16 @@ int usb_sg_init (
io->sg = sg; io->sg = sg;
io->nents = nents; io->nents = nents;
/* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
dma = (dev->dev.dma_mask != 0);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
io->entries = nents;
/* initialize all the urbs we'll use */ /* initialize all the urbs we'll use */
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
if (io->entries <= 0) if (io->entries <= 0)
return io->entries; return io->entries;
...@@ -347,8 +357,17 @@ int usb_sg_init ( ...@@ -347,8 +357,17 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS; io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0; io->urbs [i]->actual_length = 0;
io->urbs [i]->transfer_dma = sg_dma_address (sg + i); if (dma) {
len = sg_dma_len (sg + i); /* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
} else {
/* hc may use _only_ transfer_buffer */
io->urbs [i]->transfer_buffer =
page_address (sg [i].page) + sg [i].offset;
len = sg [i].length;
}
if (length) { if (length) {
len = min_t (unsigned, len, length); len = min_t (unsigned, len, length);
length -= len; length -= len;
...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
retval = 0; retval = 0;
i--; i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT? // FIXME: should it usb_sg_cancel() on INTERRUPT?
// how about imposing a backoff? yield ();
set_current_state (TASK_UNINTERRUPTIBLE);
schedule ();
break; break;
/* no error? continue immediately. /* no error? continue immediately.
......
...@@ -1224,7 +1224,8 @@ void usb_buffer_free ( ...@@ -1224,7 +1224,8 @@ void usb_buffer_free (
* *
* Return value is either null (indicating no buffer could be mapped), or * Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the
* operation succeeds. * operation succeeds. If the device is connected to this system through
* a non-DMA controller, this operation always succeeds.
* *
* This call would normally be used for an urb which is reused, perhaps * This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync() * as the target of a large periodic transfer, with usb_buffer_dmasync()
...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb) ...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return 0; return 0;
urb->transfer_dma = dma_map_single (controller, if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP; urb->transfer_flags |= URB_NO_DMA_MAP;
return urb; return urb;
} }
...@@ -1271,7 +1275,8 @@ void usb_buffer_dmasync (struct urb *urb) ...@@ -1271,7 +1275,8 @@ void usb_buffer_dmasync (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
dma_sync_single (controller, if (controller->dma_mask)
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb) ...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
dma_unmap_single (controller, if (controller->dma_mask)
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
urb->transfer_flags &= ~URB_NO_DMA_MAP;
} }
/** /**
...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, ...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return -1; return -1;
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, ...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_sync_sg (controller, sg, n_hw_ents, dma_sync_sg (controller, sg, n_hw_ents,
...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_unmap_sg (controller, sg, n_hw_ents, dma_unmap_sg (controller, sg, n_hw_ents,
......
...@@ -277,7 +277,26 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } ...@@ -277,7 +277,26 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \ default: tmp = '?'; break; \
}; tmp; }) }; tmp; })
static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) static inline char token_mark (u32 token)
{
token = le32_to_cpu (token);
if (token & QTD_STS_ACTIVE)
return '*';
if (token & QTD_STS_HALT)
return '-';
if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */
|| QTD_LENGTH (token) == 0)
return ' ';
/* tries to advance through hw_alt_next */
return '/';
}
static void qh_lines (
struct ehci_hcd *ehci,
struct ehci_qh *qh,
char **nextp,
unsigned *sizep
)
{ {
u32 scratch; u32 scratch;
u32 hw_curr; u32 hw_curr;
...@@ -286,26 +305,49 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) ...@@ -286,26 +305,49 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
unsigned temp; unsigned temp;
unsigned size = *sizep; unsigned size = *sizep;
char *next = *nextp; char *next = *nextp;
char mark;
mark = token_mark (qh->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
mark = '#'; /* blocked */
else if (qh->hw_alt_next & cpu_to_le32 (0x01))
mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */
}
scratch = cpu_to_le32p (&qh->hw_info1); scratch = cpu_to_le32p (&qh->hw_info1);
hw_curr = cpu_to_le32p (&qh->hw_current); hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0;
temp = snprintf (next, size, temp = snprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)", "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f, qh, scratch & 0x007f,
speed_char (scratch), speed_char (scratch),
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
scratch, cpu_to_le32p (&qh->hw_info2), scratch, cpu_to_le32p (&qh->hw_info2),
hw_curr, cpu_to_le32p (&qh->hw_token)); cpu_to_le32p (&qh->hw_token), mark,
(cpu_to_le32 (0x8000000) & qh->hw_token)
? "data0" : "data1",
(cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f);
size -= temp; size -= temp;
next += temp; next += temp;
/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) { list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list); td = list_entry (entry, struct ehci_qtd, qtd_list);
scratch = cpu_to_le32p (&td->hw_token); scratch = cpu_to_le32p (&td->hw_token);
mark = ' ';
if (hw_curr == td->qtd_dma)
mark = '*';
else if (qh->hw_qtd_next == td->qtd_dma)
mark = '+';
else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next)
mark = '#';
else if (td->hw_alt_next != EHCI_LIST_END)
mark = '/';
}
temp = snprintf (next, size, temp = snprintf (next, size,
"\n\t%std/%p %s len=%d %08x urb %p", "\n\t%p%c%s len=%d %08x urb %p",
(hw_curr == td->qtd_dma) ? "*" : "", td, mark, ({ char *tmp;
td, ({ char *tmp;
switch ((scratch>>8)&0x03) { switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break; case 0: tmp = "out"; break;
case 1: tmp = "in"; break; case 1: tmp = "in"; break;
...@@ -315,13 +357,27 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) ...@@ -315,13 +357,27 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
(scratch >> 16) & 0x7fff, (scratch >> 16) & 0x7fff,
scratch, scratch,
td->urb); td->urb);
if (temp < 0)
temp = 0;
else if (size < temp)
temp = size;
size -= temp; size -= temp;
next += temp; next += temp;
if (temp == size)
goto done;
} }
temp = snprintf (next, size, "\n"); temp = snprintf (next, size, "\n");
*sizep = size - temp; if (temp < 0)
*nextp = next + temp; temp = 0;
else if (size < temp)
temp = size;
size -= temp;
next += temp;
done:
*sizep = size;
*nextp = next;
} }
static ssize_t static ssize_t
...@@ -344,14 +400,15 @@ show_async (struct device *dev, char *buf) ...@@ -344,14 +400,15 @@ show_async (struct device *dev, char *buf)
* one QH per line, and TDs we know about * one QH per line, and TDs we know about
*/ */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh) for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (qh, &next, &size); qh_lines (ehci, qh, &next, &size);
if (ehci->reclaim) { if (ehci->reclaim && size > 0) {
temp = snprintf (next, size, "\nreclaim =\n"); temp = snprintf (next, size, "\nreclaim =\n");
size -= temp; size -= temp;
next += temp; next += temp;
qh_lines (ehci->reclaim, &next, &size); for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
qh_lines (ehci, qh, &next, &size);
} }
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
...@@ -421,7 +478,7 @@ show_periodic (struct device *dev, char *buf) ...@@ -421,7 +478,7 @@ show_periodic (struct device *dev, char *buf)
scratch & 0x007f, scratch & 0x007f,
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
p.qh->usecs, p.qh->c_usecs, p.qh->usecs, p.qh->c_usecs,
scratch >> 16); 0x7ff & (scratch >> 16));
/* FIXME TD info too */ /* FIXME TD info too */
...@@ -490,7 +547,8 @@ show_registers (struct device *dev, char *buf) ...@@ -490,7 +547,8 @@ show_registers (struct device *dev, char *buf)
/* Capability Registers */ /* Capability Registers */
i = readw (&ehci->caps->hci_version); i = readw (&ehci->caps->hci_version);
temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n", temp = snprintf (next, size,
"EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n",
i >> 8, i & 0x0ff, ehci->hcd.state); i >> 8, i & 0x0ff, ehci->hcd.state);
size -= temp; size -= temp;
next += temp; next += temp;
......
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4 * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "2002-Nov-29" #define DRIVER_VERSION "2003-Jan-22"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...@@ -110,10 +110,11 @@ static const char hcd_name [] = "ehci-hcd"; ...@@ -110,10 +110,11 @@ static const char hcd_name [] = "ehci-hcd";
/* magic numbers that can affect system performance */ /* magic numbers that can affect system performance */
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
#define EHCI_TUNE_RL_HS 0 /* nak throttle; see 4.9 */ #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
#define EHCI_TUNE_RL_TT 0 #define EHCI_TUNE_RL_TT 0
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
...@@ -416,13 +417,26 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -416,13 +417,26 @@ static int ehci_start (struct usb_hcd *hcd)
ehci_info (ehci, "enabled 64bit PCI DMA\n"); ehci_info (ehci, "enabled 64bit PCI DMA\n");
} }
/* help hc dma work well with cachelines */
pci_set_mwi (ehci->hcd.pdev);
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
temp = readl (&ehci->regs->command) & 0xff; temp = readl (&ehci->regs->command) & 0xff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6) if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0; log2_irq_thresh = 0;
temp |= 1 << (16 + log2_irq_thresh); temp |= 1 << (16 + log2_irq_thresh);
// if hc can park (ehci >= 0.96), default is 3 packets per async QH // if hc can park (ehci >= 0.96), default is 3 packets per async QH
// keeping default periodic framelist size if (HCC_PGM_FRAMELISTLEN (hcc_params)) {
/* periodic schedule size can be smaller than default */
temp &= ~(3 << 2);
temp |= (EHCI_TUNE_FLS << 2);
switch (EHCI_TUNE_FLS) {
case 0: ehci->periodic_size = 1024; break;
case 1: ehci->periodic_size = 512; break;
case 2: ehci->periodic_size = 256; break;
default: BUG ();
}
}
temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE), temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
// Philips, Intel, and maybe others need CMD_RUN before the // Philips, Intel, and maybe others need CMD_RUN before the
// root hub will detect new devices (why?); NEC doesn't // root hub will detect new devices (why?); NEC doesn't
...@@ -759,7 +773,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -759,7 +773,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh; struct ehci_qh *qh;
unsigned long flags; unsigned long flags;
int maybe_irq = 1;
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
...@@ -769,23 +782,23 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -769,23 +782,23 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv; qh = (struct ehci_qh *) urb->hcpriv;
if (!qh) if (!qh)
break; break;
while (qh->qh_state == QH_STATE_LINKED
/* if we need to use IAA and it's busy, defer */
if (qh->qh_state == QH_STATE_LINKED
&& ehci->reclaim && ehci->reclaim
&& HCD_IS_RUNNING (ehci->hcd.state) && HCD_IS_RUNNING (ehci->hcd.state)
) { ) {
spin_unlock_irqrestore (&ehci->lock, flags); struct ehci_qh *last;
if (maybe_irq) { for (last = ehci->reclaim;
if (in_interrupt ()) last->reclaim;
return -EAGAIN; last = last->reclaim)
maybe_irq = 0; continue;
} qh->qh_state = QH_STATE_UNLINK_WAIT;
/* let pending unlinks complete, so this can start */ last->reclaim = qh;
wait_ms (1);
spin_lock_irqsave (&ehci->lock, flags); /* bypass IAA if the hc can't care */
} } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
end_unlink_async (ehci, NULL); end_unlink_async (ehci, NULL);
/* something else might have unlinked the qh by now */ /* something else might have unlinked the qh by now */
......
...@@ -75,8 +75,6 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) ...@@ -75,8 +75,6 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) { if (qtd != 0) {
ehci_qtd_init (qtd, dma); ehci_qtd_init (qtd, dma);
if (ehci->async)
qtd->hw_alt_next = ehci->async->hw_alt_next;
} }
return qtd; return qtd;
} }
......
This diff is collapsed.
...@@ -236,12 +236,12 @@ struct ehci_qtd { ...@@ -236,12 +236,12 @@ struct ehci_qtd {
/* the rest is HCD-private */ /* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */ dma_addr_t qtd_dma; /* qtd address */
struct list_head qtd_list; /* sw qtd list */ struct list_head qtd_list; /* sw qtd list */
/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
struct urb *urb; /* qtd's urb */ struct urb *urb; /* qtd's urb */
size_t length; /* length of buffer */ size_t length; /* length of buffer */
} __attribute__ ((aligned (32))); } __attribute__ ((aligned (32)));
#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */ /* type tag from {qh,itd,sitd,fstn}->hw_next */
...@@ -305,6 +305,7 @@ struct ehci_qh { ...@@ -305,6 +305,7 @@ struct ehci_qh {
union ehci_shadow qh_next; /* ptr to qh; or periodic */ union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */ struct list_head qtd_list; /* sw qtd list */
struct ehci_qtd *dummy; struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */
atomic_t refcount; atomic_t refcount;
unsigned stamp; unsigned stamp;
...@@ -313,6 +314,8 @@ struct ehci_qh { ...@@ -313,6 +314,8 @@ struct ehci_qh {
#define QH_STATE_LINKED 1 /* HC sees this */ #define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */ #define QH_STATE_UNLINK 2 /* HC may still see this */
#define QH_STATE_IDLE 3 /* HC doesn't see this */ #define QH_STATE_IDLE 3 /* HC doesn't see this */
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
/* periodic schedule info */ /* periodic schedule info */
u8 usecs; /* intr bandwidth */ u8 usecs; /* intr bandwidth */
...@@ -426,16 +429,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd) ...@@ -426,16 +429,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd)
#else /* LINUX_VERSION_CODE */ #else /* LINUX_VERSION_CODE */
// hcd_to_bus() eventually moves to hcd.h on 2.5 too
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
// ... as does hcd_register_root()
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) #define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG #ifndef DEBUG
......
...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb) ...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb)
if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) { if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
/* URB active? */ /* URB active? */
if (urb->transfer_flags & (URB_ASYNC_UNLINK | URB_TIMEOUT_KILLED)) { if (urb->transfer_flags & URB_ASYNC_UNLINK) {
/* asynchronous with callback */ /* asynchronous with callback */
/* relink the urb to the del list */ /* relink the urb to the del list */
list_move (&urb->urb_list, &hci->del_list); list_move (&urb->urb_list, &hci->del_list);
...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb) ...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb)
struct urb *urb = (struct urb *) lurb; struct urb *urb = (struct urb *) lurb;
DBGFUNC ("enter qu_urb_timeout\n"); DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= URB_TIMEOUT_KILLED;
hci_unlink_urb (urb); hci_unlink_urb (urb);
} }
#endif #endif
......
...@@ -203,28 +203,28 @@ static int ohci_urb_enqueue ( ...@@ -203,28 +203,28 @@ static int ohci_urb_enqueue (
return -ENOMEM; return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
if (ohci->disabled || ohci->sleeping) {
retval = -ENODEV;
goto fail;
}
/* fill the private part of the URB */ /* fill the private part of the URB */
urb_priv->length = size; urb_priv->length = size;
urb_priv->ed = ed; urb_priv->ed = ed;
/* allocate the TDs (updating hash chains) */ /* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC); urb_priv->td [i] = td_alloc (ohci, mem_flags);
if (!urb_priv->td [i]) { if (!urb_priv->td [i]) {
urb_priv->length = i; urb_priv->length = i;
retval = -ENOMEM; urb_free_priv (ohci, urb_priv);
goto fail; return -ENOMEM;
} }
} }
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
if (ohci->disabled || ohci->sleeping) {
retval = -ENODEV;
goto fail;
}
/* schedule the ed if needed */ /* schedule the ed if needed */
if (ed->state == ED_IDLE) { if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed); retval = ed_schedule (ohci, ed);
......
...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) { if (td) {
int hash;
/* in case hc fetches it, make it look dead */ /* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td); memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma); td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma; td->td_dma = dma;
/* hashed in td_fill */
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (dma);
td->td_hash = hc->td_hash [hash];
hc->td_hash [hash] = td;
} }
return td; return td;
} }
......
...@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
static void static void
td_fill (unsigned int info, td_fill (struct ohci_hcd *ohci, u32 info,
dma_addr_t data, int len, dma_addr_t data, int len,
struct urb *urb, int index) struct urb *urb, int index)
{ {
struct td *td, *td_pt; struct td *td, *td_pt;
struct urb_priv *urb_priv = urb->hcpriv; struct urb_priv *urb_priv = urb->hcpriv;
int is_iso = info & TD_ISO; int is_iso = info & TD_ISO;
int hash;
// ASSERT (index < urb_priv->length); // ASSERT (index < urb_priv->length);
...@@ -516,11 +517,16 @@ td_fill (unsigned int info, ...@@ -516,11 +517,16 @@ td_fill (unsigned int info,
td->hwBE = 0; td->hwBE = 0;
td->hwNextTD = cpu_to_le32 (td_pt->td_dma); td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
/* HC might read the TD right after we link it ... */
wmb ();
/* append to queue */ /* append to queue */
list_add_tail (&td->td_list, &td->ed->td_list); list_add_tail (&td->td_list, &td->ed->td_list);
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (td->td_dma);
td->td_hash = ohci->td_hash [hash];
ohci->td_hash [hash] = td;
/* HC might read the TD (or cachelines) right away ... */
wmb ();
td->ed->hwTailP = td->hwNextTD; td->ed->hwTailP = td->hwNextTD;
} }
...@@ -578,7 +584,7 @@ static void td_submit_urb ( ...@@ -578,7 +584,7 @@ static void td_submit_urb (
: TD_T_TOGGLE | TD_CC | TD_DP_IN; : TD_T_TOGGLE | TD_CC | TD_DP_IN;
/* TDs _could_ transfer up to 8K each */ /* TDs _could_ transfer up to 8K each */
while (data_len > 4096) { while (data_len > 4096) {
td_fill (info, data, 4096, urb, cnt); td_fill (ohci, info, data, 4096, urb, cnt);
data += 4096; data += 4096;
data_len -= 4096; data_len -= 4096;
cnt++; cnt++;
...@@ -586,11 +592,11 @@ static void td_submit_urb ( ...@@ -586,11 +592,11 @@ static void td_submit_urb (
/* maybe avoid ED halt on final TD short read */ /* maybe avoid ED halt on final TD short read */
if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
info |= TD_R; info |= TD_R;
td_fill (info, data, data_len, urb, cnt); td_fill (ohci, info, data, data_len, urb, cnt);
cnt++; cnt++;
if ((urb->transfer_flags & URB_ZERO_PACKET) if ((urb->transfer_flags & URB_ZERO_PACKET)
&& cnt < urb_priv->length) { && cnt < urb_priv->length) {
td_fill (info, 0, 0, urb, cnt); td_fill (ohci, info, 0, 0, urb, cnt);
cnt++; cnt++;
} }
/* maybe kickstart bulk list */ /* maybe kickstart bulk list */
...@@ -605,17 +611,17 @@ static void td_submit_urb ( ...@@ -605,17 +611,17 @@ static void td_submit_urb (
*/ */
case PIPE_CONTROL: case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0; info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
td_fill (info, urb->setup_dma, 8, urb, cnt++); td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);
if (data_len > 0) { if (data_len > 0) {
info = TD_CC | TD_R | TD_T_DATA1; info = TD_CC | TD_R | TD_T_DATA1;
info |= is_out ? TD_DP_OUT : TD_DP_IN; info |= is_out ? TD_DP_OUT : TD_DP_IN;
/* NOTE: mishandles transfers >8K, some >4K */ /* NOTE: mishandles transfers >8K, some >4K */
td_fill (info, data, data_len, urb, cnt++); td_fill (ohci, info, data, data_len, urb, cnt++);
} }
info = is_out info = is_out
? TD_CC | TD_DP_IN | TD_T_DATA1 ? TD_CC | TD_DP_IN | TD_T_DATA1
: TD_CC | TD_DP_OUT | TD_T_DATA1; : TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (info, data, 0, urb, cnt++); td_fill (ohci, info, data, 0, urb, cnt++);
/* maybe kickstart control list */ /* maybe kickstart control list */
wmb (); wmb ();
writel (OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_CLF, &ohci->regs->cmdstatus);
...@@ -634,7 +640,7 @@ static void td_submit_urb ( ...@@ -634,7 +640,7 @@ static void td_submit_urb (
// a 2^16 iso range, vs other HCs max of 2^10) // a 2^16 iso range, vs other HCs max of 2^10)
frame += cnt * urb->interval; frame += cnt * urb->interval;
frame &= 0xffff; frame &= 0xffff;
td_fill (TD_CC | TD_ISO | frame, td_fill (ohci, TD_CC | TD_ISO | frame,
data + urb->iso_frame_desc [cnt].offset, data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt); urb->iso_frame_desc [cnt].length, urb, cnt);
} }
......
...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr) ...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next; tmp = tmp->next;
u->transfer_flags |= URB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u); uhci_urb_dequeue(hcd, u);
} }
......
/* -*- linux-c -*- */ /* -*- linux-c -*- */
/* /*
* Driver for USB Scanners (linux-2.5.54) * Driver for USB Scanners (linux-2.5.60)
* *
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Copyright (C) 2002, 2003 Henning Meier-Geinitz
* *
* Portions may be copyright Brad Keryan and Michael Gee. * Portions may be copyright Brad Keryan and Michael Gee.
* *
* Brian Beattie <beattie@beattie-home.net> * Previously maintained by Brian Beattie
*
* Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -300,8 +303,6 @@ ...@@ -300,8 +303,6 @@
* Frank Zago <fzago@greshamstorage.com> and * Frank Zago <fzago@greshamstorage.com> and
* Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing. * Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing.
* *
* 05/21/02 Currently maintained by Brian Beattie <beattie@beattie-home.net>
*
* 0.4.8 5/30/2002 * 0.4.8 5/30/2002
* - Added Mustek BearPaw 2400 TA. Thanks to Sergey * - Added Mustek BearPaw 2400 TA. Thanks to Sergey
* Vlasov <vsu@mivlgu.murom.ru>. * Vlasov <vsu@mivlgu.murom.ru>.
...@@ -332,12 +333,18 @@ ...@@ -332,12 +333,18 @@
* <oliver@neukum.name>. * <oliver@neukum.name>.
* *
* 0.4.10 01/07/2003 * 0.4.10 01/07/2003
* - Added vendor/product ids for Visioneer scanners. * - Added vendor/product ids for Artec, Canon, Compaq, Epson, HP, Microtek
* and Visioneer scanners. Thanks to William Lam <wklam@triad.rr.com>,
* Till Kamppeter <till.kamppeter@gmx.net> and others for all the ids.
* - Cleaned up list of vendor/product ids.
* - Print information about user-supplied ids only once at startup instead * - Print information about user-supplied ids only once at startup instead
* of everytime any USB device is plugged in. * of everytime any USB device is plugged in.
* - Removed PV8630 ioctls. Use the standard ioctls instead. * - Removed PV8630 ioctls. Use the standard ioctls instead.
* - Made endpoint detection more generic. Basically, only one bulk-in * - Made endpoint detection more generic. Basically, only one bulk-in
* endpoint is required, everything else is optional. * endpoint is required, everything else is optional.
* - New maintainer: Henning Meier-Geinitz.
* - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy.
* *
* TODO * TODO
* - Performance * - Performance
...@@ -360,7 +367,7 @@ ...@@ -360,7 +367,7 @@
* - All the developers that are working on USB SANE backends or other * - All the developers that are working on USB SANE backends or other
* applications to use USB scanners. * applications to use USB scanners.
* - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie * - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
* to be the new USB Scanner maintainer. * and Henning Meier-Geinitz to be the new USB Scanner maintainer.
* *
* Performance: * Performance:
* *
...@@ -369,6 +376,14 @@ ...@@ -369,6 +376,14 @@
* 24 Bit Color ~ 70 secs - 3.6 Mbit/sec * 24 Bit Color ~ 70 secs - 3.6 Mbit/sec
* 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */ * 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
/*
* For documentation, see Documentation/usb/scanner.txt.
* Website: http://www.meier-geinitz.de/kernel/
* Please contact the maintainer if your scanner is not detected by this
* driver automatically.
*/
#include <asm/byteorder.h> #include <asm/byteorder.h>
/* /*
...@@ -461,7 +476,7 @@ open_scanner(struct inode * inode, struct file * file) ...@@ -461,7 +476,7 @@ open_scanner(struct inode * inode, struct file * file)
} }
if (scn->isopen) { if (scn->isopen) {
err("open_scanner(%d): Scanner device is already open", scn_minor); dbg("open_scanner(%d): Scanner device is already open", scn_minor);
err = -EBUSY; err = -EBUSY;
goto out_error; goto out_error;
} }
...@@ -1047,6 +1062,9 @@ probe_scanner(struct usb_interface *intf, ...@@ -1047,6 +1062,9 @@ probe_scanner(struct usb_interface *intf,
if (scn->devfs == NULL) if (scn->devfs == NULL)
dbg("scanner%d: device node registration failed", scn_minor); dbg("scanner%d: device node registration failed", scn_minor);
info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
dev->descriptor.idVendor, dev->descriptor.idProduct, name);
up(&scn_mutex); up(&scn_mutex);
usb_set_intfdata(intf, scn); usb_set_intfdata(intf, scn);
......
This diff is collapsed.
...@@ -1324,6 +1324,9 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1324,6 +1324,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS 0xffff
#define USB_DEVICE_ID_MGE_UPS1 0x0001 #define USB_DEVICE_ID_MGE_UPS1 0x0001
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
struct hid_blacklist { struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
...@@ -1359,6 +1362,12 @@ struct hid_blacklist { ...@@ -1359,6 +1362,12 @@ struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -381,6 +381,83 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) ...@@ -381,6 +381,83 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
** **
***********************/ ***********************/
/* encapsulate in an AAL5 frame, which is then split into ATM cells */
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length)
{
unsigned int num_cells = (pdu_length + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
unsigned int num_pdu_cells = pdu_length / ATM_CELL_PAYLOAD + 1;
unsigned int aal5_length = num_cells * ATM_CELL_PAYLOAD;
unsigned int zero_padding = aal5_length - pdu_length - ATM_AAL5_TRAILER;
unsigned int final_length = num_cells * ATM_CELL_SIZE;
unsigned char aal5_trailer [ATM_AAL5_TRAILER];
unsigned char cell_header [ATM_CELL_HEADER];
u32 crc;
int i;
PDEBUG ("atmsar_encode entered\n");
PDEBUG ("pdu_length %d, num_cells %d, num_pdu_cells %d, aal5_length %d, zero_padding %d, final_length %d\n", pdu_length, num_cells, num_pdu_cells, aal5_length, zero_padding, final_length);
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
aal5_trailer [0] = 0; /* UU = 0 */
aal5_trailer [1] = 0; /* CPI = 0 */
aal5_trailer [2] = pdu_length >> 8;
aal5_trailer [3] = pdu_length;
crc = crc32 (~0, source, pdu_length);
for (i = 0; i < zero_padding; i++)
crc = CRC32 (0, crc);
crc = crc32 (crc, aal5_trailer, 4);
crc = ~crc;
aal5_trailer [4] = crc >> 24;
aal5_trailer [5] = crc >> 16;
aal5_trailer [6] = crc >> 8;
aal5_trailer [7] = crc;
cell_header [0] = ctx->atmHeader >> 24;
cell_header [1] = ctx->atmHeader >> 16;
cell_header [2] = ctx->atmHeader >> 8;
cell_header [3] = ctx->atmHeader;
cell_header [4] = 0xec;
for (i = 1; i < num_pdu_cells; i++) {
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, ATM_CELL_PAYLOAD);
target += ATM_CELL_PAYLOAD;
source += ATM_CELL_PAYLOAD;
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
}
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, pdu_length % ATM_CELL_PAYLOAD);
target += pdu_length % ATM_CELL_PAYLOAD;
if (num_pdu_cells < num_cells) {
memset (target, 0, zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD);
target += zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD;
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
zero_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
}
memset (target, 0, zero_padding);
target += zero_padding;
memcpy (target, aal5_trailer, ATM_AAL5_TRAILER);
/* set pti bit in last cell */
*(target + ATM_AAL5_TRAILER + 3 - ATM_CELL_SIZE) |= 0x2;
/* update stats */
if (ctx->stats)
atomic_inc (&ctx->stats->tx);
if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
atomic_add (num_cells, &(ctx->stats->tx));
return final_length;
}
struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb) struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
{ {
int number_of_cells = (skb->len) / 48; int number_of_cells = (skb->len) / 48;
...@@ -624,9 +701,8 @@ struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_b ...@@ -624,9 +701,8 @@ struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_b
} else { } else {
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) == if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
NULL) { NULL)
skb_trim (skb, 0); return NULL;
}
} }
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define ATMSAR_USE_53BYTE_CELL 0x1L #define ATMSAR_USE_53BYTE_CELL 0x1L
#define ATMSAR_SET_PTI 0x2L #define ATMSAR_SET_PTI 0x2L
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
/* types */ /* types */
#define ATMSAR_TYPE_AAL0 ATM_AAL0 #define ATMSAR_TYPE_AAL0 ATM_AAL0
...@@ -89,4 +90,6 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff ...@@ -89,4 +90,6 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff
struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size); struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size);
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length);
#endif /* _ATMSAR_H_ */ #endif /* _ATMSAR_H_ */
This diff is collapsed.
#
# Makefile for USB Network drivers which require generic MII code.
#
obj-$(CONFIG_USB_PEGASUS) += mii.o
...@@ -135,6 +135,7 @@ static struct usb_device_id id_table_sio [] = { ...@@ -135,6 +135,7 @@ static struct usb_device_id id_table_sio [] = {
static struct usb_device_id id_table_8U232AM [] = { static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -143,6 +144,7 @@ static struct usb_device_id id_table_8U232AM [] = { ...@@ -143,6 +144,7 @@ static struct usb_device_id id_table_8U232AM [] = {
static struct usb_device_id id_table_combined [] = { static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -17,11 +17,14 @@ ...@@ -17,11 +17,14 @@
* Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
* FTDI_SIO implementation. * FTDI_SIO implementation.
* *
* Philipp Ghring - pg@futureware.at - added the Device ID of the USB relais
* from Rudolf Gugler
*/ */
#define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */
......
...@@ -106,6 +106,7 @@ static struct usb_device_id ipaq_id_table [] = { ...@@ -106,6 +106,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) }, { USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
...@@ -126,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = { ...@@ -126,6 +127,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) }, { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) },
{ USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) }, { USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) },
{ USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) },
{ USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#define COMPAQ_IPAQ_ID 0x0003 #define COMPAQ_IPAQ_ID 0x0003
#define COMPAQ_0032_ID 0x0032 #define COMPAQ_0032_ID 0x0032
#define DELL_VENDOR_ID 0x413c
#define DELL_AXIM_ID 0x4001
#define HP_VENDOR_ID 0x03f0 #define HP_VENDOR_ID 0x03f0
#define HP_JORNADA_548_ID 0x1016 #define HP_JORNADA_548_ID 0x1016
#define HP_JORNADA_568_ID 0x1116 #define HP_JORNADA_568_ID 0x1116
...@@ -63,6 +66,7 @@ ...@@ -63,6 +66,7 @@
#define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_VENDOR_ID 0x0930
#define TOSHIBA_PRODUCT_ID 0x0700 #define TOSHIBA_PRODUCT_ID 0x0700
#define TOSHIBA_E740_ID 0x0706
#define HTC_VENDOR_ID 0x0bb4 #define HTC_VENDOR_ID 0x0bb4
#define HTC_PRODUCT_ID 0x00ce #define HTC_PRODUCT_ID 0x00ce
......
...@@ -74,6 +74,7 @@ static struct usb_device_id id_table [] = { ...@@ -74,6 +74,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -28,3 +28,6 @@ ...@@ -28,3 +28,6 @@
#define RATOC_VENDOR_ID 0x0584 #define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000 #define RATOC_PRODUCT_ID 0xb000
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
...@@ -27,14 +27,14 @@ ...@@ -27,14 +27,14 @@
extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us);
struct datafab_info { struct datafab_info {
unsigned long sectors; // total sector count unsigned long sectors; // total sector count
unsigned long ssize; // sector size in bytes unsigned long ssize; // sector size in bytes
char lun; // used for dual-slot readers char lun; // used for dual-slot readers
// the following aren't used yet // the following aren't used yet
unsigned char sense_key; unsigned char sense_key;
unsigned long sense_asc; // additional sense code unsigned long sense_asc; // additional sense code
unsigned long sense_ascq; // additional sense code qualifier unsigned long sense_ascq; // additional sense code qualifier
}; };
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
#define US_SC_UFI 0x04 /* Floppy */ #define US_SC_UFI 0x04 /* Floppy */
#define US_SC_8070 0x05 /* Removable media */ #define US_SC_8070 0x05 /* Removable media */
#define US_SC_SCSI 0x06 /* Transparent */ #define US_SC_SCSI 0x06 /* Transparent */
#define US_SC_ISD200 0x07 /* ISD200 ATA */ #define US_SC_ISD200 0x07 /* ISD200 ATA */
#define US_SC_MIN US_SC_RBC #define US_SC_MIN US_SC_RBC
#define US_SC_MAX US_SC_ISD200 #define US_SC_MAX US_SC_ISD200
......
...@@ -50,23 +50,25 @@ ...@@ -50,23 +50,25 @@
#include "transport.h" #include "transport.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h>
/*********************************************************************** /***********************************************************************
* Host functions * Host functions
***********************************************************************/ ***********************************************************************/
static const char* host_info(struct Scsi_Host *host) static const char* usb_storage_info(struct Scsi_Host *host)
{ {
return "SCSI emulation for USB Mass Storage devices"; return "SCSI emulation for USB Mass Storage devices";
} }
#if 0
/* detect a virtual adapter (always works) /* detect a virtual adapter (always works)
* Synchronization: 2.4: with the io_request_lock * Synchronization: 2.4: with the io_request_lock
* 2.5: no locks. * 2.5: no locks.
* fortunately we don't care. * fortunately we don't care.
* */ * */
static int detect(struct SHT *sht) static int usb_storage_detect(struct SHT *sht)
{ {
struct us_data *us; struct us_data *us;
char local_name[32]; char local_name[32];
...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht) ...@@ -109,7 +111,7 @@ static int detect(struct SHT *sht)
* the driver and we're doing each virtual host in turn, not in parallel * the driver and we're doing each virtual host in turn, not in parallel
* Synchronization: BKL, no spinlock. * Synchronization: BKL, no spinlock.
*/ */
static int release(struct Scsi_Host *psh) static int usb_storage_release(struct Scsi_Host *psh)
{ {
struct us_data *us = (struct us_data *)psh->hostdata[0]; struct us_data *us = (struct us_data *)psh->hostdata[0];
...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh) ...@@ -132,18 +134,11 @@ static int release(struct Scsi_Host *psh)
/* we always have a successful release */ /* we always have a successful release */
return 0; return 0;
} }
#endif
/* run command */
static int command( Scsi_Cmnd *srb )
{
US_DEBUGP("Bad use of us_command\n");
return DID_BAD_TARGET << 16;
}
/* queue a command */ /* queue a command */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) ...@@ -168,7 +163,7 @@ static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
/* Command abort */ /* Command abort */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int command_abort( Scsi_Cmnd *srb ) static int usb_storage_command_abort( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb ) ...@@ -187,7 +182,7 @@ static int command_abort( Scsi_Cmnd *srb )
/* This invokes the transport reset mechanism to reset the state of the /* This invokes the transport reset mechanism to reset the state of the
* device */ * device */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int device_reset( Scsi_Cmnd *srb ) static int usb_storage_device_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
int result; int result;
...@@ -202,11 +197,10 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -202,11 +197,10 @@ static int device_reset( Scsi_Cmnd *srb )
/* lock the device pointers */ /* lock the device pointers */
down(&(us->dev_semaphore)); down(&(us->dev_semaphore));
/* if the device was removed, then we're already reset */ /* do the reset */
if (!(us->flags & US_FL_DEV_ATTACHED)) result = us->transport_reset(us);
result = SUCCESS;
else /* unlock */
result = us->transport_reset(us);
up(&(us->dev_semaphore)); up(&(us->dev_semaphore));
/* lock access to the state and clear it */ /* lock access to the state and clear it */
...@@ -219,31 +213,26 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -219,31 +213,26 @@ static int device_reset( Scsi_Cmnd *srb )
* disconnect/reconnect for all drivers which have claimed * disconnect/reconnect for all drivers which have claimed
* interfaces, including ourself. */ * interfaces, including ourself. */
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int bus_reset( Scsi_Cmnd *srb )
/* FIXME: This needs to be re-examined in the face of the new
* hotplug system -- this will implicitly cause a detach/reattach of
* usb-storage, which is not what we want now.
*
* Can we just skip over usb-storage in the while loop?
*/
static int usb_storage_bus_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct us_data *us;
int i; int i;
int result; int result;
struct usb_device *pusb_dev_save;
/* we use the usb_reset_device() function to handle this for us */ /* we use the usb_reset_device() function to handle this for us */
US_DEBUGP("bus_reset() called\n"); US_DEBUGP("bus_reset() called\n");
scsi_unlock(srb->device->host); scsi_unlock(srb->device->host);
us = (struct us_data *)srb->device->host->hostdata[0];
/* if the device has been removed, this worked */
down(&us->dev_semaphore);
if (!(us->flags & US_FL_DEV_ATTACHED)) {
US_DEBUGP("-- device removed already\n");
up(&us->dev_semaphore);
scsi_lock(srb->device->host);
return SUCCESS;
}
pusb_dev_save = us->pusb_dev;
up(&us->dev_semaphore);
/* attempt to reset the port */ /* attempt to reset the port */
result = usb_reset_device(pusb_dev_save); result = usb_reset_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result); US_DEBUGP("usb_reset_device returns %d\n", result);
if (result < 0) { if (result < 0) {
scsi_lock(srb->device->host); scsi_lock(srb->device->host);
...@@ -253,9 +242,9 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -253,9 +242,9 @@ static int bus_reset( Scsi_Cmnd *srb )
/* FIXME: This needs to lock out driver probing while it's working /* FIXME: This needs to lock out driver probing while it's working
* or we can have race conditions */ * or we can have race conditions */
/* This functionality really should be provided by the khubd thread */ /* This functionality really should be provided by the khubd thread */
for (i = 0; i < pusb_dev_save->actconfig->desc.bNumInterfaces; i++) { for (i = 0; i < us->pusb_dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf = struct usb_interface *intf =
&pusb_dev_save->actconfig->interface[i]; &us->pusb_dev->actconfig->interface[i];
/* if this is an unclaimed interface, skip it */ /* if this is an unclaimed interface, skip it */
if (!intf->driver) { if (!intf->driver) {
...@@ -274,14 +263,6 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -274,14 +263,6 @@ static int bus_reset( Scsi_Cmnd *srb )
return SUCCESS; return SUCCESS;
} }
/* FIXME: This doesn't do anything right now */
static int host_reset( Scsi_Cmnd *srb )
{
printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
bus_reset(srb);
return FAILED;
}
/*********************************************************************** /***********************************************************************
* /proc/scsi/ functions * /proc/scsi/ functions
***********************************************************************/ ***********************************************************************/
...@@ -291,29 +272,23 @@ static int host_reset( Scsi_Cmnd *srb ) ...@@ -291,29 +272,23 @@ static int host_reset( Scsi_Cmnd *srb )
#define SPRINTF(args...) \ #define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
static int proc_info (char *buffer, char **start, off_t offset, int length, static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
int hostno, int inout) int length, int hostno, int inout)
{ {
struct us_data *us; struct us_data *us;
char *pos = buffer; char *pos = buffer;
struct Scsi_Host *hostptr;
/* if someone is sending us data, just throw it away */ /* if someone is sending us data, just throw it away */
if (inout) if (inout)
return length; return length;
/* lock the data structures */ /* find our data from the given hostno */
down(&us_list_semaphore); hostptr = scsi_host_hn_get(hostno);
if (!hostptr) { /* if we couldn't find it, we return an error */
/* find our data from hostno */ return -ESRCH;
us = us_list;
while (us) {
if (us->host_no == hostno)
break;
us = us->next;
} }
us = (struct us_data*)hostptr->hostdata[0];
/* release our lock on the data structures */
up(&us_list_semaphore);
/* if we couldn't find it, we return an error */ /* if we couldn't find it, we return an error */
if (!us) { if (!us) {
...@@ -332,10 +307,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -332,10 +307,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
SPRINTF(" Protocol: %s\n", us->protocol_name); SPRINTF(" Protocol: %s\n", us->protocol_name);
SPRINTF(" Transport: %s\n", us->transport_name); SPRINTF(" Transport: %s\n", us->transport_name);
/* show the GUID of the device */ /* release the reference count on this host */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); scsi_host_put(hostptr);
SPRINTF(" Attached: %s\n", (us->flags & US_FL_DEV_ATTACHED ?
"Yes" : "No"));
/* /*
* Calculate start of next buffer, and return value. * Calculate start of next buffer, and return value.
...@@ -351,33 +324,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -351,33 +324,69 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
} }
/* /*
* this defines our 'host' * this defines our host template, with which we'll allocate hosts
*/ */
Scsi_Host_Template usb_stor_host_template = { struct SHT usb_stor_host_template = {
.name = "usb-storage", /* basic userland interface stuff */
.proc_info = proc_info, .name = "usb-storage",
.info = host_info, .proc_name = "usb-storage",
.proc_info = usb_storage_proc_info,
.detect = detect, .proc_dir = NULL,
.release = release, .info = usb_storage_info,
.command = command, .ioctl = NULL,
.queuecommand = queuecommand,
/* old-style detect and release */
.eh_abort_handler = command_abort, .detect = NULL,
.eh_device_reset_handler =device_reset, .release = NULL,
.eh_bus_reset_handler = bus_reset,
.eh_host_reset_handler =host_reset, /* command interface -- queued only */
.command = NULL,
.can_queue = 1, .queuecommand = usb_storage_queuecommand,
.this_id = -1,
/* error and abort handlers */
.sg_tablesize = SG_ALL, .eh_abort_handler = usb_storage_command_abort,
.cmd_per_lun = 1, .eh_device_reset_handler = usb_storage_device_reset,
.present = 0, .eh_bus_reset_handler = usb_storage_bus_reset,
.unchecked_isa_dma = FALSE, .eh_host_reset_handler = NULL,
.use_clustering = TRUE, .eh_strategy_handler = NULL,
.emulated = TRUE
/* queue commands only, only one command per LUN */
.can_queue = 1,
.cmd_per_lun = 1,
/* unknown initiator id */
.this_id = -1,
/* no limit on commands */
.max_sectors = 0,
/* pre- and post- device scan functions */
.slave_alloc = NULL,
.slave_configure = NULL,
.slave_destroy = NULL,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL,
/* use 32-bit address space for DMA */
.unchecked_isa_dma = FALSE,
.highmem_io = FALSE,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal.
*/
.use_clustering = TRUE,
/* emulated HBA */
.emulated = TRUE,
/* sorry, no BIOS to help us */
.bios_param = NULL,
/* module management */
.module = THIS_MODULE
}; };
/* For a device that is "Not Ready" */ /* For a device that is "Not Ready" */
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_notready[18];
extern unsigned char usb_stor_sense_invalidCDB[18]; extern unsigned char usb_stor_sense_invalidCDB[18];
extern Scsi_Host_Template usb_stor_host_template; extern struct SHT usb_stor_host_template;
extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.h>
/** /**
* seq_open - initialize sequential file * seq_open - initialize sequential file
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment