Commit 0a310d2a authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/sparc-2.6

into kernel.bkbits.net:/home/davem/sparc-2.6
parents 89d3f699 4ab33f9d
This diff is collapsed.
This diff is collapsed.
...@@ -14,10 +14,10 @@ Index ...@@ -14,10 +14,10 @@ Index
4. Module dependencies 4. Module dependencies
5. Module loading 5. Module loading
6. Module parameters 6. Module parameters
7. Device control through "sysfs" 7. Optional device control through "sysfs"
8. Supported devices 8. Supported devices
9. How to add support for new image sensors 9. How to add support for new image sensors
10. Note for V4L2 developers 10. Notes for V4L2 application developers
11. Contact information 11. Contact information
12. Credits 12. Credits
...@@ -148,8 +148,8 @@ Default: 2 ...@@ -148,8 +148,8 @@ Default: 2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
7. Device control through "sysfs" 7. Optional device control through "sysfs"
================================= ==========================================
It is possible to read and write both the SN9C10[12] and the image sensor It is possible to read and write both the SN9C10[12] and the image sensor
registers by using the "sysfs" filesystem interface. registers by using the "sysfs" filesystem interface.
...@@ -206,7 +206,7 @@ Vendor ID Product ID ...@@ -206,7 +206,7 @@ Vendor ID Product ID
0xc45 0x6029 0xc45 0x6029
0xc45 0x602a 0xc45 0x602a
0xc45 0x602c 0xc45 0x602c
0xc45 0x8001 0xc45 0x6030
The list above does NOT imply that all those devices work with this driver: up The list above does NOT imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported. until now only the ones that mount the following image sensors are supported.
...@@ -242,19 +242,27 @@ At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA), ...@@ -242,19 +242,27 @@ At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
MI03 (VGA), OV7620 (VGA). MI03 (VGA), OV7620 (VGA).
10. Note for V4L2 developers 10. Notes for V4L2 application developers
============================ =========================================
This driver follows the V4L2 API specifications. In particular, it enforces two This driver follows the V4L2 API specifications. In particular, it enforces two
rules: rules:
1) Exactly one I/O method, either "mmap" or "read", is associated with each - exactly one I/O method, either "mmap" or "read", is associated with each
file descriptor. Once it is selected, the application must close and reopen the file descriptor. Once it is selected, the application must close and reopen the
device to switch to the other I/O method. device to switch to the other I/O method;
2) Previously mapped buffer memory must always be unmapped before calling any - previously mapped buffer memory must always be unmapped before calling any
of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. In case, of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. The same
the same number of buffers as before will be allocated again to match the size number of buffers as before will be allocated again to match the size of the
of the new video frames, so you have to map them again before any I/O attempts. new video frames, so you have to map them again before any I/O attempts.
Consistently with the hardware limits, this driver also supports image
downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions.
However the V4L2 API specifications don't correctly define how the scaling
factor can be choosen arbitrarily by the "negotiation" of the "source" and
"target" rectangles. To work around this flaw, we have added the convention
that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1.
11. Contact information 11. Contact information
......
...@@ -573,12 +573,12 @@ static inline void restart_syscall(struct pt_regs *regs) ...@@ -573,12 +573,12 @@ static inline void restart_syscall(struct pt_regs *regs)
* OK, we're invoking a handler * OK, we're invoking a handler
*/ */
static void static void
handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs, int syscall) struct pt_regs * regs, int syscall)
{ {
struct thread_info *thread = current_thread_info(); struct thread_info *thread = current_thread_info();
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct k_sigaction *ka = &tsk->sighand->action[sig-1];
int usig = sig; int usig = sig;
int ret; int ret;
...@@ -633,11 +633,8 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, ...@@ -633,11 +633,8 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
spin_unlock_irq(&tsk->sighand->siglock); spin_unlock_irq(&tsk->sighand->siglock);
} }
if (ret == 0) { if (ret == 0)
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
return; return;
}
force_sigsegv(sig, tsk); force_sigsegv(sig, tsk);
} }
...@@ -653,6 +650,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, ...@@ -653,6 +650,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
*/ */
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{ {
struct k_sigaction ka;
siginfo_t info; siginfo_t info;
int signr; int signr;
...@@ -673,9 +671,9 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) ...@@ -673,9 +671,9 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (current->ptrace & PT_SINGLESTEP) if (current->ptrace & PT_SINGLESTEP)
ptrace_cancel_bpt(current); ptrace_cancel_bpt(current);
signr = get_signal_to_deliver(&info, regs, NULL); signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) { if (signr > 0) {
handle_signal(signr, &info, oldset, regs, syscall); handle_signal(signr, &ka, &info, oldset, regs, syscall);
if (current->ptrace & PT_SINGLESTEP) if (current->ptrace & PT_SINGLESTEP)
ptrace_set_bpt(current); ptrace_set_bpt(current);
return 1; return 1;
......
...@@ -41,20 +41,21 @@ obj-$(CONFIG_SCx200) += scx200.o ...@@ -41,20 +41,21 @@ obj-$(CONFIG_SCx200) += scx200.o
# Note: kbuild does not track this dependency due to usage of .incbin # Note: kbuild does not track this dependency due to usage of .incbin
$(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so $(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so
targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so) targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so)
targets += vsyscall.lds
# The DSO images are built using a special linker script. # The DSO images are built using a special linker script.
quiet_cmd_syscall = SYSCALL $@ quiet_cmd_syscall = SYSCALL $@
cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@ -Wl,-T,$(filter-out FORCE,$^) -o $@
export AFLAGS_vsyscall.lds.o += -P -C -U$(ARCH) export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH)
vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1
SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags)
$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
$(obj)/vsyscall-%.so: $(src)/vsyscall.lds.s $(obj)/vsyscall-%.o FORCE $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
$(call if_changed,syscall) $(call if_changed,syscall)
# We also create a special relocatable object that should mirror the symbol # We also create a special relocatable object that should mirror the symbol
...@@ -65,5 +66,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o ...@@ -65,5 +66,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o
$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
SYSCFLAGS_vsyscall-syms.o = -r SYSCFLAGS_vsyscall-syms.o = -r
$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds.s $(obj)/vsyscall-sysenter.o FORCE $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE
$(call if_changed,syscall) $(call if_changed,syscall)
...@@ -145,6 +145,9 @@ ia32_gdt_init (void) ...@@ -145,6 +145,9 @@ ia32_gdt_init (void)
int cpu = smp_processor_id(); int cpu = smp_processor_id();
ia32_shared_page[cpu] = alloc_page(GFP_KERNEL); ia32_shared_page[cpu] = alloc_page(GFP_KERNEL);
if (!ia32_shared_page[cpu])
panic("failed to allocate ia32_shared_page[%d]\n", cpu);
cpu_gdt_table[cpu] = page_address(ia32_shared_page[cpu]); cpu_gdt_table[cpu] = page_address(ia32_shared_page[cpu]);
/* Copy from the boot cpu's GDT */ /* Copy from the boot cpu's GDT */
...@@ -161,6 +164,9 @@ ia32_boot_gdt_init (void) ...@@ -161,6 +164,9 @@ ia32_boot_gdt_init (void)
unsigned long ldt_size; unsigned long ldt_size;
ia32_shared_page[0] = alloc_page(GFP_KERNEL); ia32_shared_page[0] = alloc_page(GFP_KERNEL);
if (!ia32_shared_page[0])
panic("failed to allocate ia32_shared_page[0]\n");
ia32_boot_gdt = page_address(ia32_shared_page[0]); ia32_boot_gdt = page_address(ia32_shared_page[0]);
cpu_gdt_table[0] = ia32_boot_gdt; cpu_gdt_table[0] = ia32_boot_gdt;
......
#include <linux/module.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/io.h>
/* IBM Summit (EXA) Cyclone counter code*/ /* IBM Summit (EXA) Cyclone counter code*/
#define CYCLONE_CBAR_ADDR 0xFEB00CD0 #define CYCLONE_CBAR_ADDR 0xFEB00CD0
......
...@@ -781,8 +781,7 @@ GLOBAL_ENTRY(ia64_switch_mode_virt) ...@@ -781,8 +781,7 @@ GLOBAL_ENTRY(ia64_switch_mode_virt)
// going to virtual // going to virtual
// - for code addresses, set upper bits of addr to KERNEL_START // - for code addresses, set upper bits of addr to KERNEL_START
// - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the // - for stack addresses, copy from input argument
// lower bits since we want it to stay identity mapped
movl r18=KERNEL_START movl r18=KERNEL_START
dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT
dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT
......
...@@ -371,7 +371,7 @@ ia64_init_itm (void) ...@@ -371,7 +371,7 @@ ia64_init_itm (void)
itc_drift = -1; itc_drift = -1;
local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, "
"ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(), "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(),
platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* 03/05/07 davidm Switch from PCI-DMA to generic device DMA API. * 03/05/07 davidm Switch from PCI-DMA to generic device DMA API.
* 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid * 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid
* unnecessary i-cache flushing. * unnecessary i-cache flushing.
* 04/07/.. ak Better overflow handling. Assorted fixes.
*/ */
#include <linux/cache.h> #include <linux/cache.h>
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/ctype.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/pci.h> #include <asm/pci.h>
...@@ -46,6 +48,8 @@ ...@@ -46,6 +48,8 @@
*/ */
#define IO_TLB_SHIFT 11 #define IO_TLB_SHIFT 11
int swiotlb_force;
/* /*
* Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see
* if the memory was in fact allocated by this API. * if the memory was in fact allocated by this API.
...@@ -55,8 +59,16 @@ static char *io_tlb_start, *io_tlb_end; ...@@ -55,8 +59,16 @@ static char *io_tlb_start, *io_tlb_end;
/* /*
* The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end. * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end.
* This is command line adjustable via setup_io_tlb_npages. * This is command line adjustable via setup_io_tlb_npages.
* Default to 64MB.
*/
static unsigned long io_tlb_nslabs = 32768;
/*
* When the IOMMU overflows we return a fallback buffer. This sets the size.
*/ */
static unsigned long io_tlb_nslabs = 1024; static unsigned long io_tlb_overflow = 32*1024;
void *io_tlb_overflow_buffer;
/* /*
* This is a free list describing the number of free entries available from each index * This is a free list describing the number of free entries available from each index
...@@ -78,15 +90,19 @@ static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED; ...@@ -78,15 +90,19 @@ static spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED;
static int __init static int __init
setup_io_tlb_npages (char *str) setup_io_tlb_npages (char *str)
{ {
io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); if (isdigit(*str)) {
io_tlb_nslabs = simple_strtoul(str, &str, 0) << (PAGE_SHIFT - IO_TLB_SHIFT);
/* avoid tail segment of size < IO_TLB_SEGSIZE */ /* avoid tail segment of size < IO_TLB_SEGSIZE */
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
if (*str == ',')
++str;
if (!strcmp(str, "force"))
swiotlb_force = 1;
return 1; return 1;
} }
__setup("swiotlb=", setup_io_tlb_npages); __setup("swiotlb=", setup_io_tlb_npages);
/* make io_tlb_overflow tunable too? */
/* /*
* Statically reserve bounce buffer space and initialize bounce buffer data structures for * Statically reserve bounce buffer space and initialize bounce buffer data structures for
...@@ -102,7 +118,7 @@ swiotlb_init (void) ...@@ -102,7 +118,7 @@ swiotlb_init (void)
*/ */
io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
if (!io_tlb_start) if (!io_tlb_start)
BUG(); panic("Cannot allocate SWIOTLB buffer");
io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
/* /*
...@@ -116,8 +132,20 @@ swiotlb_init (void) ...@@ -116,8 +132,20 @@ swiotlb_init (void)
io_tlb_index = 0; io_tlb_index = 0;
io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
printk(KERN_INFO "Placing software IO TLB between 0x%p - 0x%p\n", /*
(void *) io_tlb_start, (void *) io_tlb_end); * Get the overflow emergency buffer
*/
io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
}
static inline int address_needs_mapping(struct device *hwdev, dma_addr_t addr)
{
dma_addr_t mask = 0xffffffff;
if (hwdev && hwdev->dma_mask)
mask = *hwdev->dma_mask;
return (addr & ~mask) != 0;
} }
/* /*
...@@ -184,11 +212,8 @@ map_single (struct device *hwdev, char *buffer, size_t size, int dir) ...@@ -184,11 +212,8 @@ map_single (struct device *hwdev, char *buffer, size_t size, int dir)
index = 0; index = 0;
} while (index != wrap); } while (index != wrap);
/* spin_unlock_irqrestore(&io_tlb_lock, flags);
* XXX What is a suitable recovery mechanism here? We cannot return NULL;
* sleep because we are called from with in interrupts!
*/
panic("map_single: could not allocate software IO TLB (%ld bytes)", size);
} }
found: found:
spin_unlock_irqrestore(&io_tlb_lock, flags); spin_unlock_irqrestore(&io_tlb_lock, flags);
...@@ -285,7 +310,7 @@ swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handl ...@@ -285,7 +310,7 @@ swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handl
memset(ret, 0, size); memset(ret, 0, size);
dev_addr = virt_to_phys(ret); dev_addr = virt_to_phys(ret);
if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) if (address_needs_mapping(hwdev,dev_addr))
panic("swiotlb_alloc_consistent: allocated memory is out of range for device"); panic("swiotlb_alloc_consistent: allocated memory is out of range for device");
*dma_handle = dev_addr; *dma_handle = dev_addr;
return ret; return ret;
...@@ -297,6 +322,28 @@ swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_ ...@@ -297,6 +322,28 @@ swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_
free_pages((unsigned long) vaddr, get_order(size)); free_pages((unsigned long) vaddr, get_order(size));
} }
static void swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
{
/*
* Ran out of IOMMU space for this operation. This is very bad.
* Unfortunately the drivers cannot handle this operation properly.
* unless they check for pci_dma_mapping_error (most don't)
* When the mapping is small enough return a static buffer to limit
* the damage, or panic when the transfer is too big.
*/
printk(KERN_ERR
"PCI-DMA: Out of SW-IOMMU space for %lu bytes at device %s\n",
size, dev ? dev->bus_id : "?");
if (size > io_tlb_overflow && do_panic) {
if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
panic("PCI-DMA: Memory would be corrupted\n");
if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL)
panic("PCI-DMA: Random memory would be DMAed\n");
}
}
/* /*
* Map a single buffer of the indicated size for DMA in streaming mode. The PCI address * Map a single buffer of the indicated size for DMA in streaming mode. The PCI address
* to use is returned. * to use is returned.
...@@ -308,13 +355,14 @@ dma_addr_t ...@@ -308,13 +355,14 @@ dma_addr_t
swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir)
{ {
unsigned long dev_addr = virt_to_phys(ptr); unsigned long dev_addr = virt_to_phys(ptr);
void *map;
if (dir == DMA_NONE) if (dir == DMA_NONE)
BUG(); BUG();
/* /*
* Check if the PCI device can DMA to ptr... if so, just return ptr * Check if the PCI device can DMA to ptr... if so, just return ptr
*/ */
if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) == 0) if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
/* /*
* Device is bit capable of DMA'ing to the buffer... just return the PCI * Device is bit capable of DMA'ing to the buffer... just return the PCI
* address of ptr * address of ptr
...@@ -324,12 +372,18 @@ swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) ...@@ -324,12 +372,18 @@ swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir)
/* /*
* get a bounce buffer: * get a bounce buffer:
*/ */
dev_addr = virt_to_phys(map_single(hwdev, ptr, size, dir)); map = map_single(hwdev, ptr, size, dir);
if (!map) {
swiotlb_full(hwdev, size, dir, 1);
map = io_tlb_overflow_buffer;
}
dev_addr = virt_to_phys(map);
/* /*
* Ensure that the address returned is DMA'ble: * Ensure that the address returned is DMA'ble:
*/ */
if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) if (address_needs_mapping(hwdev, dev_addr))
panic("map_single: bounce buffer is not DMA'ble"); panic("map_single: bounce buffer is not DMA'ble");
return dev_addr; return dev_addr;
...@@ -437,9 +491,17 @@ swiotlb_map_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int di ...@@ -437,9 +491,17 @@ swiotlb_map_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int di
for (i = 0; i < nelems; i++, sg++) { for (i = 0; i < nelems; i++, sg++) {
addr = SG_ENT_VIRT_ADDRESS(sg); addr = SG_ENT_VIRT_ADDRESS(sg);
dev_addr = virt_to_phys(addr); dev_addr = virt_to_phys(addr);
if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
sg->dma_address = (dma_addr_t) map_single(hwdev, addr, sg->length, dir); sg->dma_address = (dma_addr_t) virt_to_phys(map_single(hwdev, addr, sg->length, dir));
else if (!sg->dma_address) {
/* Don't panic here, we expect pci_map_sg users
to do proper error handling. */
swiotlb_full(hwdev, sg->length, dir, 0);
swiotlb_unmap_sg(hwdev, sg - i, i, dir);
sg[0].dma_length = 0;
return 0;
}
} else
sg->dma_address = dev_addr; sg->dma_address = dev_addr;
sg->dma_length = sg->length; sg->dma_length = sg->length;
} }
...@@ -460,7 +522,7 @@ swiotlb_unmap_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int ...@@ -460,7 +522,7 @@ swiotlb_unmap_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int
for (i = 0; i < nelems; i++, sg++) for (i = 0; i < nelems; i++, sg++)
if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir);
else if (dir == DMA_FROM_DEVICE) else if (dir == DMA_FROM_DEVICE)
mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
} }
...@@ -501,7 +563,7 @@ swiotlb_sync_sg_for_device (struct device *hwdev, struct scatterlist *sg, int ne ...@@ -501,7 +563,7 @@ swiotlb_sync_sg_for_device (struct device *hwdev, struct scatterlist *sg, int ne
int int
swiotlb_dma_mapping_error (dma_addr_t dma_addr) swiotlb_dma_mapping_error (dma_addr_t dma_addr)
{ {
return 0; return (dma_addr == virt_to_phys(io_tlb_overflow_buffer));
} }
/* /*
......
# arch/ia64/sn/fakeprom/Makefile
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved.
#
# Medusa fake PROM support
#
EXTRA_TARGETS := fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o \
fprom vmlinux.sym
OBJS := $(obj)/fpromasm.o $(obj)/main.o $(obj)/fw-emu.o $(obj)/fpmem.o \
$(obj)/klgraph_init.o
LDFLAGS_fprom = -static -T
.PHONY: fprom
fprom: $(obj)/fprom
$(obj)/fprom: $(src)/fprom.lds $(OBJS) arch/ia64/lib/lib.a FORCE
$(call if_changed,ld)
$(obj)/vmlinux.sym: $(src)/make_textsym System.map
$(src)/make_textsym vmlinux > vmlinux.sym
$(call cmd,cptotop)
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
*/
This directory contains the files required to build
the fake PROM image that is currently being used to
boot IA64 kernels running under the SGI Medusa kernel.
The FPROM currently provides the following functions:
- PAL emulation for all PAL calls we've made so far.
- SAL emulation for all SAL calls we've made so far.
- EFI emulation for all EFI calls we've made so far.
- builds the "ia64_bootparam" structure that is
passed to the kernel from SAL. This structure
shows the cpu & memory configurations.
- supports medusa boottime options for changing
the number of cpus present
- supports medusa boottime options for changing
the memory configuration.
At some point, this fake PROM will be replaced by the
real PROM.
To build a fake PROM, cd to this directory & type:
make
This will (or should) build a fake PROM named "fprom".
Use this fprom image when booting the Medusa simulator. The
control file used to boot Medusa should include the
following lines:
load fprom
load vmlinux
sr pc 0x100000
sr g 9 <address of kernel _start function> #(currently 0xe000000000520000)
NOTE: There is a script "runsim" in this directory that can be used to
simplify setting up an environment for running under Medusa.
The following parameters may be passed to the fake PROM to
control the PAL/SAL/EFI parameters passed to the kernel:
GR[8] = # of cpus
GR[9] = address of primary entry point into the kernel
GR[20] = memory configuration for node 0
GR[21] = memory configuration for node 1
GR[22] = memory configuration for node 2
GR[23] = memory configuration for node 3
Registers GR[20] - GR[23] contain information to specify the
amount of memory present on nodes 0-3.
- if nothing is specified (all registers are 0), the configuration
defaults to 8 MB on node 0.
- a mem config entry for node N is passed in GR[20+N]
- a mem config entry consists of 8 hex digits. Each digit gives the
amount of physical memory available on the node starting at
1GB*<dn>, where dn is the digit number. The amount of memory
is 8MB*2**<d>. (If <d> = 0, the memory size is 0).
SN1 doesn't support dimms this small but small memory systems
boot faster on Medusa.
An example helps a lot. The following specifies that node 0 has
physical memory 0 to 8MB and 1GB to 1GB+32MB, and that node 1 has
64MB starting at address 0 of the node which is 8GB.
gr[20] = 0x21 # 0 to 8MB, 1GB to 1GB+32MB
gr[21] = 0x4 # 8GB to 8GB+64MB
/*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
/*
* FPROM EFI memory descriptor build routines
*
* - Routines to build the EFI memory descriptor map
* - Should also be usable by the SGI prom to convert
* klconfig to efi_memmap
*/
#include <linux/config.h>
#include <linux/efi.h>
#include "fpmem.h"
/*
* args points to a layout in memory like this
*
* 32 bit 32 bit
*
* numnodes numcpus
*
* 16 bit 16 bit 32 bit
* nasid0 cpuconf membankdesc0
* nasid1 cpuconf membankdesc1
* .
* .
* .
* .
* .
*/
sn_memmap_t *sn_memmap ;
sn_config_t *sn_config ;
/*
* There is a hole in the node 0 address space. Dont put it
* in the memory map
*/
#define NODE0_HOLE_SIZE (20*MB)
#define NODE0_HOLE_END (4UL*GB)
#define MB (1024*1024)
#define GB (1024*MB)
#define KERNEL_SIZE (4*MB)
#define PROMRESERVED_SIZE (1*MB)
#ifdef SGI_SN2
#define PHYS_ADDRESS(_n, _x) (((long)_n<<38) | (long)_x | 0x3000000000UL)
#define MD_BANK_SHFT 34
#endif
/*
* For SN, this may not take an arg and gets the numnodes from
* the prom variable or by traversing klcfg or promcfg
*/
int
GetNumNodes(void)
{
return sn_config->nodes;
}
int
GetNumCpus(void)
{
return sn_config->cpus;
}
/* For SN, get the index th nasid */
int
GetNasid(int index)
{
return sn_memmap[index].nasid ;
}
node_memmap_t
GetMemBankInfo(int index)
{
return sn_memmap[index].node_memmap ;
}
int
IsCpuPresent(int cnode, int cpu)
{
return sn_memmap[cnode].cpuconfig & (1UL<<cpu);
}
/*
* Made this into an explicit case statement so that
* we can assign specific properties to banks like bank0
* actually disabled etc.
*/
#ifdef SGI_SN2
int
IsBankPresent(int index, node_memmap_t nmemmap)
{
switch (index) {
case 0:return BankPresent(nmemmap.b0size);
case 1:return BankPresent(nmemmap.b1size);
case 2:return BankPresent(nmemmap.b2size);
case 3:return BankPresent(nmemmap.b3size);
default:return -1 ;
}
}
int
GetBankSize(int index, node_memmap_t nmemmap)
{
/*
* Add 2 because there are 4 dimms per bank.
*/
switch (index) {
case 0:return 2 + ((long)nmemmap.b0size + nmemmap.b0dou);
case 1:return 2 + ((long)nmemmap.b1size + nmemmap.b1dou);
case 2:return 2 + ((long)nmemmap.b2size + nmemmap.b2dou);
case 3:return 2 + ((long)nmemmap.b3size + nmemmap.b3dou);
default:return -1 ;
}
}
#endif
void
build_mem_desc(efi_memory_desc_t *md, int type, long paddr, long numbytes, long attr)
{
md->type = type;
md->phys_addr = paddr;
md->virt_addr = 0;
md->num_pages = numbytes >> 12;
md->attribute = attr;
}
int
build_efi_memmap(void *md, int mdsize)
{
int numnodes = GetNumNodes() ;
int cnode,bank ;
int nasid ;
node_memmap_t membank_info ;
int bsize;
int count = 0 ;
long paddr, hole, numbytes;
for (cnode=0;cnode<numnodes;cnode++) {
nasid = GetNasid(cnode) ;
membank_info = GetMemBankInfo(cnode) ;
for (bank=0;bank<MD_BANKS_PER_NODE;bank++) {
if (IsBankPresent(bank, membank_info)) {
bsize = GetBankSize(bank, membank_info) ;
paddr = PHYS_ADDRESS(nasid, (long)bank<<MD_BANK_SHFT);
numbytes = BankSizeBytes(bsize);
#ifdef SGI_SN2
/*
* Ignore directory.
* Shorten memory chunk by 1 page - makes a better
* testcase & is more like the real PROM.
*/
numbytes = numbytes * 31 / 32;
#endif
/*
* Only emulate the memory prom grabs
* if we have lots of memory, to allow
* us to simulate smaller memory configs than
* we can actually run on h/w. Otherwise,
* linux throws away a whole "granule".
*/
if (cnode == 0 && bank == 0 &&
numbytes > 128*1024*1024) {
numbytes -= 1000;
}
/*
* Check for the node 0 hole. Since banks cant
* span the hole, we only need to check if the end of
* the range is the end of the hole.
*/
if (paddr+numbytes == NODE0_HOLE_END)
numbytes -= NODE0_HOLE_SIZE;
/*
* UGLY hack - we must skip overr the kernel and
* PROM runtime services but we dont exactly where it is.
* So lets just reserve:
* node 0
* 0-1MB for PAL
* 1-4MB for SAL
* node 1-N
* 0-1 for SAL
*/
if (bank == 0) {
if (cnode == 0) {
hole = 2*1024*1024;
build_mem_desc(md, EFI_PAL_CODE, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
hole = 1*1024*1024;
build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, hole, EFI_MEMORY_UC);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
hole = 1*1024*1024;
build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
} else {
hole = 2*1024*1024;
build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
hole = 2*1024*1024;
build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_UC);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
}
}
build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes, EFI_MEMORY_WB|EFI_MEMORY_WB);
md += mdsize ;
count++ ;
}
}
}
return count ;
}
void
build_init(unsigned long args)
{
sn_config = (sn_config_t *) (args);
sn_memmap = (sn_memmap_t *)(args + 8) ; /* SN equiv for this is */
/* init to klconfig start */
}
/*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/config.h>
/*
* Structure of the mem config of the node as a SN MI reg
* Medusa supports this reg config.
*
* BankSize nibble to bank size mapping
*
* 1 - 64 MB
* 2 - 128 MB
* 3 - 256 MB
* 4 - 512 MB
* 5 - 1024 MB (1GB)
*/
#define MBSHIFT 20
#ifdef SGI_SN2
typedef struct node_memmap_s
{
unsigned int b0size :3, /* 0-2 bank 0 size */
b0dou :1, /* 3 bank 0 is 2-sided */
ena0 :1, /* 4 bank 0 enabled */
r0 :3, /* 5-7 reserved */
b1size :3, /* 8-10 bank 1 size */
b1dou :1, /* 11 bank 1 is 2-sided */
ena1 :1, /* 12 bank 1 enabled */
r1 :3, /* 13-15 reserved */
b2size :3, /* 16-18 bank 2 size */
b2dou :1, /* 19 bank 1 is 2-sided */
ena2 :1, /* 20 bank 2 enabled */
r2 :3, /* 21-23 reserved */
b3size :3, /* 24-26 bank 3 size */
b3dou :1, /* 27 bank 3 is 2-sided */
ena3 :1, /* 28 bank 3 enabled */
r3 :3; /* 29-31 reserved */
} node_memmap_t ;
#define SN2_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */
#define BankPresent(bsize) (bsize<6)
#define BankSizeBytes(bsize) (BankPresent(bsize) ? 1UL<<((bsize)+SN2_BANK_SIZE_SHIFT) : 0)
#define MD_BANKS_PER_NODE 4
#define MD_BANKSIZE (1UL << 34)
#endif
typedef struct sn_memmap_s
{
short nasid ;
short cpuconfig;
node_memmap_t node_memmap ;
} sn_memmap_t ;
typedef struct sn_config_s
{
int cpus;
int nodes;
sn_memmap_t memmap[1]; /* start of array */
} sn_config_t;
extern void build_init(unsigned long);
extern int build_efi_memmap(void *, int);
extern int GetNumNodes(void);
extern int GetNumCpus(void);
extern int IsCpuPresent(int, int);
extern int GetNasid(int);
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
*/
OUTPUT_FORMAT("elf64-ia64-little")
OUTPUT_ARCH(ia64)
ENTRY(_start)
SECTIONS
{
v = 0x0000000000000000 ; /* this symbol is here to make debugging with kdb easier... */
. = (0x000000000000000 + 0x100000) ;
_text = .;
.text : AT(ADDR(.text) - 0x0000000000000000 )
{
*(__ivt_section)
/* these are not really text pages, but the zero page needs to be in a fixed location: */
*(__special_page_section)
__start_gate_section = .;
*(__gate_section)
__stop_gate_section = .;
*(.text)
}
/* Global data */
_data = .;
.rodata : AT(ADDR(.rodata) - 0x0000000000000000 )
{ *(.rodata) *(.rodata.*) }
.opd : AT(ADDR(.opd) - 0x0000000000000000 )
{ *(.opd) }
.data : AT(ADDR(.data) - 0x0000000000000000 )
{ *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
__gp = ALIGN (8) + 0x200000;
.got : AT(ADDR(.got) - 0x0000000000000000 )
{ *(.got.plt) *(.got) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : AT(ADDR(.sdata) - 0x0000000000000000 )
{ *(.sdata) }
_edata = .;
_bss = .;
.sbss : AT(ADDR(.sbss) - 0x0000000000000000 )
{ *(.sbss) *(.scommon) }
.bss : AT(ADDR(.bss) - 0x0000000000000000 )
{ *(.bss) *(COMMON) }
. = ALIGN(64 / 8);
_end = .;
/* Sections to be discarded */
/DISCARD/ : {
*(.text.exit)
*(.data.exit)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
/* Discard them for now since Intel SoftSDV cannot handle them.
.comment 0 : { *(.comment) }
.note 0 : { *(.note) }
*/
/DISCARD/ : { *(.comment) }
/DISCARD/ : { *(.note) }
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <asm/bitops.h>
extern void klgraph_init(void);
void bedrock_init(int);
void synergy_init(int, int);
void sys_fw_init (const char *args, int arglen, int bsp);
volatile int bootmaster=0; /* Used to pick bootmaster */
volatile int nasidmaster[128]={0}; /* Used to pick node/synergy masters */
int init_done=0;
extern int bsp_lid;
#define get_bit(b,p) (((*p)>>(b))&1)
int
fmain(int lid, int bsp) {
int syn, nasid, cpu;
/*
* First lets figure out who we are. This is done from the
* LID passed to us.
*/
nasid = (lid>>16)&0xfff;
cpu = (lid>>28)&3;
syn = 0;
/*
* Now pick a nasid master to initialize Bedrock registers.
*/
if (test_and_set_bit(8, &nasidmaster[nasid]) == 0) {
bedrock_init(nasid);
test_and_set_bit(9, &nasidmaster[nasid]);
} else
while (get_bit(9, &nasidmaster[nasid]) == 0);
/*
* Now pick a BSP & finish init.
*/
if (test_and_set_bit(0, &bootmaster) == 0) {
sys_fw_init(0, 0, bsp);
test_and_set_bit(1, &bootmaster);
} else
while (get_bit(1, &bootmaster) == 0);
return (lid == bsp_lid);
}
void
bedrock_init(int nasid)
{
nasid = nasid; /* to quiet gcc */
#if 0
/*
* Undef if you need fprom to generate a 1 node klgraph
* information .. only works for 1 node for nasid 0.
*/
klgraph_init();
#endif
}
void
synergy_init(int nasid, int syn)
{
long *base;
long off;
/*
* Enable all FSB flashed interrupts.
* I'd really like defines for this......
*/
base = (long*)0x80000e0000000000LL; /* base of synergy regs */
for (off = 0x2a0; off < 0x2e0; off+=8) /* offset for VEC_MASK_{0-3}_A/B */
*(base+off/8) = -1LL;
/*
* Set the NASID in the FSB_CONFIG register.
*/
base = (long*)0x80000e0000000450LL;
*base = (long)((nasid<<16)|(syn<<9));
}
/* Why isnt there a bcopy/memcpy in lib64.a */
void*
memcpy(void * dest, const void *src, size_t count)
{
char *s, *se, *d;
for(d=dest, s=(char*)src, se=s+count; s<se; s++, d++)
*d = *s;
return dest;
}
#!/bin/sh
#
# Build a textsym file for use in the Arium ITP probe.
#
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved.
#
help() {
cat <<END
Build a WinDD "symtxt" file for use with the Arium ECM-30 probe.
Usage: $0 [<vmlinux file> [<output file>]]
If no input file is specified, it defaults to vmlinux.
If no output file name is specified, it defaults to "textsym".
END
exit 1
}
err () {
echo "ERROR - $*" >&2
exit 1
}
OPTS="H"
while getopts "$OPTS" c ; do
case $c in
H) help;;
\?) help;;
esac
done
shift `expr $OPTIND - 1`
#OBJDUMP=/usr/bin/ia64-linux-objdump
LINUX=${1:-vmlinux}
TEXTSYM=${2:-${LINUX}.sym}
TMPSYM=${2:-${LINUX}.sym.tmp}
trap "/bin/rm -f $TMPSYM" 0
[ -f $VMLINUX ] || help
$OBJDUMP -t $LINUX | egrep -v '__ks' | sort > $TMPSYM
SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l`
# Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE.
# Eventually, these values should be:
# dataprefix ffffffff
# textprefix fffffffe
# but right now they're still changing, so make them dynamic.
dataprefix=`awk ' / \.data / { print substr($1, 0, 8) ; exit ; }' $TMPSYM`
textprefix=`awk ' / \.text / { print substr($1, 0, 8) ; exit ; }' $TMPSYM`
# pipe everything thru sort
echo "TEXTSYM V1.0"
(cat <<END
GLOBAL | ${textprefix}00000000 | CODE | VEC_VHPT_Translation_0000
GLOBAL | ${textprefix}00000400 | CODE | VEC_ITLB_0400
GLOBAL | ${textprefix}00000800 | CODE | VEC_DTLB_0800
GLOBAL | ${textprefix}00000c00 | CODE | VEC_Alt_ITLB_0c00
GLOBAL | ${textprefix}00001000 | CODE | VEC_Alt_DTLB_1000
GLOBAL | ${textprefix}00001400 | CODE | VEC_Data_nested_TLB_1400
GLOBAL | ${textprefix}00001800 | CODE | VEC_Instruction_Key_Miss_1800
GLOBAL | ${textprefix}00001c00 | CODE | VEC_Data_Key_Miss_1c00
GLOBAL | ${textprefix}00002000 | CODE | VEC_Dirty-bit_2000
GLOBAL | ${textprefix}00002400 | CODE | VEC_Instruction_Access-bit_2400
GLOBAL | ${textprefix}00002800 | CODE | VEC_Data_Access-bit_2800
GLOBAL | ${textprefix}00002c00 | CODE | VEC_Break_instruction_2c00
GLOBAL | ${textprefix}00003000 | CODE | VEC_External_Interrupt_3000
GLOBAL | ${textprefix}00003400 | CODE | VEC_Reserved_3400
GLOBAL | ${textprefix}00003800 | CODE | VEC_Reserved_3800
GLOBAL | ${textprefix}00003c00 | CODE | VEC_Reserved_3c00
GLOBAL | ${textprefix}00004000 | CODE | VEC_Reserved_4000
GLOBAL | ${textprefix}00004400 | CODE | VEC_Reserved_4400
GLOBAL | ${textprefix}00004800 | CODE | VEC_Reserved_4800
GLOBAL | ${textprefix}00004c00 | CODE | VEC_Reserved_4c00
GLOBAL | ${textprefix}00005000 | CODE | VEC_Page_Not_Present_5000
GLOBAL | ${textprefix}00005100 | CODE | VEC_Key_Permission_5100
GLOBAL | ${textprefix}00005200 | CODE | VEC_Instruction_Access_Rights_5200
GLOBAL | ${textprefix}00005300 | CODE | VEC_Data_Access_Rights_5300
GLOBAL | ${textprefix}00005400 | CODE | VEC_General_Exception_5400
GLOBAL | ${textprefix}00005500 | CODE | VEC_Disabled_FP-Register_5500
GLOBAL | ${textprefix}00005600 | CODE | VEC_Nat_Consumption_5600
GLOBAL | ${textprefix}00005700 | CODE | VEC_Speculation_5700
GLOBAL | ${textprefix}00005800 | CODE | VEC_Reserved_5800
GLOBAL | ${textprefix}00005900 | CODE | VEC_Debug_5900
GLOBAL | ${textprefix}00005a00 | CODE | VEC_Unaligned_Reference_5a00
GLOBAL | ${textprefix}00005b00 | CODE | VEC_Unsupported_Data_Reference_5b00
GLOBAL | ${textprefix}00005c00 | CODE | VEC_Floating-Point_Fault_5c00
GLOBAL | ${textprefix}00005d00 | CODE | VEC_Floating_Point_Trap_5d00
GLOBAL | ${textprefix}00005e00 | CODE | VEC_Lower_Privilege_Tranfer_Trap_5e00
GLOBAL | ${textprefix}00005f00 | CODE | VEC_Taken_Branch_Trap_5f00
GLOBAL | ${textprefix}00006000 | CODE | VEC_Single_Step_Trap_6000
GLOBAL | ${textprefix}00006100 | CODE | VEC_Reserved_6100
GLOBAL | ${textprefix}00006200 | CODE | VEC_Reserved_6200
GLOBAL | ${textprefix}00006300 | CODE | VEC_Reserved_6300
GLOBAL | ${textprefix}00006400 | CODE | VEC_Reserved_6400
GLOBAL | ${textprefix}00006500 | CODE | VEC_Reserved_6500
GLOBAL | ${textprefix}00006600 | CODE | VEC_Reserved_6600
GLOBAL | ${textprefix}00006700 | CODE | VEC_Reserved_6700
GLOBAL | ${textprefix}00006800 | CODE | VEC_Reserved_6800
GLOBAL | ${textprefix}00006900 | CODE | VEC_IA-32_Exeception_6900
GLOBAL | ${textprefix}00006a00 | CODE | VEC_IA-32_Intercept_6a00
GLOBAL | ${textprefix}00006b00 | CODE | VEC_IA-32_Interrupt_6b00
GLOBAL | ${textprefix}00006c00 | CODE | VEC_Reserved_6c00
GLOBAL | ${textprefix}00006d00 | CODE | VEC_Reserved_6d00
GLOBAL | ${textprefix}00006e00 | CODE | VEC_Reserved_6e00
GLOBAL | ${textprefix}00006f00 | CODE | VEC_Reserved_6f00
GLOBAL | ${textprefix}00007000 | CODE | VEC_Reserved_7000
GLOBAL | ${textprefix}00007100 | CODE | VEC_Reserved_7100
GLOBAL | ${textprefix}00007200 | CODE | VEC_Reserved_7200
GLOBAL | ${textprefix}00007300 | CODE | VEC_Reserved_7300
GLOBAL | ${textprefix}00007400 | CODE | VEC_Reserved_7400
GLOBAL | ${textprefix}00007500 | CODE | VEC_Reserved_7500
GLOBAL | ${textprefix}00007600 | CODE | VEC_Reserved_7600
GLOBAL | ${textprefix}00007700 | CODE | VEC_Reserved_7700
GLOBAL | ${textprefix}00007800 | CODE | VEC_Reserved_7800
GLOBAL | ${textprefix}00007900 | CODE | VEC_Reserved_7900
GLOBAL | ${textprefix}00007a00 | CODE | VEC_Reserved_7a00
GLOBAL | ${textprefix}00007b00 | CODE | VEC_Reserved_7b00
GLOBAL | ${textprefix}00007c00 | CODE | VEC_Reserved_7c00
GLOBAL | ${textprefix}00007d00 | CODE | VEC_Reserved_7d00
GLOBAL | ${textprefix}00007e00 | CODE | VEC_Reserved_7e00
GLOBAL | ${textprefix}00007f00 | CODE | VEC_Reserved_7f00
END
awk '
/ _start$/ {start=1}
/ start_ap$/ {start=1}
/__start_gate_section/ {start=1}
/^'${dataprefix}\|${textprefix}'/ {
if ($4 == ".kdb")
next
if (start && substr($NF,1,1) != "0") {
type = substr($0,26,5)
if (type == ".text")
printf "GLOBAL | %s | CODE | %s\n", $1, $NF
else {
n = 0
s = $(NF-1)
while (length(s) > 0) {
n = n*16 + (index("0123456789abcdef", substr(s,1,1)) - 1)
s = substr(s,2)
}
printf "GLOBAL | %s | DATA | %s | %d\n", $1, $NF, n
}
}
if($NF == "_end")
exit
}
' $TMPSYM ) | egrep -v " __device| __vendor" | awk -v sn1="$SN1" '
/GLOBAL/ {
print $0
if (sn1 != 0) {
/* 32 bits of sn1 physical addrs, */
print substr($0,1,9) "04" substr($0,20,16) "Phy_" substr($0,36)
} else {
/* 38 bits of sn2 physical addrs, need addr space bits */
print substr($0,1,9) "3004" substr($0,20,16) "Phy_" substr($0,36)
}
} ' | sort -k3
N=`wc -l $TEXTSYM|awk '{print $1}'`
echo "Generated TEXTSYM file" >&2
echo " $LINUX --> $TEXTSYM" >&2
echo " Found $N symbols" >&2
This diff is collapsed.
...@@ -290,6 +290,7 @@ sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -290,6 +290,7 @@ sn_pci_fixup_slot(struct pci_dev *dev)
addr |= __IA64_UNCACHED_OFFSET; addr |= __IA64_UNCACHED_OFFSET;
dev->resource[idx].start = addr; dev->resource[idx].start = addr;
dev->resource[idx].end = addr + size; dev->resource[idx].end = addr + size;
dev->resource[idx].parent = &ioport_resource;
} }
if (dev->resource[idx].flags & IORESOURCE_IO) if (dev->resource[idx].flags & IORESOURCE_IO)
...@@ -322,6 +323,7 @@ sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -322,6 +323,7 @@ sn_pci_fixup_slot(struct pci_dev *dev)
addr |= __IA64_UNCACHED_OFFSET; addr |= __IA64_UNCACHED_OFFSET;
dev->resource[idx].start = addr; dev->resource[idx].start = addr;
dev->resource[idx].end = addr + size; dev->resource[idx].end = addr + size;
dev->resource[idx].parent = &iomem_resource;
} }
if (dev->resource[idx].flags & IORESOURCE_MEM) if (dev->resource[idx].flags & IORESOURCE_MEM)
...@@ -351,6 +353,7 @@ sn_pci_fixup_slot(struct pci_dev *dev) ...@@ -351,6 +353,7 @@ sn_pci_fixup_slot(struct pci_dev *dev)
addr |= __IA64_UNCACHED_OFFSET; addr |= __IA64_UNCACHED_OFFSET;
dev->resource[PCI_ROM_RESOURCE].start = addr; dev->resource[PCI_ROM_RESOURCE].start = addr;
dev->resource[PCI_ROM_RESOURCE].end = addr + size; dev->resource[PCI_ROM_RESOURCE].end = addr + size;
dev->resource[idx].parent = &iomem_resource;
if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM) if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY; cmd |= PCI_COMMAND_MEMORY;
} }
......
...@@ -421,9 +421,10 @@ bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) ...@@ -421,9 +421,10 @@ bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda;
for (i = 0; i < BTES_PER_NODE; i++) { for (i = 0; i < BTES_PER_NODE; i++) {
(u64) mynodepda->bte_if[i].bte_base_addr = /* Which link status register should we use? */
REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1);
(i == 0 ? IIO_IBLS0 : IIO_IBLS1)); mynodepda->bte_if[i].bte_base_addr = (u64 *)
REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status);
/* /*
* Initialize the notification and spinlock * Initialize the notification and spinlock
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -118,11 +118,33 @@ register_sn_force_interrupt(void) { ...@@ -118,11 +118,33 @@ register_sn_force_interrupt(void) {
} }
} }
static int coherence_id_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data) {
return sprintf(page, "%d\n", cpuid_to_coherence_id(smp_processor_id()));
}
void
register_sn_coherence_id(void) {
struct proc_dir_entry *entry;
if (!sgi_proc_dir) {
sgi_proc_dir = proc_mkdir("sgi_sn", 0);
}
entry = create_proc_entry("coherence_id", 0444, sgi_proc_dir);
if (entry) {
entry->nlink = 1;
entry->data = 0;
entry->read_proc = coherence_id_read_proc;
entry->write_proc = NULL;
}
}
void void
register_sn_procfs(void) { register_sn_procfs(void) {
register_sn_partition_id(); register_sn_partition_id();
register_sn_serial_numbers(); register_sn_serial_numbers();
register_sn_force_interrupt(); register_sn_force_interrupt();
register_sn_coherence_id();
} }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
...@@ -107,6 +107,8 @@ struct ub_dev; ...@@ -107,6 +107,8 @@ struct ub_dev;
* A second ought to be enough for a 32K transfer (UB_MAX_SECTORS) * A second ought to be enough for a 32K transfer (UB_MAX_SECTORS)
* even if a webcam hogs the bus (famous last words). * even if a webcam hogs the bus (famous last words).
* Some CDs need a second to spin up though. * Some CDs need a second to spin up though.
* ZIP drive rejects commands when it's not spinning,
* so it does not need long timeouts either.
*/ */
#define UB_URB_TIMEOUT (HZ*2) #define UB_URB_TIMEOUT (HZ*2)
#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ #define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */
...@@ -287,6 +289,7 @@ struct ub_dev { ...@@ -287,6 +289,7 @@ struct ub_dev {
struct ub_completion work_done; struct ub_completion work_done;
struct urb work_urb; struct urb work_urb;
struct timer_list work_timer;
int last_pipe; /* What might need clearing */ int last_pipe; /* What might need clearing */
struct bulk_cb_wrap work_bcb; struct bulk_cb_wrap work_bcb;
struct bulk_cs_wrap work_bcs; struct bulk_cs_wrap work_bcs;
...@@ -776,16 +779,20 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -776,16 +779,20 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->last_pipe = sc->send_bulk_pipe; sc->last_pipe = sc->send_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
sc->work_urb.timeout = UB_URB_TIMEOUT; sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
/* Fill what we shouldn't be filling, because usb-storage did so. */ /* Fill what we shouldn't be filling, because usb-storage did so. */
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
add_timer(&sc->work_timer);
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */ /* XXX Clear stalls */
printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
del_timer(&sc->work_timer);
ub_complete(&sc->work_done); ub_complete(&sc->work_done);
return rc; return rc;
} }
...@@ -795,6 +802,19 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -795,6 +802,19 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return 0; return 0;
} }
/*
* Timeout handler.
*/
static void ub_urb_timeout(unsigned long arg)
{
struct ub_dev *sc = (struct ub_dev *) arg;
unsigned long flags;
spin_lock_irqsave(&sc->lock, flags);
usb_unlink_urb(&sc->work_urb);
spin_unlock_irqrestore(&sc->lock, flags);
}
/* /*
* Completion routine for the work URB. * Completion routine for the work URB.
* *
...@@ -943,14 +963,18 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -943,14 +963,18 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->last_pipe = pipe; sc->last_pipe = pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
cmd->data, cmd->len, ub_urb_complete, sc); cmd->data, cmd->len, ub_urb_complete, sc);
sc->work_urb.timeout = UB_URB_TIMEOUT; sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
add_timer(&sc->work_timer);
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */ /* XXX Clear stalls */
printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
del_timer(&sc->work_timer);
ub_complete(&sc->work_done); ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc); ub_state_done(sc, cmd, rc);
return; return;
...@@ -1034,16 +1058,20 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -1034,16 +1058,20 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
usb_fill_bulk_urb(&sc->work_urb, sc->dev, usb_fill_bulk_urb(&sc->work_urb, sc->dev,
sc->recv_bulk_pipe, &sc->work_bcs, sc->recv_bulk_pipe, &sc->work_bcs,
US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
sc->work_urb.timeout = UB_URB_TIMEOUT; sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
add_timer(&sc->work_timer);
rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC);
if (rc != 0) { if (rc != 0) {
/* XXX Clear stalls */ /* XXX Clear stalls */
printk("%s: CSW #%d submit failed (%d)\n", printk("%s: CSW #%d submit failed (%d)\n",
sc->name, cmd->tag, rc); /* P3 */ sc->name, cmd->tag, rc); /* P3 */
del_timer(&sc->work_timer);
ub_complete(&sc->work_done); ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc); ub_state_done(sc, cmd, rc);
return; return;
...@@ -1153,14 +1181,18 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -1153,14 +1181,18 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
sc->last_pipe = sc->recv_bulk_pipe; sc->last_pipe = sc->recv_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
&sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
sc->work_urb.timeout = UB_URB_TIMEOUT; sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
add_timer(&sc->work_timer);
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */ /* XXX Clear stalls */
printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
del_timer(&sc->work_timer);
ub_complete(&sc->work_done); ub_complete(&sc->work_done);
ub_state_done(sc, cmd, rc); ub_state_done(sc, cmd, rc);
return; return;
...@@ -1233,14 +1265,17 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, ...@@ -1233,14 +1265,17 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
UB_INIT_COMPLETION(sc->work_done); UB_INIT_COMPLETION(sc->work_done);
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
ub_urb_complete, sc); sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.timeout = UB_CTRL_TIMEOUT;
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
add_timer(&sc->work_timer);
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
del_timer(&sc->work_timer);
ub_complete(&sc->work_done); ub_complete(&sc->work_done);
return rc; return rc;
} }
...@@ -1653,6 +1688,12 @@ static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) ...@@ -1653,6 +1688,12 @@ static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt)
complete(cop); complete(cop);
} }
static void ub_probe_timeout(unsigned long arg)
{
struct completion *cop = (struct completion *) arg;
complete(cop);
}
/* /*
* Clear initial stalls. * Clear initial stalls.
*/ */
...@@ -1661,6 +1702,7 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) ...@@ -1661,6 +1702,7 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
int endp; int endp;
struct usb_ctrlrequest *cr; struct usb_ctrlrequest *cr;
struct completion compl; struct completion compl;
struct timer_list timer;
int rc; int rc;
init_completion(&compl); init_completion(&compl);
...@@ -1677,21 +1719,35 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) ...@@ -1677,21 +1719,35 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
cr->wLength = cpu_to_le16(0); cr->wLength = cpu_to_le16(0);
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
ub_probe_urb_complete, &compl); sc->work_urb.transfer_flags = 0;
sc->work_urb.timeout = UB_CTRL_TIMEOUT;
sc->work_urb.actual_length = 0; sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0; sc->work_urb.error_count = 0;
sc->work_urb.status = 0; sc->work_urb.status = 0;
init_timer(&timer);
timer.function = ub_probe_timeout;
timer.data = (unsigned long) &compl;
timer.expires = jiffies + UB_CTRL_TIMEOUT;
add_timer(&timer);
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: Unable to submit a probe clear (%d)\n", sc->name, rc); "%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
del_timer_sync(&timer);
return rc; return rc;
} }
wait_for_completion(&compl); wait_for_completion(&compl);
del_timer_sync(&timer);
/*
* Most of the time, URB was done and dev set to NULL, and so
* the unlink bounces out with ENODEV. We do not call usb_kill_urb
* because we still think about a backport to 2.4.
*/
usb_unlink_urb(&sc->work_urb);
/* reset the endpoint toggle */ /* reset the endpoint toggle */
usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
...@@ -1767,6 +1823,10 @@ static int ub_probe(struct usb_interface *intf, ...@@ -1767,6 +1823,10 @@ static int ub_probe(struct usb_interface *intf,
tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
atomic_set(&sc->poison, 0); atomic_set(&sc->poison, 0);
init_timer(&sc->work_timer);
sc->work_timer.data = (unsigned long) sc;
sc->work_timer.function = ub_urb_timeout;
ub_init_completion(&sc->work_done); ub_init_completion(&sc->work_done);
sc->work_done.done = 1; /* A little yuk, but oh well... */ sc->work_done.done = 1; /* A little yuk, but oh well... */
......
...@@ -299,4 +299,16 @@ config SENSORS_RTC8564 ...@@ -299,4 +299,16 @@ config SENSORS_RTC8564
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-rtc8564. will be called i2c-rtc8564.
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
help
If you say yes here you get support for the Philips ISP1301
USB-On-The-Go transceiver working with the OMAP OTG controller.
The ISP1301 is used in products including H2 and H3 development
boards for Texas Instruments OMAP processors.
This driver can also be built as a module. If so, the module
will be called isp1301_omap.
endmenu endmenu
...@@ -29,7 +29,9 @@ obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o ...@@ -29,7 +29,9 @@ obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
endif endif
This diff is collapsed.
...@@ -268,7 +268,6 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) ...@@ -268,7 +268,6 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
speed_bulk_callback, self); speed_bulk_callback, self);
urb->transfer_buffer_length = USB_IRDA_HEADER; urb->transfer_buffer_length = USB_IRDA_HEADER;
urb->transfer_flags = URB_ASYNC_UNLINK; urb->transfer_flags = URB_ASYNC_UNLINK;
urb->timeout = msecs_to_jiffies(100);
/* Irq disabled -> GFP_ATOMIC */ /* Irq disabled -> GFP_ATOMIC */
if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
...@@ -411,8 +410,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -411,8 +410,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
* after each of our packets that is exact multiple of the frame size. * after each of our packets that is exact multiple of the frame size.
* This is how the dongle will detect the end of packet - Jean II */ * This is how the dongle will detect the end of packet - Jean II */
urb->transfer_flags |= URB_ZERO_PACKET; urb->transfer_flags |= URB_ZERO_PACKET;
/* Timeout need to be shorter than NET watchdog timer */
urb->timeout = msecs_to_jiffies(200);
/* Generate min turn time. FIXME: can we do better than this? */ /* Generate min turn time. FIXME: can we do better than this? */
/* Trying to a turnaround time at this level is trying to measure /* Trying to a turnaround time at this level is trying to measure
......
...@@ -367,7 +367,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c ...@@ -367,7 +367,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
acm->writeurb->dev = acm->dev; acm->writeurb->dev = acm->dev;
acm->ready_for_write = 0; acm->ready_for_write = 0;
stat = usb_submit_urb(acm->writeurb, GFP_NOIO); stat = usb_submit_urb(acm->writeurb, from_user ? GFP_KERNEL : GFP_ATOMIC);
if (stat < 0) { if (stat < 0) {
dbg("usb_submit_urb(write bulk) failed"); dbg("usb_submit_urb(write bulk) failed");
acm->ready_for_write = 1; acm->ready_for_write = 1;
......
...@@ -71,3 +71,29 @@ config USB_SUSPEND ...@@ -71,3 +71,29 @@ config USB_SUSPEND
may not yet work as expected. may not yet work as expected.
If you are unsure about this, say N here. If you are unsure about this, say N here.
config USB_OTG
bool
depends on USB && EXPERIMENTAL
select USB_SUSPEND
default n
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
depends on USB_OTG
default y
help
If you say Y here, the "otg_whitelist.h" file will be used as a
product whitelist, so USB peripherals not listed there will be
rejected during enumeration. This behavior is required by the
USB OTG specification for all devices not on your product's
"Targeted Peripherals List".
Otherwise, peripherals not listed there will only generate a
warning and enumeration will continue. That's more like what
normal Linux-USB hosts do (other than the warning), and is
convenient for many stages of product development.
...@@ -790,6 +790,8 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev ...@@ -790,6 +790,8 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64; usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) { if (retval != sizeof usb_dev->descriptor) {
usb_dev->bus->root_hub = NULL;
up (&usb_bus_list_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n", dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
usb_dev->dev.bus_id, retval); usb_dev->dev.bus_id, retval);
return (retval < 0) ? retval : -EMSGSIZE; return (retval < 0) ? retval : -EMSGSIZE;
...@@ -1404,6 +1406,45 @@ static int hcd_hub_resume (struct usb_bus *bus) ...@@ -1404,6 +1406,45 @@ static int hcd_hub_resume (struct usb_bus *bus)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_OTG
/**
* usb_bus_start_enum - start immediate enumeration (for OTG)
* @bus: the bus (must use hcd framework)
* @port: 1-based number of port; usually bus->otg_port
* Context: in_interrupt()
*
* Starts enumeration, with an immediate reset followed later by
* khubd identifying and possibly configuring the device.
* This is needed by OTG controller drivers, where it helps meet
* HNP protocol timing requirements for starting a port reset.
*/
int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
{
struct usb_hcd *hcd;
int status = -EOPNOTSUPP;
/* NOTE: since HNP can't start by grabbing the bus's address0_sem,
* boards with root hubs hooked up to internal devices (instead of
* just the OTG port) may need more attention to resetting...
*/
hcd = container_of (bus, struct usb_hcd, self);
if (port_num && hcd->driver->start_port_reset)
status = hcd->driver->start_port_reset(hcd, port_num);
/* run khubd shortly after (first) root port reset finishes;
* it may issue others, until at least 50 msecs have passed.
*/
if (status == 0)
mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));
return status;
}
EXPORT_SYMBOL (usb_bus_start_enum);
#endif
/*-------------------------------------------------------------------------*/
/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup. /* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup.
* we're guaranteed that the device is fully quiesced. also, that each * we're guaranteed that the device is fully quiesced. also, that each
* endpoint has been hcd_endpoint_disabled. * endpoint has been hcd_endpoint_disabled.
......
...@@ -212,6 +212,7 @@ struct hc_driver { ...@@ -212,6 +212,7 @@ struct hc_driver {
char *buf, u16 wLength); char *buf, u16 wLength);
int (*hub_suspend)(struct usb_hcd *); int (*hub_suspend)(struct usb_hcd *);
int (*hub_resume)(struct usb_hcd *); int (*hub_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
}; };
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
......
...@@ -1095,6 +1095,10 @@ static inline void show_string(struct usb_device *udev, char *id, int index) ...@@ -1095,6 +1095,10 @@ static inline void show_string(struct usb_device *udev, char *id, int index)
{} {}
#endif #endif
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
#endif
/** /**
* usb_new_device - perform initial device setup (usbcore-internal) * usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state) * @udev: newly addressed device (in ADDRESS state)
...@@ -1144,6 +1148,79 @@ int usb_new_device(struct usb_device *udev) ...@@ -1144,6 +1148,79 @@ int usb_new_device(struct usb_device *udev)
show_string(udev, "SerialNumber", show_string(udev, "SerialNumber",
udev->descriptor.iSerialNumber); udev->descriptor.iSerialNumber);
#ifdef CONFIG_USB_OTG
/*
* OTG-aware devices on OTG-capable root hubs may be able to use SRP,
* to wake us after we've powered off VBUS; and HNP, switching roles
* "host" to "peripheral". The OTG descriptor helps figure this out.
*/
if (!udev->bus->is_b_host
&& udev->config
&& udev->parent == udev->bus->root_hub) {
struct usb_otg_descriptor *desc = 0;
struct usb_bus *bus = udev->bus;
/* descriptor may appear anywhere in config */
if (__usb_get_extra_descriptor (udev->rawdescriptors[0],
udev->config[0].desc.wTotalLength,
USB_DT_OTG, (void **) &desc) == 0) {
if (desc->bmAttributes & USB_OTG_HNP) {
unsigned port;
struct usb_device *root = udev->parent;
for (port = 0; port < root->maxchild; port++) {
if (root->children[port] == udev)
break;
}
port++;
dev_info(&udev->dev,
"Dual-Role OTG device on %sHNP port\n",
(port == bus->otg_port)
? "" : "non-");
/* enable HNP before suspend, it's simpler */
if (port == bus->otg_port)
bus->b_hnp_enable = 1;
err = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, 0,
bus->b_hnp_enable
? USB_DEVICE_B_HNP_ENABLE
: USB_DEVICE_A_ALT_HNP_SUPPORT,
0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (err < 0) {
/* OTG MESSAGE: report errors here,
* customize to match your product.
*/
dev_info(&udev->dev,
"can't set HNP mode; %d\n",
err);
bus->b_hnp_enable = 0;
}
}
}
}
if (!is_targeted(udev)) {
/* Maybe it can talk to us, though we can't talk to it.
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
static int __usb_suspend_device (struct usb_device *,
int port, u32 state);
err = __usb_suspend_device(udev,
udev->bus->otg_port - 1,
PM_SUSPEND_MEM);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
err = -ENODEV;
goto fail;
}
#endif
/* put device-specific files into sysfs */ /* put device-specific files into sysfs */
err = device_add (&udev->dev); err = device_add (&udev->dev);
if (err) { if (err) {
...@@ -1934,6 +2011,10 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) ...@@ -1934,6 +2011,10 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
hdev->bus->b_hnp_enable = 0; hdev->bus->b_hnp_enable = 0;
} }
retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
if (retval < 0 && retval != -EPIPE)
dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval);
/* Some low speed devices have problems with the quick delay, so */ /* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */ /* be a bit pessimistic with those devices. RHbug #23670 */
if (oldspeed == USB_SPEED_LOW) if (oldspeed == USB_SPEED_LOW)
...@@ -2160,6 +2241,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port, ...@@ -2160,6 +2241,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port,
usb_disconnect(&hdev->children[port]); usb_disconnect(&hdev->children[port]);
clear_bit(port, hub->change_bits); clear_bit(port, hub->change_bits);
#ifdef CONFIG_USB_OTG
/* during HNP, don't repeat the debounce */
if (hdev->bus->is_b_host)
portchange &= ~USB_PORT_STAT_C_CONNECTION;
#endif
if (portchange & USB_PORT_STAT_C_CONNECTION) { if (portchange & USB_PORT_STAT_C_CONNECTION) {
status = hub_port_debounce(hdev, port); status = hub_port_debounce(hdev, port);
if (status < 0) { if (status < 0) {
......
...@@ -190,8 +190,8 @@ struct usb_hub { ...@@ -190,8 +190,8 @@ struct usb_hub {
struct usb_device *hdev; struct usb_device *hdev;
struct urb *urb; /* for interrupt polling pipe */ struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... 1 bit each for hub and children, rounded up */ /* buffer for urb ... with extra space in case of babble */
char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; char (*buffer)[8];
dma_addr_t buffer_dma; /* DMA address for buffer */ dma_addr_t buffer_dma; /* DMA address for buffer */
union { union {
struct usb_hub_status hub; struct usb_hub_status hub;
......
...@@ -248,7 +248,7 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) ...@@ -248,7 +248,7 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
* unlink pending urbs so they won't rx/tx bad data. * unlink pending urbs so they won't rx/tx bad data.
*/ */
for (i = 0, found = 0; i < io->entries; i++) { for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs [i]) if (!io->urbs [i] || !io->urbs [i]->dev)
continue; continue;
if (found) { if (found) {
status = usb_unlink_urb (io->urbs [i]); status = usb_unlink_urb (io->urbs [i]);
...@@ -337,7 +337,7 @@ int usb_sg_init ( ...@@ -337,7 +337,7 @@ int usb_sg_init (
if (io->entries <= 0) if (io->entries <= 0)
return io->entries; return io->entries;
io->count = 0; io->count = io->entries;
io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
if (!io->urbs) if (!io->urbs)
goto nomem; goto nomem;
...@@ -347,7 +347,7 @@ int usb_sg_init ( ...@@ -347,7 +347,7 @@ int usb_sg_init (
if (usb_pipein (pipe)) if (usb_pipein (pipe))
urb_flags |= URB_SHORT_NOT_OK; urb_flags |= URB_SHORT_NOT_OK;
for (i = 0; i < io->entries; i++, io->count = i) { for (i = 0; i < io->entries; i++) {
unsigned len; unsigned len;
io->urbs [i] = usb_alloc_urb (0, mem_flags); io->urbs [i] = usb_alloc_urb (0, mem_flags);
...@@ -477,24 +477,19 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -477,24 +477,19 @@ void usb_sg_wait (struct usb_sg_request *io)
/* fail any uncompleted urbs */ /* fail any uncompleted urbs */
default: default:
spin_lock_irq (&io->lock); io->urbs [i]->dev = NULL;
io->count -= entries - i;
if (io->status == -EINPROGRESS)
io->status = retval;
if (io->count == 0)
complete (&io->complete);
spin_unlock_irq (&io->lock);
io->urbs[i]->dev = NULL;
io->urbs [i]->status = retval; io->urbs [i]->status = retval;
dev_dbg (&io->dev->dev, "%s, submit --> %d\n", dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
__FUNCTION__, retval); __FUNCTION__, retval);
usb_sg_cancel (io); usb_sg_cancel (io);
} }
spin_lock_irq (&io->lock); spin_lock_irq (&io->lock);
if (retval && io->status == -ECONNRESET) if (retval && (io->status == 0 || io->status == -ECONNRESET))
io->status = retval; io->status = retval;
} }
io->count -= entries - i;
if (io->count == 0)
complete (&io->complete);
spin_unlock_irq (&io->lock); spin_unlock_irq (&io->lock);
/* OK, yes, this could be packaged as non-blocking. /* OK, yes, this could be packaged as non-blocking.
......
/*
* drivers/usb/core/otg_whitelist.h
*
* Copyright (C) 2004 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/*
* This OTG Whitelist is the OTG "Targeted Peripheral List". It should
* mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
*
* YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
*/
static struct usb_device_id whitelist_table [] = {
/* hubs are optional in OTG, but very handy ... */
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
/* FIXME actually, printers are NOT supposed to use device classes;
* they're supposed to use interface classes...
*/
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
{ USB_DEVICE_INFO(7, 1, 3) },
#endif
#ifdef CONFIG_USB_CDCETHER
/* Linux-USB CDC Ethernet gadget */
{ USB_DEVICE(0x0525, 0xa4a1), },
/* Linux-USB CDC Ethernet + RNDIS gadget */
{ USB_DEVICE(0x0525, 0xa4a2), },
#endif
#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
/* gadget zero, for testing */
{ USB_DEVICE(0x0525, 0xa4a0), },
#endif
{ } /* Terminating entry */
};
static int is_targeted(struct usb_device *dev)
{
struct usb_device_id *id = whitelist_table;
/* possible in developer configs only! */
if (!dev->bus->otg_port)
return 1;
/* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
if (dev->descriptor.idVendor == 0x1a0a
&& dev->descriptor.idProduct == 0xbadd)
return 0;
/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
for (id = whitelist_table; id->match_flags; id++) {
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != dev->descriptor.idVendor)
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != dev->descriptor.idProduct)
continue;
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > dev->descriptor.bcdDevice))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < dev->descriptor.bcdDevice))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
return 1;
}
/* add other match criteria here ... */
/* OTG MESSAGE: report errors here, customize to match your product */
dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
#ifdef CONFIG_USB_OTG_WHITELIST
return 0;
#else
return 1;
#endif
}
...@@ -135,6 +135,18 @@ config USB_SA1100 ...@@ -135,6 +135,18 @@ config USB_SA1100
depends on USB_GADGET_SA1100 depends on USB_GADGET_SA1100
default USB_GADGET default USB_GADGET
config USB_GADGET_LH7A40X
boolean "LH7A40X"
depends on ARCH_LH7A40X
help
This driver provides USB Device Controller driver for LH7A40x
config USB_LH7A40X
tristate
depends on USB_GADGET_LH7A40X
default USB_GADGET
config USB_GADGET_DUMMY_HCD config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)" boolean "Dummy HCD (DEVELOPMENT)"
depends on USB && EXPERIMENTAL depends on USB && EXPERIMENTAL
...@@ -163,6 +175,41 @@ config USB_DUMMY_HCD ...@@ -163,6 +175,41 @@ config USB_DUMMY_HCD
depends on USB_GADGET_DUMMY_HCD depends on USB_GADGET_DUMMY_HCD
default USB_GADGET default USB_GADGET
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
select ISP1301_OMAP if MACH_OMAP_H2
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
endpoints (plus endpoint zero). This driver supports the
controller in the OMAP 1611, and should work with controllers
in other OMAP processors too, given minor tweaks.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "omap_udc" and force all
gadget drivers to also be dynamically linked.
config USB_OMAP
tristate
depends on USB_GADGET_OMAP
default USB_GADGET
config USB_OTG
boolean "OTG Support"
depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
help
The most notable feature of USB OTG is support for a
"Dual-Role" device, which can act as either a device
or a host. The initial role choice can be changed
later, when two dual-role devices talk to each other.
Select this only if your OMAP board has a Mini-AB connector.
config USB_OMAP_PROC
boolean "/proc/driver/udc file"
depends on USB_GADGET_OMAP
endchoice endchoice
config USB_GADGET_DUALSPEED config USB_GADGET_DUALSPEED
......
...@@ -5,6 +5,8 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o ...@@ -5,6 +5,8 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
# #
# USB gadget drivers # USB gadget drivers
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
/* /*
* Ethernet gadget driver -- with CDC and non-CDC options * Ethernet gadget driver -- with CDC and non-CDC options
* Builds on hardware support for a full duplex link.
* *
* CDC Ethernet is the standard USB solution for sending Ethernet frames * CDC Ethernet is the standard USB solution for sending Ethernet frames
* using USB. Real hardware tends to use the same framing protocol but look * using USB. Real hardware tends to use the same framing protocol but look
...@@ -242,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); ...@@ -242,6 +243,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET #define DEV_CONFIG_SUBSET
#endif #endif
#ifdef CONFIG_USB_GADGET_LH7A40X
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_SA1100 #ifdef CONFIG_USB_GADGET_SA1100
/* use non-CDC for backwards compatibility */ /* use non-CDC for backwards compatibility */
#define DEV_CONFIG_SUBSET #define DEV_CONFIG_SUBSET
...@@ -855,7 +860,7 @@ static char product_desc [40] = DRIVER_DESC; ...@@ -855,7 +860,7 @@ static char product_desc [40] = DRIVER_DESC;
static char ethaddr [2 * ETH_ALEN + 1]; static char ethaddr [2 * ETH_ALEN + 1];
#endif #endif
/* static strings, in iso 8859/1 */ /* static strings, in UTF-8 */
static struct usb_string strings [] = { static struct usb_string strings [] = {
{ STRING_MANUFACTURER, manufacturer, }, { STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, product_desc, }, { STRING_PRODUCT, product_desc, },
...@@ -897,9 +902,9 @@ config_buf (enum usb_device_speed speed, ...@@ -897,9 +902,9 @@ config_buf (enum usb_device_speed speed,
if (type == USB_DT_OTHER_SPEED_CONFIG) if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs; hs = !hs;
#define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
#else #else
#define which_fn(t) (& fs_ ## t ## _function) #define which_fn(t) (fs_ ## t ## _function)
#endif #endif
if (index >= device_desc.bNumConfigurations) if (index >= device_desc.bNumConfigurations)
...@@ -911,14 +916,12 @@ config_buf (enum usb_device_speed speed, ...@@ -911,14 +916,12 @@ config_buf (enum usb_device_speed speed,
*/ */
if (device_desc.bNumConfigurations == 2 && index == 0) { if (device_desc.bNumConfigurations == 2 && index == 0) {
config = &rndis_config; config = &rndis_config;
function = (const struct usb_descriptor_header **) function = which_fn (rndis);
which_fn (rndis);
} else } else
#endif #endif
{ {
config = &eth_config; config = &eth_config;
function = (const struct usb_descriptor_header **) function = which_fn (eth);
which_fn (eth);
} }
/* for now, don't advertise srp-only devices */ /* for now, don't advertise srp-only devices */
...@@ -2329,6 +2332,8 @@ eth_bind (struct usb_gadget *gadget) ...@@ -2329,6 +2332,8 @@ eth_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
} else if (gadget_is_omap (gadget)) { } else if (gadget_is_omap (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
} else { } else {
/* can't assume CDC works. don't want to default to /* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware, * anything less functional on CDC-capable hardware,
......
...@@ -3713,6 +3713,8 @@ static int __init check_parameters(struct fsg_dev *fsg) ...@@ -3713,6 +3713,8 @@ static int __init check_parameters(struct fsg_dev *fsg)
mod_data.release = __constant_cpu_to_le16(0x0307); mod_data.release = __constant_cpu_to_le16(0x0307);
else if (gadget_is_omap(fsg->gadget)) else if (gadget_is_omap(fsg->gadget))
mod_data.release = __constant_cpu_to_le16(0x0308); mod_data.release = __constant_cpu_to_le16(0x0308);
else if (gadget_is_lh7a40x(gadget))
mod_data.release = __constant_cpu_to_le16 (0x0309);
else { else {
WARN(fsg, "controller '%s' not recognized\n", WARN(fsg, "controller '%s' not recognized\n",
fsg->gadget->name); fsg->gadget->name);
......
...@@ -44,6 +44,12 @@ ...@@ -44,6 +44,12 @@
#define gadget_is_sa1100(g) 0 #define gadget_is_sa1100(g) 0
#endif #endif
#ifdef CONFIG_USB_GADGET_LH7A40X
#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name)
#else
#define gadget_is_lh7a40x(g) 0
#endif
#ifdef CONFIG_USB_GADGET_MQ11XX #ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) #define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else #else
......
/* /*
* inode.c -- user mode filesystem api for usb gadget controllers * inode.c -- user mode filesystem api for usb gadget controllers
* *
* Copyright (C) 2003 David Brownell * Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies * Copyright (C) 2003 Agilent Technologies
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
*/ */
#define DRIVER_DESC "USB Gadget filesystem" #define DRIVER_DESC "USB Gadget filesystem"
#define DRIVER_VERSION "18 Nov 2003" #define DRIVER_VERSION "24 Aug 2004"
static const char driver_desc [] = DRIVER_DESC; static const char driver_desc [] = DRIVER_DESC;
static const char shortname [] = "gadgetfs"; static const char shortname [] = "gadgetfs";
...@@ -229,37 +229,12 @@ static void put_ep (struct ep_data *data) ...@@ -229,37 +229,12 @@ static void put_ep (struct ep_data *data)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* most "how to use the hardware" policy choices are in userspace: /* most "how to use the hardware" policy choices are in userspace:
* mapping endpoint roles the driver needs to the capabilities that * mapping endpoint roles (which the driver needs) to the capabilities
* the usb controller exposes. * which the usb controller has. most of those capabilities are exposed
* implicitly, starting with the driver name and then endpoint names.
*/ */
#ifdef CONFIG_USB_GADGET_DUMMY_HCD static const char *CHIP;
/* act (mostly) like a net2280 */
#define CONFIG_USB_GADGET_NET2280
#endif
#ifdef CONFIG_USB_GADGET_NET2280
#define CHIP "net2280"
#define HIGHSPEED
#endif
#ifdef CONFIG_USB_GADGET_PXA2XX
#define CHIP "pxa2xx_udc"
/* earlier hardware doesn't have UDCCFR, races set_{config,interface} */
#warning works best with pxa255 or newer
#endif
#ifdef CONFIG_USB_GADGET_GOKU
#define CHIP "goku_udc"
#endif
#ifdef CONFIG_USB_GADGET_OMAP
#define CHIP "omap_udc"
#endif
#ifdef CONFIG_USB_GADGET_SA1100
#define CHIP "sa1100"
#endif
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -558,7 +533,7 @@ struct kiocb_priv { ...@@ -558,7 +533,7 @@ struct kiocb_priv {
static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
{ {
struct kiocb_priv *priv = (void *) &iocb->private; struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata; struct ep_data *epdata;
int value; int value;
...@@ -579,7 +554,7 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) ...@@ -579,7 +554,7 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
static ssize_t ep_aio_read_retry(struct kiocb *iocb) static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{ {
struct kiocb_priv *priv = (void *) &iocb->private; struct kiocb_priv *priv = iocb->private;
ssize_t status = priv->actual; ssize_t status = priv->actual;
/* we "retry" to get the right mm context for this: */ /* we "retry" to get the right mm context for this: */
...@@ -589,6 +564,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) ...@@ -589,6 +564,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
else else
status = priv->actual; status = priv->actual;
kfree(priv->buf); kfree(priv->buf);
kfree(priv);
aio_put_req(iocb); aio_put_req(iocb);
return status; return status;
} }
...@@ -596,7 +572,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) ...@@ -596,7 +572,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
{ {
struct kiocb *iocb = req->context; struct kiocb *iocb = req->context;
struct kiocb_priv *priv = (void *) &iocb->private; struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata = priv->epdata; struct ep_data *epdata = priv->epdata;
/* lock against disconnect (and ideally, cancel) */ /* lock against disconnect (and ideally, cancel) */
...@@ -607,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -607,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
|| unlikely(0 == req->actual) || unlikely(0 == req->actual)
|| unlikely(kiocbIsCancelled(iocb))) { || unlikely(kiocbIsCancelled(iocb))) {
kfree(req->buf); kfree(req->buf);
kfree(priv);
iocb->private = 0;
/* aio_complete() reports bytes-transferred _and_ faults */ /* aio_complete() reports bytes-transferred _and_ faults */
if (unlikely(kiocbIsCancelled(iocb))) if (unlikely(kiocbIsCancelled(iocb)))
aio_put_req(iocb); aio_put_req(iocb);
...@@ -631,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -631,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
} }
static ssize_t static ssize_t
ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) ep_aio_rwtail(
struct kiocb *iocb,
char *buf,
size_t len,
struct ep_data *epdata,
char __user *ubuf
)
{ {
struct kiocb_priv *priv = (void *) &iocb->private; struct kiocb_priv *priv = (void *) &iocb->private;
struct usb_request *req; struct usb_request *req;
ssize_t value; ssize_t value;
value = get_ready_ep(iocb->ki_filp->f_flags, epdata); priv = kmalloc(sizeof *priv, GFP_KERNEL);
if (unlikely(value < 0)) { if (!priv) {
value = -ENOMEM;
fail:
kfree(buf); kfree(buf);
return value; return value;
} }
iocb->private = priv;
priv->ubuf = ubuf;
value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
if (unlikely(value < 0)) {
kfree(priv);
goto fail;
}
iocb->ki_cancel = ep_aio_cancel; iocb->ki_cancel = ep_aio_cancel;
get_ep(epdata); get_ep(epdata);
...@@ -671,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) ...@@ -671,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata)
up(&epdata->lock); up(&epdata->lock);
if (unlikely(value)) if (unlikely(value)) {
kfree(priv);
put_ep(epdata); put_ep(epdata);
else } else
value = -EIOCBQUEUED; value = -EIOCBQUEUED;
return value; return value;
} }
...@@ -681,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) ...@@ -681,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata)
static ssize_t static ssize_t
ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
{ {
struct kiocb_priv *priv = (void *) &iocb->private;
struct ep_data *epdata = iocb->ki_filp->private_data; struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf; char *buf;
...@@ -691,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) ...@@ -691,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
if (unlikely(!buf)) if (unlikely(!buf))
return -ENOMEM; return -ENOMEM;
iocb->ki_retry = ep_aio_read_retry; iocb->ki_retry = ep_aio_read_retry;
priv->ubuf = ubuf; return ep_aio_rwtail(iocb, buf, len, epdata, ubuf);
return ep_aio_rwtail(iocb, buf, len, epdata);
} }
static ssize_t static ssize_t
...@@ -710,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) ...@@ -710,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
kfree(buf); kfree(buf);
return -EFAULT; return -EFAULT;
} }
return ep_aio_rwtail(iocb, buf, len, epdata); return ep_aio_rwtail(iocb, buf, len, epdata, 0);
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -718,6 +711,8 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) ...@@ -718,6 +711,8 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
/* used after endpoint configuration */ /* used after endpoint configuration */
static struct file_operations ep_io_operations = { static struct file_operations ep_io_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep_read, .read = ep_read,
.write = ep_write, .write = ep_write,
.ioctl = ep_ioctl, .ioctl = ep_ioctl,
...@@ -874,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd) ...@@ -874,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd)
/* used before endpoint configuration */ /* used before endpoint configuration */
static struct file_operations ep_config_operations = { static struct file_operations ep_config_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.open = ep_open, .open = ep_open,
.write = ep_config, .write = ep_config,
.release = ep_release, .release = ep_release,
...@@ -980,6 +977,18 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) ...@@ -980,6 +977,18 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
retval = usb_ep_queue (ep, req, GFP_ATOMIC); retval = usb_ep_queue (ep, req, GFP_ATOMIC);
dev->state = STATE_CONNECTED; dev->state = STATE_CONNECTED;
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
unsigned power;
#ifdef HIGHSPEED
if (dev->gadget->speed == USB_SPEED_HIGH)
power = dev->hs_config->bMaxPower;
else
#endif
power = dev->config->bMaxPower;
usb_gadget_vbus_draw(dev->gadget, 2 * power);
}
} else { /* collect OUT data */ } else { /* collect OUT data */
if ((fd->f_flags & O_NONBLOCK) != 0 if ((fd->f_flags & O_NONBLOCK) != 0
&& !dev->setup_out_ready) { && !dev->setup_out_ready) {
...@@ -1230,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd, ...@@ -1230,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd,
/* used after device configuration */ /* used after device configuration */
static struct file_operations ep0_io_operations = { static struct file_operations ep0_io_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep0_read, .read = ep0_read,
.write = ep0_write, .write = ep0_write,
.fasync = ep0_fasync, .fasync = ep0_fasync,
...@@ -1406,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -1406,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (0 == (u8) ctrl->wValue) { if (0 == (u8) ctrl->wValue) {
value = 0; value = 0;
dev->current_config = 0; dev->current_config = 0;
usb_gadget_vbus_draw(gadget, 8 /* mA */ );
// user mode expected to disable endpoints // user mode expected to disable endpoints
} else { } else {
u8 config; u8 config, power;
#ifdef HIGHSPEED #ifdef HIGHSPEED
if (gadget->speed == USB_SPEED_HIGH) if (gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue; config = dev->hs_config->bConfigurationValue;
else power = dev->hs_config->bMaxPower;
} else
#endif #endif
{
config = dev->config->bConfigurationValue; config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
if (config == (u8) ctrl->wValue) { if (config == (u8) ctrl->wValue) {
value = 0; value = 0;
dev->current_config = config; dev->current_config = config;
usb_gadget_vbus_draw(gadget, 2 * power);
} }
} }
...@@ -1636,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget) ...@@ -1636,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget)
if (!dev) if (!dev)
return -ESRCH; return -ESRCH;
if (0 != strcmp (CHIP, gadget->name)) { if (0 != strcmp (CHIP, gadget->name)) {
printk (KERN_ERR "%s expected " CHIP " controller not %s\n", printk (KERN_ERR "%s expected %s controller not %s\n",
shortname, gadget->name); shortname, CHIP, gadget->name);
return -ENODEV; return -ENODEV;
} }
...@@ -1727,6 +1744,26 @@ static struct usb_gadget_driver gadgetfs_driver = { ...@@ -1727,6 +1744,26 @@ static struct usb_gadget_driver gadgetfs_driver = {
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static void gadgetfs_nop(struct usb_gadget *arg) { }
static int gadgetfs_probe (struct usb_gadget *gadget)
{
CHIP = gadget->name;
return -EISNAM;
}
static struct usb_gadget_driver probe_driver = {
.speed = USB_SPEED_HIGH,
.bind = gadgetfs_probe,
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,
.driver = {
.name = "nop",
},
};
/* DEVICE INITIALIZATION /* DEVICE INITIALIZATION
* *
* fd = open ("/dev/gadget/$CHIP", O_RDWR) * fd = open ("/dev/gadget/$CHIP", O_RDWR)
...@@ -1763,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config) ...@@ -1763,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config)
&& config->bConfigurationValue != 0 && config->bConfigurationValue != 0
&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
/* FIXME if gadget->is_otg, _must_ include an otg descriptor */
/* FIXME check lengths: walk to end */ /* FIXME check lengths: walk to end */
} }
...@@ -1881,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd) ...@@ -1881,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd)
static struct file_operations dev_init_operations = { static struct file_operations dev_init_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.open = dev_open, .open = dev_open,
.write = dev_config, .write = dev_config,
.fasync = ep0_fasync, .fasync = ep0_fasync,
...@@ -1976,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) ...@@ -1976,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
if (the_device) if (the_device)
return -ESRCH; return -ESRCH;
/* fake probe to determine $CHIP */
(void) usb_gadget_register_driver (&probe_driver);
if (!CHIP)
return -ENODEV;
/* superblock */ /* superblock */
sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
......
This diff is collapsed.
This diff is collapsed.
...@@ -307,7 +307,6 @@ static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep) ...@@ -307,7 +307,6 @@ static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep)
| (1 << SET_NAK_OUT_PACKETS) | (1 << SET_NAK_OUT_PACKETS)
| (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
| (1 << CLEAR_INTERRUPT_MODE) | (1 << CLEAR_INTERRUPT_MODE)
| (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
| (1 << CLEAR_ENDPOINT_TOGGLE) | (1 << CLEAR_ENDPOINT_TOGGLE)
| (1 << CLEAR_ENDPOINT_HALT) | (1 << CLEAR_ENDPOINT_HALT)
, &ep->regs->ep_rsp); , &ep->regs->ep_rsp);
...@@ -2511,15 +2510,23 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) ...@@ -2511,15 +2510,23 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
static void handle_stat1_irqs (struct net2280 *dev, u32 stat) static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
{ {
struct net2280_ep *ep; struct net2280_ep *ep;
u32 tmp, num, scratch; u32 tmp, num, mask, scratch;
/* after disconnect there's nothing else to do! */ /* after disconnect there's nothing else to do! */
tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED);
/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
* Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
* both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* only indicates a change in the reset state).
*/
if (stat & tmp) { if (stat & tmp) {
writel (tmp, &dev->regs->irqstat1); writel (tmp, &dev->regs->irqstat1);
if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0 if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
|| (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0 ((readl (&dev->usb->usbstat) & mask) == 0))
) && dev->gadget.speed != USB_SPEED_UNKNOWN) { || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
DEBUG (dev, "disconnect %s\n", DEBUG (dev, "disconnect %s\n",
dev->driver->driver.name); dev->driver->driver.name);
stop_activity (dev, dev->driver); stop_activity (dev, dev->driver);
......
This diff is collapsed.
This diff is collapsed.
...@@ -1299,6 +1299,9 @@ static int gs_bind(struct usb_gadget *gadget) ...@@ -1299,6 +1299,9 @@ static int gs_bind(struct usb_gadget *gadget)
} else if (gadget_is_omap(gadget)) { } else if (gadget_is_omap(gadget)) {
gs_device_desc.bcdDevice = gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0007); __constant_cpu_to_le16(GS_VERSION_NUM|0x0007);
} else if (gadget_is_lh7a40x(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0008);
} else { } else {
printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
gadget->name); gadget->name);
......
...@@ -399,7 +399,7 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { ...@@ -399,7 +399,7 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
static char manufacturer [40]; static char manufacturer [40];
static char serial [40]; static char serial [40];
/* static strings, in iso 8859/1 */ /* static strings, in UTF-8 */
static struct usb_string strings [] = { static struct usb_string strings [] = {
{ STRING_MANUFACTURER, manufacturer, }, { STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, }, { STRING_PRODUCT, longname, },
...@@ -960,7 +960,8 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -960,7 +960,8 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_DT_STRING: case USB_DT_STRING:
/* wIndex == language code. /* wIndex == language code.
* this driver only handles one language, you can * this driver only handles one language, you can
* add others even if they don't use iso8859/1 * add string tables for other languages, using
* any UTF-8 characters
*/ */
value = usb_gadget_get_string (&stringtab, value = usb_gadget_get_string (&stringtab,
ctrl->wValue & 0xff, req->buf); ctrl->wValue & 0xff, req->buf);
...@@ -1185,6 +1186,8 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1185,6 +1186,8 @@ zero_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
} else if (gadget_is_omap (gadget)) { } else if (gadget_is_omap (gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
} else { } else {
/* gadget zero is so simple (for now, no altsettings) that /* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware. * it SHOULD NOT have problems with bulk-capable hardware.
...@@ -1236,6 +1239,12 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1236,6 +1239,12 @@ zero_bind (struct usb_gadget *gadget)
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
if (gadget->is_otg) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
usb_gadget_set_selfpowered (gadget); usb_gadget_set_selfpowered (gadget);
init_timer (&dev->resume); init_timer (&dev->resume);
......
...@@ -52,6 +52,7 @@ config USB_EHCI_ROOT_HUB_TT ...@@ -52,6 +52,7 @@ config USB_EHCI_ROOT_HUB_TT
config USB_OHCI_HCD config USB_OHCI_HCD
tristate "OHCI HCD support" tristate "OHCI HCD support"
depends on USB depends on USB
select ISP1301_OMAP if MACH_OMAP_H2
---help--- ---help---
The Open Host Controller Interface (OHCI) is a standard for accessing The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's USB 1.1 host controller hardware. It does more in hardware than Intel's
......
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */ #include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb_otg.h>
#include "../core/hcd.h" #include "../core/hcd.h"
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */ #include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */
...@@ -693,7 +694,7 @@ static void ohci_stop (struct usb_hcd *hcd) ...@@ -693,7 +694,7 @@ static void ohci_stop (struct usb_hcd *hcd)
/* must not be called from interrupt context */ /* must not be called from interrupt context */
#ifdef CONFIG_PM #if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
static void mark_children_gone (struct usb_device *dev) static void mark_children_gone (struct usb_device *dev)
{ {
......
...@@ -435,6 +435,89 @@ ohci_hub_descriptor ( ...@@ -435,6 +435,89 @@ ohci_hub_descriptor (
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_OTG
static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
u32 status;
if (!port)
return -EINVAL;
port--;
/* start port reset before HNP protocol times out */
status = ohci_readl(&ohci->regs->roothub.portstatus [port]);
if (!(status & RH_PS_CCS))
return -ENODEV;
/* khubd will finish the reset later */
writel(RH_PS_PRS, &ohci->regs->roothub.portstatus [port]);
return 0;
}
static void start_hnp(struct ohci_hcd *ohci);
#else
#define ohci_start_port_reset NULL
#endif
/*-------------------------------------------------------------------------*/
/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling,
* not necessarily continuous ... to guard against resume signaling.
* The short timeout is safe for non-root hubs, and is backward-compatible
* with earlier Linux hosts.
*/
#ifdef CONFIG_USB_SUSPEND
#define PORT_RESET_MSEC 50
#else
#define PORT_RESET_MSEC 10
#endif
/* this timer value might be vendor-specific ... */
#define PORT_RESET_HW_MSEC 10
/* wrap-aware logic stolen from <linux/jiffies.h> */
#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
/* called from some task, normally khubd */
static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
u32 *portstat = &ohci->regs->roothub.portstatus [port];
u32 temp;
u16 now = readl(&ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
/* build a "continuous enough" reset signal, with up to
* 3msec gap between pulses. scheduler HZ==100 must work;
* this might need to be deadline-scheduled.
*/
do {
/* spin until any current reset finishes */
for (;;) {
temp = ohci_readl (portstat);
if (!(temp & RH_PS_PRS))
break;
udelay (500);
}
if (!(temp & RH_PS_CCS))
break;
if (temp & RH_PS_PRSC)
writel (RH_PS_PRSC, portstat);
/* start the next reset, sleep till it's probably done */
writel (RH_PS_PRS, portstat);
msleep(PORT_RESET_HW_MSEC);
now = readl(&ohci->regs->fmnumber);
} while (tick_before(now, reset_done));
/* caller synchronizes using PRSC */
}
static int ohci_hub_control ( static int ohci_hub_control (
struct usb_hcd *hcd, struct usb_hcd *hcd,
u16 typeReq, u16 typeReq,
...@@ -533,6 +616,12 @@ static int ohci_hub_control ( ...@@ -533,6 +616,12 @@ static int ohci_hub_control (
wIndex--; wIndex--;
switch (wValue) { switch (wValue) {
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
#ifdef CONFIG_USB_OTG
if (ohci->hcd.self.otg_port == (wIndex + 1)
&& ohci->hcd.self.b_hnp_enable)
start_hnp(ohci);
else
#endif
writel (RH_PS_PSS, writel (RH_PS_PSS,
&ohci->regs->roothub.portstatus [wIndex]); &ohci->regs->roothub.portstatus [wIndex]);
break; break;
...@@ -541,10 +630,7 @@ static int ohci_hub_control ( ...@@ -541,10 +630,7 @@ static int ohci_hub_control (
&ohci->regs->roothub.portstatus [wIndex]); &ohci->regs->roothub.portstatus [wIndex]);
break; break;
case USB_PORT_FEAT_RESET: case USB_PORT_FEAT_RESET:
temp = ohci_readl (&ohci->regs->roothub.portstatus [wIndex]); root_port_reset (ohci, wIndex);
if (temp & RH_PS_CCS)
writel (RH_PS_PRS,
&ohci->regs->roothub.portstatus [wIndex]);
break; break;
default: default:
goto error; goto error;
......
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