Commit 9bb82966 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-acpi.bkbits.net/linux-acpi

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 6ccc3e25 4a5f1de1
......@@ -4,8 +4,8 @@
gamma-objs := gamma_drv.o gamma_dma.o
tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
i810-objs := i810_drv.o i810_dma.o
i830-objs := i830_drv.o i830_dma.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
......
/* sarea.h -- SAREA definitions -*- linux-c -*-
*
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Michel Dänzer <michel@daenzer.net>
*/
#ifndef _DRM_SAREA_H_
#define _DRM_SAREA_H_
#define SAREA_MAX_DRAWABLES 256
typedef struct _drm_sarea_drawable_t {
unsigned int stamp;
unsigned int flags;
} drm_sarea_drawable_t;
typedef struct _dri_sarea_frame_t {
unsigned int x;
unsigned int y;
unsigned int width;
unsigned int height;
unsigned int fullscreen;
} drm_sarea_frame_t;
typedef struct _drm_sarea_t {
/* first thing is always the drm locking structure */
drm_hw_lock_t lock;
/* NOT_DONE: Use readers/writer lock for drawable_lock */
drm_hw_lock_t drawable_lock;
drm_sarea_drawable_t drawableTable[SAREA_MAX_DRAWABLES];
drm_sarea_frame_t frame;
drm_context_t dummy_context;
} drm_sarea_t;
#endif /* _DRM_SAREA_H_ */
......@@ -71,7 +71,7 @@ struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
* Find the right map
*/
if(!dev->agp->cant_use_aperture) goto vm_nopage_error;
if(!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error;
list_for_each(list, &dev->maplist->head) {
r_list = (drm_map_list_t *)list;
......
......@@ -26,7 +26,7 @@
*
* Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* Jeff Hartmann <jhartmann@valinux.com>
* Keith Whitwell <keith_whitwell@yahoo.com>
* Keith Whitwell <keith@tungstengraphics.com>
*
*/
......@@ -264,44 +264,6 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
return retcode;
}
static unsigned long i810_alloc_page(drm_device_t *dev)
{
unsigned long address;
address = __get_free_page(GFP_KERNEL);
if(address == 0UL)
return 0;
#if LINUX_VERSION_CODE < 0x020409
atomic_inc(&virt_to_page(address)->count);
set_bit(PG_locked, &virt_to_page(address)->flags);
#else
get_page(virt_to_page(address));
#if LINUX_VERSION_CODE < 0x020500
LockPage(virt_to_page(address));
#else
SetPageLocked(virt_to_page(address));
#endif
#endif
return address;
}
static void i810_free_page(drm_device_t *dev, unsigned long page)
{
if (page) {
#if LINUX_VERSION_CODE < 0x020409
atomic_dec(&virt_to_page(page)->count);
clear_bit(PG_locked, &virt_to_page(page)->flags);
wake_up(&virt_to_page(page)->wait);
#else
struct page *p = virt_to_page(page);
put_page(p);
unlock_page(p);
#endif
free_page(page);
}
}
static int i810_dma_cleanup(drm_device_t *dev)
{
drm_device_dma_t *dma = dev->dma;
......@@ -316,7 +278,9 @@ static int i810_dma_cleanup(drm_device_t *dev)
dev_priv->ring.Size);
}
if(dev_priv->hw_status_page != 0UL) {
i810_free_page(dev, dev_priv->hw_status_page);
pci_free_consistent(dev->pdev, PAGE_SIZE,
(void *)dev_priv->hw_status_page,
dev_priv->dma_status_page);
/* Need to rewrite hardware status page */
I810_WRITE(0x02080, 0x1ffff000);
}
......@@ -476,7 +440,9 @@ static int i810_dma_initialize(drm_device_t *dev,
dev_priv->zi1 = init->depth_offset | init->pitch_bits;
/* Program Hardware Status Page */
dev_priv->hw_status_page = i810_alloc_page(dev);
dev_priv->hw_status_page =
(unsigned long) pci_alloc_consistent(dev->pdev, PAGE_SIZE,
&dev_priv->dma_status_page);
if(dev_priv->hw_status_page == 0UL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
......@@ -486,7 +452,7 @@ static int i810_dma_initialize(drm_device_t *dev,
memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
I810_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
/* Now we need to init our freelist */
......
......@@ -64,6 +64,8 @@ typedef struct drm_i810_private {
unsigned long hw_status_page;
unsigned long counter;
dma_addr_t dma_status_page;
drm_buf_t *mmap_buffer;
......
......@@ -272,29 +272,6 @@ static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d,
return retcode;
}
static unsigned long i830_alloc_page(drm_device_t *dev)
{
unsigned long address;
address = __get_free_page(GFP_KERNEL);
if(address == 0UL)
return 0;
get_page(virt_to_page(address));
LockPage(virt_to_page(address));
return address;
}
static void i830_free_page(drm_device_t *dev, unsigned long page)
{
if (page) {
struct page *p = virt_to_page(page);
put_page(p);
UnlockPage(p);
free_page(page);
}
}
static int i830_dma_cleanup(drm_device_t *dev)
{
drm_device_dma_t *dma = dev->dma;
......@@ -309,7 +286,9 @@ static int i830_dma_cleanup(drm_device_t *dev)
dev_priv->ring.Size);
}
if(dev_priv->hw_status_page != 0UL) {
i830_free_page(dev, dev_priv->hw_status_page);
pci_free_consistent(dev->pdev, PAGE_SIZE,
(void *)dev_priv->hw_status_page,
dev_priv->dma_status_page);
/* Need to rewrite hardware status page */
I830_WRITE(0x02080, 0x1ffff000);
}
......@@ -483,7 +462,9 @@ static int i830_dma_initialize(drm_device_t *dev,
dev_priv->depth_pitch = init->depth_pitch;
/* Program Hardware Status Page */
dev_priv->hw_status_page = i830_alloc_page(dev);
dev_priv->hw_status_page =
(unsigned long) pci_alloc_consistent(dev->pdev, PAGE_SIZE,
&dev_priv->dma_status_page);
if(dev_priv->hw_status_page == 0UL) {
dev->dev_private = (void *)dev_priv;
i830_dma_cleanup(dev);
......@@ -493,7 +474,7 @@ static int i830_dma_initialize(drm_device_t *dev,
memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
I830_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
I830_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
/* Now we need to init our freelist */
......
......@@ -64,6 +64,8 @@ typedef struct drm_i830_private {
unsigned long hw_status_page;
unsigned long counter;
dma_addr_t dma_status_page;
drm_buf_t *mmap_buffer;
u32 front_di1, back_di1, zi1;
......
......@@ -45,11 +45,11 @@
#define DRIVER_NAME "mga"
#define DRIVER_DESC "Matrox G200/G400"
#define DRIVER_DATE "20010321"
#define DRIVER_DATE "20021029"
#define DRIVER_MAJOR 3
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 2
#define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma_buffers, 1, 0 }, \
......@@ -61,7 +61,8 @@
[DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_dma_vertex, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam, 1, 0 },
#define __HAVE_COUNTERS 3
#define __HAVE_COUNTER6 _DRM_STAT_IRQ
......@@ -77,6 +78,9 @@
/* DMA customization:
*/
#define __HAVE_DMA 1
#define __HAVE_DMA_IRQ 1
#define __HAVE_VBL_IRQ 1
#define __HAVE_SHARED_IRQ 1
#define __HAVE_DMA_QUIESCENT 1
#define DRIVER_DMA_QUIESCENT() do { \
......
......@@ -27,7 +27,7 @@
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Jeff Hartmann <jhartmann@valinux.com>
* Keith Whitwell <keithw@valinux.com>
* Keith Whitwell <keith@tungstengraphics.com>
*
* Rewritten by:
* Gareth Hughes <gareth@valinux.com>
......@@ -166,7 +166,7 @@ void mga_do_dma_flush( drm_mga_private_t *dev_priv )
for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
if ( status == MGA_ENDPRDMASTS ) break;
udelay( 1 );
DRM_UDELAY( 1 );
}
if ( primary->tail == primary->last_flush ) {
......
......@@ -26,7 +26,7 @@
*
* Authors:
* Jeff Hartmann <jhartmann@valinux.com>
* Keith Whitwell <keithw@valinux.com>
* Keith Whitwell <keith@tungstengraphics.com>
*
* Rewritten by:
* Gareth Hughes <gareth@valinux.com>
......@@ -239,6 +239,7 @@ typedef struct _drm_mga_sarea {
#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t)
#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x47, drm_mga_iload_t)
#define DRM_IOCTL_MGA_BLIT DRM_IOW( 0x48, drm_mga_blit_t)
#define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(0x49, drm_mga_getparam_t)
typedef struct _drm_mga_warp_index {
int installed;
......@@ -322,4 +323,14 @@ typedef struct _drm_mga_blit {
int source_pitch, dest_pitch;
} drm_mga_blit_t;
/* 3.1: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define MGA_PARAM_IRQ_NR 1
typedef struct drm_mga_getparam {
int param;
int *value;
} drm_mga_getparam_t;
#endif
......@@ -125,6 +125,7 @@ extern int mga_dma_vertex( DRM_IOCTL_ARGS );
extern int mga_dma_indices( DRM_IOCTL_ARGS );
extern int mga_dma_iload( DRM_IOCTL_ARGS );
extern int mga_dma_blit( DRM_IOCTL_ARGS );
extern int mga_getparam( DRM_IOCTL_ARGS );
/* mga_warp.c */
extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv );
......@@ -141,6 +142,7 @@ extern int mga_warp_init( drm_mga_private_t *dev_priv );
#ifdef __alpha__
#define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg)))
#define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg)))
#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0)
#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0)
......@@ -152,6 +154,7 @@ static inline u32 _MGA_READ(u32 *addr)
#else
#define MGA_READ( reg ) MGA_DEREF( reg )
#define MGA_READ8( reg ) MGA_DEREF8( reg )
#define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0)
#define MGA_WRITE8( reg, val ) do { MGA_DEREF8( reg ) = val; } while (0)
#endif
......@@ -345,6 +348,11 @@ do { \
/* A reduced set of the mga registers.
*/
#define MGA_CRTC_INDEX 0x1fd4
#define MGA_CRTC_DATA 0x1fd5
/* CRTC11 */
#define MGA_VINTCLR (1 << 4)
#define MGA_VINTEN (1 << 5)
#define MGA_ALPHACTRL 0x2c7c
#define MGA_AR0 0x1c60
......@@ -416,8 +424,10 @@ do { \
#define MGA_ICLEAR 0x1e18
# define MGA_SOFTRAPICLR (1 << 0)
# define MGA_VLINEICLR (1 << 5)
#define MGA_IEN 0x1e1c
# define MGA_SOFTRAPIEN (1 << 0)
# define MGA_VLINEIEN (1 << 5)
#define MGA_LEN 0x1c5c
......@@ -456,6 +466,8 @@ do { \
# define MGA_SRCACC_AGP (1 << 1)
#define MGA_STATUS 0x1e14
# define MGA_SOFTRAPEN (1 << 0)
# define MGA_VSYNCPEN (1 << 4)
# define MGA_VLINEPEN (1 << 5)
# define MGA_DWGENGSTS (1 << 16)
# define MGA_ENDPRDMASTS (1 << 17)
#define MGA_STENCIL 0x2cc8
......
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
* Eric Anholt <anholt@FreeBSD.org>
*/
#include "mga.h"
#include "drmP.h"
#include "drm.h"
#include "mga_drm.h"
#include "mga_drv.h"
void mga_dma_service( DRM_IRQ_ARGS )
{
drm_device_t *dev = (drm_device_t *) arg;
drm_mga_private_t *dev_priv =
(drm_mga_private_t *)dev->dev_private;
int status;
status = MGA_READ( MGA_STATUS );
/* VBLANK interrupt */
if ( status & MGA_VLINEPEN ) {
MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
}
}
int mga_vblank_wait(drm_device_t *dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ,
( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
+ ~*sequence + 1 ) <= (1<<23) ) );
*sequence = cur_vblank;
return ret;
}
void mga_driver_irq_preinstall( drm_device_t *dev ) {
drm_mga_private_t *dev_priv =
(drm_mga_private_t *)dev->dev_private;
/* Disable *all* interrupts */
MGA_WRITE( MGA_IEN, 0 );
/* Clear bits if they're already high */
MGA_WRITE( MGA_ICLEAR, ~0 );
}
void mga_driver_irq_postinstall( drm_device_t *dev ) {
drm_mga_private_t *dev_priv =
(drm_mga_private_t *)dev->dev_private;
/* Turn on VBL interrupt */
MGA_WRITE( MGA_IEN, MGA_VLINEIEN );
}
void mga_driver_irq_uninstall( drm_device_t *dev ) {
drm_mga_private_t *dev_priv =
(drm_mga_private_t *)dev->dev_private;
if ( dev_priv ) {
/* Disable *all* interrupts */
MGA_WRITE( MGA_IEN, 0 );
}
}
......@@ -26,7 +26,7 @@
*
* Authors:
* Jeff Hartmann <jhartmann@valinux.com>
* Keith Whitwell <keithw@valinux.com>
* Keith Whitwell <keith@tungstengraphics.com>
*
* Rewritten by:
* Gareth Hughes <gareth@valinux.com>
......@@ -1075,3 +1075,36 @@ int mga_dma_blit( DRM_IOCTL_ARGS )
return 0;
}
int mga_getparam( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_getparam_t param;
int value;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( param, (drm_mga_getparam_t *)data,
sizeof(param) );
DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID );
switch( param.param ) {
case MGA_PARAM_IRQ_NR:
value = dev->irq;
break;
default:
return DRM_ERR(EINVAL);
}
if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) {
DRM_ERROR( "copy_to_user\n" );
return DRM_ERR(EFAULT);
}
return 0;
}
......@@ -47,10 +47,10 @@
#define DRIVER_NAME "r128"
#define DRIVER_DESC "ATI Rage 128"
#define DRIVER_DATE "20010917"
#define DRIVER_DATE "20021029"
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 2
#define DRIVER_MINOR 3
#define DRIVER_PATCHLEVEL 0
......@@ -70,7 +70,8 @@
[DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)] = { r128_cce_depth, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, \
[DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)] = { r128_getparam, 1, 1 },
/* Driver customization:
*/
......@@ -90,6 +91,9 @@
/* DMA customization:
*/
#define __HAVE_DMA 1
#define __HAVE_DMA_IRQ 1
#define __HAVE_VBL_IRQ 1
#define __HAVE_SHARED_IRQ 1
#if 0
/* GH: Remove this for now... */
......
......@@ -190,6 +190,7 @@ typedef struct drm_r128_sarea {
#define DRM_IOCTL_R128_INDIRECT DRM_IOWR(0x4f, drm_r128_indirect_t)
#define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( 0x50, drm_r128_fullscreen_t)
#define DRM_IOCTL_R128_CLEAR2 DRM_IOW( 0x51, drm_r128_clear2_t)
#define DRM_IOCTL_R128_GETPARAM DRM_IOW( 0x52, drm_r128_getparam_t)
typedef struct drm_r128_init {
enum {
......@@ -305,4 +306,14 @@ typedef struct drm_r128_fullscreen {
} func;
} drm_r128_fullscreen_t;
/* 2.3: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define R128_PARAM_IRQ_NR 1
typedef struct drm_r128_getparam {
int param;
int *value;
} drm_r128_getparam_t;
#endif
......@@ -124,6 +124,7 @@ extern int r128_cce_idle( DRM_IOCTL_ARGS );
extern int r128_engine_reset( DRM_IOCTL_ARGS );
extern int r128_fullscreen( DRM_IOCTL_ARGS );
extern int r128_cce_buffers( DRM_IOCTL_ARGS );
extern int r128_getparam( DRM_IOCTL_ARGS );
extern void r128_freelist_reset( drm_device_t *dev );
extern drm_buf_t *r128_freelist_get( drm_device_t *dev );
......@@ -213,6 +214,11 @@ extern int r128_cce_indirect( DRM_IOCTL_ARGS );
#define R128_DST_PITCH_OFFSET_C 0x1c80
# define R128_DST_TILE (1 << 31)
#define R128_GEN_INT_CNTL 0x0040
# define R128_CRTC_VBLANK_INT_EN (1 << 0)
#define R128_GEN_INT_STATUS 0x0044
# define R128_CRTC_VBLANK_INT (1 << 0)
# define R128_CRTC_VBLANK_INT_AK (1 << 0)
#define R128_GEN_RESET_CNTL 0x00f0
# define R128_SOFT_RESET_GUI (1 << 0)
......
/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
* Eric Anholt <anholt@FreeBSD.org>
*/
#include "r128.h"
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
#include "r128_drv.h"
void r128_dma_service( DRM_IRQ_ARGS )
{
drm_device_t *dev = (drm_device_t *) arg;
drm_r128_private_t *dev_priv =
(drm_r128_private_t *)dev->dev_private;
int status;
status = R128_READ( R128_GEN_INT_STATUS );
/* VBLANK interrupt */
if ( status & R128_CRTC_VBLANK_INT ) {
R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
}
}
int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ,
( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
+ ~*sequence + 1 ) <= (1<<23) ) );
*sequence = cur_vblank;
return ret;
}
void r128_driver_irq_preinstall( drm_device_t *dev ) {
drm_r128_private_t *dev_priv =
(drm_r128_private_t *)dev->dev_private;
/* Disable *all* interrupts */
R128_WRITE( R128_GEN_INT_CNTL, 0 );
/* Clear vblank bit if it's already high */
R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK );
}
void r128_driver_irq_postinstall( drm_device_t *dev ) {
drm_r128_private_t *dev_priv =
(drm_r128_private_t *)dev->dev_private;
/* Turn on VBL interrupt */
R128_WRITE( R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN );
}
void r128_driver_irq_uninstall( drm_device_t *dev ) {
drm_r128_private_t *dev_priv =
(drm_r128_private_t *)dev->dev_private;
if ( dev_priv ) {
/* Disable *all* interrupts */
R128_WRITE( R128_GEN_INT_CNTL, 0 );
}
}
......@@ -1564,3 +1564,36 @@ int r128_cce_indirect( DRM_IOCTL_ARGS )
return 0;
}
int r128_getparam( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_getparam_t param;
int value;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( param, (drm_r128_getparam_t *)data,
sizeof(param) );
DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID );
switch( param.param ) {
case R128_PARAM_IRQ_NR:
value = dev->irq;
break;
default:
return DRM_ERR(EINVAL);
}
if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) {
DRM_ERROR( "copy_to_user\n" );
return DRM_ERR(EFAULT);
}
return 0;
}
......@@ -51,7 +51,7 @@
#define DRIVER_DATE "20020828"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 6
#define DRIVER_MINOR 7
#define DRIVER_PATCHLEVEL 0
/* Interface history:
......@@ -73,6 +73,10 @@
* Add irq ioctls and irq_active getparam.
* Add wait command for cmdbuf ioctl
* Add agp offset query for getparam
* 1.7 - Add support for cube map registers: R200_PP_CUBIC_FACES_[0..5]
* and R200_PP_CUBIC_OFFSET_F1_[0..5].
* Added packets R200_EMIT_PP_CUBIC_FACES_[0..5] and
* R200_EMIT_PP_CUBIC_OFFSETS_[0..5]. (brian)
*/
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
......
......@@ -27,7 +27,7 @@
* Authors:
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
* Keith Whitwell <keith_whitwell@yahoo.com>
* Keith Whitwell <keith@tungstengraphics.com>
*/
#ifndef __RADEON_DRM_H__
......@@ -129,7 +129,19 @@
#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */
#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */
#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */
#define RADEON_MAX_STATE_PACKETS 61
#define R200_EMIT_PP_CUBIC_FACES_0 61
#define R200_EMIT_PP_CUBIC_OFFSETS_0 62
#define R200_EMIT_PP_CUBIC_FACES_1 63
#define R200_EMIT_PP_CUBIC_OFFSETS_1 64
#define R200_EMIT_PP_CUBIC_FACES_2 65
#define R200_EMIT_PP_CUBIC_OFFSETS_2 66
#define R200_EMIT_PP_CUBIC_FACES_3 67
#define R200_EMIT_PP_CUBIC_OFFSETS_3 68
#define R200_EMIT_PP_CUBIC_FACES_4 69
#define R200_EMIT_PP_CUBIC_OFFSETS_4 70
#define R200_EMIT_PP_CUBIC_FACES_5 71
#define R200_EMIT_PP_CUBIC_OFFSETS_5 72
#define RADEON_MAX_STATE_PACKETS 73
/* Commands understood by cmd_buffer ioctl. More can be added but
......@@ -343,6 +355,7 @@ typedef struct {
int ctx_owner;
int pfState; /* number of 3d windows (0,1,2ormore) */
int pfCurrentPage; /* which buffer is being displayed? */
int crtc2_base; /* CRTC2 frame offset */
} drm_radeon_sarea_t;
......
......@@ -109,8 +109,6 @@ typedef struct drm_radeon_private {
int do_boxes;
int page_flipping;
int current_page;
u32 crtc_offset;
u32 crtc_offset_cntl;
u32 color_fmt;
unsigned int front_offset;
......@@ -230,6 +228,8 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define RADEON_CRTC_OFFSET_CNTL 0x0228
# define RADEON_CRTC_TILE_EN (1 << 15)
# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16)
#define RADEON_CRTC2_OFFSET 0x0324
#define RADEON_CRTC2_OFFSET_CNTL 0x0328
#define RADEON_RB3D_COLORPITCH 0x1c48
......@@ -574,6 +574,9 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define RADEON_TXFORMAT_RGBA8888 7
#define RADEON_TXFORMAT_VYUY422 10
#define RADEON_TXFORMAT_YVYU422 11
#define RADEON_TXFORMAT_DXT1 12
#define RADEON_TXFORMAT_DXT23 14
#define RADEON_TXFORMAT_DXT45 15
#define R200_PP_TXCBLEND_0 0x2f00
#define R200_PP_TXCBLEND_1 0x2f10
......@@ -602,6 +605,44 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define R200_PP_TXOFFSET_2 0x2d30
#define R200_PP_TXOFFSET_1 0x2d18
#define R200_PP_TXOFFSET_0 0x2d00
#define R200_PP_CUBIC_FACES_0 0x2c18
#define R200_PP_CUBIC_FACES_1 0x2c38
#define R200_PP_CUBIC_FACES_2 0x2c58
#define R200_PP_CUBIC_FACES_3 0x2c78
#define R200_PP_CUBIC_FACES_4 0x2c98
#define R200_PP_CUBIC_FACES_5 0x2cb8
#define R200_PP_CUBIC_OFFSET_F1_0 0x2d04
#define R200_PP_CUBIC_OFFSET_F2_0 0x2d08
#define R200_PP_CUBIC_OFFSET_F3_0 0x2d0c
#define R200_PP_CUBIC_OFFSET_F4_0 0x2d10
#define R200_PP_CUBIC_OFFSET_F5_0 0x2d14
#define R200_PP_CUBIC_OFFSET_F1_1 0x2d1c
#define R200_PP_CUBIC_OFFSET_F2_1 0x2d20
#define R200_PP_CUBIC_OFFSET_F3_1 0x2d24
#define R200_PP_CUBIC_OFFSET_F4_1 0x2d28
#define R200_PP_CUBIC_OFFSET_F5_1 0x2d2c
#define R200_PP_CUBIC_OFFSET_F1_2 0x2d34
#define R200_PP_CUBIC_OFFSET_F2_2 0x2d38
#define R200_PP_CUBIC_OFFSET_F3_2 0x2d3c
#define R200_PP_CUBIC_OFFSET_F4_2 0x2d40
#define R200_PP_CUBIC_OFFSET_F5_2 0x2d44
#define R200_PP_CUBIC_OFFSET_F1_3 0x2d4c
#define R200_PP_CUBIC_OFFSET_F2_3 0x2d50
#define R200_PP_CUBIC_OFFSET_F3_3 0x2d54
#define R200_PP_CUBIC_OFFSET_F4_3 0x2d58
#define R200_PP_CUBIC_OFFSET_F5_3 0x2d5c
#define R200_PP_CUBIC_OFFSET_F1_4 0x2d64
#define R200_PP_CUBIC_OFFSET_F2_4 0x2d68
#define R200_PP_CUBIC_OFFSET_F3_4 0x2d6c
#define R200_PP_CUBIC_OFFSET_F4_4 0x2d70
#define R200_PP_CUBIC_OFFSET_F5_4 0x2d74
#define R200_PP_CUBIC_OFFSET_F1_5 0x2d7c
#define R200_PP_CUBIC_OFFSET_F2_5 0x2d80
#define R200_PP_CUBIC_OFFSET_F3_5 0x2d84
#define R200_PP_CUBIC_OFFSET_F4_5 0x2d88
#define R200_PP_CUBIC_OFFSET_F5_5 0x2d8c
#define R200_RE_AUX_SCISSOR_CNTL 0x26f0
#define R200_SE_VTE_CNTL 0x20b0
#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL 0x2250
......
......@@ -30,6 +30,7 @@
#include "radeon.h"
#include "drmP.h"
#include "drm.h"
#include "drm_sarea.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
......@@ -279,6 +280,18 @@ static struct {
{ R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL" },
{ R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE" },
{ R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4, "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0" },
{ R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0" }, /* 61 */
{ R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0" }, /* 62 */
{ R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1" },
{ R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1" },
{ R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2" },
{ R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2" },
{ R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3" },
{ R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3" },
{ R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4" },
{ R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4" },
{ R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5" },
{ R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5" },
};
......@@ -791,6 +804,9 @@ static void radeon_cp_dispatch_swap( drm_device_t *dev )
static void radeon_cp_dispatch_flip( drm_device_t *dev )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_sarea_t *sarea = (drm_sarea_t *)dev_priv->sarea->handle;
int offset = (dev_priv->current_page == 1)
? dev_priv->front_offset : dev_priv->back_offset;
RING_LOCALS;
DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n",
__FUNCTION__,
......@@ -804,18 +820,17 @@ static void radeon_cp_dispatch_flip( drm_device_t *dev )
radeon_cp_performance_boxes( dev_priv );
}
BEGIN_RING( 4 );
/* Update the frame offsets for both CRTCs
*/
BEGIN_RING( 6 );
RADEON_WAIT_UNTIL_3D_IDLE();
OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET, 0 ) );
if ( dev_priv->current_page == 0 ) {
OUT_RING( dev_priv->back_offset );
dev_priv->current_page = 1;
} else {
OUT_RING( dev_priv->front_offset );
dev_priv->current_page = 0;
}
OUT_RING_REG( RADEON_CRTC_OFFSET, ( ( sarea->frame.y * dev_priv->front_pitch
+ sarea->frame.x
* ( dev_priv->color_fmt - 2 ) ) & ~7 )
+ offset );
OUT_RING_REG( RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
+ offset );
ADVANCE_RING();
......@@ -824,7 +839,8 @@ static void radeon_cp_dispatch_flip( drm_device_t *dev )
* performing the swapbuffer ioctl.
*/
dev_priv->sarea_priv->last_frame++;
dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
1 - dev_priv->current_page;
BEGIN_RING( 2 );
......@@ -1292,12 +1308,12 @@ static int radeon_do_init_pageflip( drm_device_t *dev )
DRM_DEBUG( "\n" );
dev_priv->crtc_offset_cntl = RADEON_READ( RADEON_CRTC_OFFSET_CNTL );
BEGIN_RING( 4 );
BEGIN_RING( 6 );
RADEON_WAIT_UNTIL_3D_IDLE();
OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET_CNTL, 0 ) );
OUT_RING( dev_priv->crtc_offset_cntl | RADEON_CRTC_OFFSET_FLIP_CNTL );
OUT_RING( RADEON_READ( RADEON_CRTC_OFFSET_CNTL ) | RADEON_CRTC_OFFSET_FLIP_CNTL );
OUT_RING( CP_PACKET0( RADEON_CRTC2_OFFSET_CNTL, 0 ) );
OUT_RING( RADEON_READ( RADEON_CRTC2_OFFSET_CNTL ) | RADEON_CRTC_OFFSET_FLIP_CNTL );
ADVANCE_RING();
dev_priv->page_flipping = 1;
......@@ -1318,10 +1334,6 @@ int radeon_do_cleanup_pageflip( drm_device_t *dev )
if (dev_priv->current_page != 0)
radeon_cp_dispatch_flip( dev );
/* FIXME: If the X server changes screen resolution, it
* clobbers the value of RADEON_CRTC_OFFSET_CNTL, above,
* leading to a flashing efect.
*/
dev_priv->page_flipping = 0;
return 0;
}
......@@ -1792,11 +1804,16 @@ static int radeon_emit_packets(
drm_radeon_cmd_buffer_t *cmdbuf )
{
int id = (int)header.packet.packet_id;
int sz = packet[id].len;
int reg = packet[id].start;
int sz, reg;
int *data = (int *)cmdbuf->buf;
RING_LOCALS;
if (id >= RADEON_MAX_STATE_PACKETS)
return DRM_ERR(EINVAL);
sz = packet[id].len;
reg = packet[id].start;
if (sz * sizeof(int) > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
......
......@@ -63,8 +63,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.1"
#define DRV_MODULE_RELDATE "Aug 30, 2002"
#define DRV_MODULE_VERSION "1.2"
#define DRV_MODULE_RELDATE "Nov 14, 2002"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
......@@ -2377,13 +2377,28 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
/* No BH disabling for tx_lock here. We are running in BH disabled
* context and TX reclaim runs via tp->poll inside of a software
* interrupt. Rejoice!
*
* Actually, things are not so simple. If we are to take a hw
* IRQ here, we can deadlock, consider:
*
* CPU1 CPU2
* tg3_start_xmit
* take tp->tx_lock
* tg3_timer
* take tp->lock
* tg3_interrupt
* spin on tp->lock
* spin on tp->tx_lock
*
* So we really do need to disable interrupts when taking
* tx_lock here.
*/
spin_lock(&tp->tx_lock);
spin_lock_irq(&tp->tx_lock);
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
netif_stop_queue(dev);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->tx_lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1;
......@@ -2535,7 +2550,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out_unlock:
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->tx_lock);
dev->trans_start = jiffies;
......@@ -2553,13 +2568,28 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* No BH disabling for tx_lock here. We are running in BH disabled
* context and TX reclaim runs via tp->poll inside of a software
* interrupt. Rejoice!
*
* Actually, things are not so simple. If we are to take a hw
* IRQ here, we can deadlock, consider:
*
* CPU1 CPU2
* tg3_start_xmit
* take tp->tx_lock
* tg3_timer
* take tp->lock
* tg3_interrupt
* spin on tp->lock
* spin on tp->tx_lock
*
* So we really do need to disable interrupts when taking
* tx_lock here.
*/
spin_lock(&tp->tx_lock);
spin_lock_irq(&tp->tx_lock);
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
netif_stop_queue(dev);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->tx_lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1;
......@@ -2665,7 +2695,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->tx_lock);
dev->trans_start = jiffies;
......
......@@ -8,13 +8,8 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_OHCI) += host/
obj-$(CONFIG_USB_OHCI_SA1111) += host/
obj-$(CONFIG_USB_SL811HS) += host/
obj-$(CONFIG_USB_UHCI_ALT) += host/
obj-$(CONFIG_USB_UHCI_HCD_ALT) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI) += host/
obj-$(CONFIG_USB_SL811HS) += host/
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_AUDIO) += class/
......
......@@ -20,14 +20,16 @@ config USB_BLUETOOTH_TTY
tristate "USB Bluetooth TTY support"
depends on USB
---help---
Say Y here if you want to connect a USB Bluetooth device to your
computer's USB port. You will need the Bluetooth stack (available
at <http://developer.axis.com/software/index.shtml>) to fully use
the device.
This driver implements a tty inteface to a Bluetooth device. If
you want to use a socket based Bluetooth stack (like the BlueZ
stack), do not use this driver.
This driver implements a nonstandard tty interface to a Bluetooth
device that can be used only by specialized Bluetooth HCI software.
Say Y here if you want to use OpenBT Bluetooth stack (available
at <http://developer.axis.com/software/index.shtml>), or other TTY
based Bluetooth stacks, and want to connect a USB Bluetooth device
to your computer's USB port.
Do *not* enable this driver if you want to use generic Linux
Bluetooth support.
If in doubt, say N here.
......
/*
* usblp.c Version 0.12
* usblp.c Version 0.13
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
* Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com>
* Copyright (c) 2000 Randy Dunlap <rddunlap@osdl.org>
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
# Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com>
# Copyright (c) 2001 David Paschal <paschal@rcsis.com>
......@@ -25,6 +25,8 @@
* v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
* v0.11 - add proto_bias option (Pete Zaitcev)
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
*/
/*
......@@ -59,7 +61,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.12"
#define DRIVER_VERSION "v0.13"
#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
#define DRIVER_DESC "USB Printer Device Class driver"
......@@ -120,11 +122,19 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_LAST_PROTOCOL 3
#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1)
/*
* some arbitrary status buffer size;
* need a status buffer that is allocated via kmalloc(), not on stack
*/
#define STATUS_BUF_SIZE 8
struct usblp {
struct usb_device *dev; /* USB device */
devfs_handle_t devfs; /* devfs device */
struct semaphore sem; /* locks this struct, especially "dev" */
char *buf; /* writeurb->transfer_buffer */
char *writebuf; /* write transfer_buffer */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */
......@@ -289,13 +299,14 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
error = usblp_read_status (usblp, &status);
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
err("usblp%d: error %d reading printer status",
usblp->minor, error);
return 0;
}
status = *usblp->statusbuf;
if (~status & LP_PERRORP) {
newerr = 3;
if (status & LP_POUTPA) newerr = 1;
......@@ -375,8 +386,12 @@ static void usblp_cleanup (struct usblp *usblp)
usb_deregister_dev (1, usblp->minor);
info("usblp%d: removed", usblp->minor);
kfree (usblp->writeurb->transfer_buffer);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->writeurb->transfer_dma);
kfree (usblp->device_id_string);
kfree (usblp->statusbuf);
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree (usblp);
......@@ -841,11 +856,27 @@ static int usblp_probe(struct usb_interface *intf,
goto abort_minor;
}
/* Malloc write/read buffers in one chunk. We somewhat wastefully
usblp->writebuf = usblp->readbuf = NULL;
usblp->writeurb->transfer_flags = URB_NO_DMA_MAP;
usblp->readurb->transfer_flags = URB_NO_DMA_MAP;
/* Malloc write & read buffers. We somewhat wastefully
* malloc both regardless of bidirectionality, because the
* alternate setting can be changed later via an ioctl. */
if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
err("out of memory for buf");
if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
err("out of memory for write buf");
goto abort_minor;
}
if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
GFP_KERNEL, &usblp->readurb->transfer_dma))) {
err("out of memory for read buf");
goto abort_minor;
}
/* Allocate buffer for printer status */
usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
if (!usblp->statusbuf) {
err("out of memory for statusbuf");
goto abort_minor;
}
......@@ -900,10 +931,16 @@ static int usblp_probe(struct usb_interface *intf,
usb_deregister_dev (1, usblp->minor);
abort:
if (usblp) {
if (usblp->writebuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
if (usblp->readbuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->writeurb->transfer_dma);
if (usblp->statusbuf) kfree(usblp->statusbuf);
if (usblp->device_id_string) kfree(usblp->device_id_string);
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
if (usblp->buf) kfree(usblp->buf);
if (usblp->device_id_string) kfree(usblp->device_id_string);
kfree(usblp);
}
return -EIO;
......@@ -1020,16 +1057,16 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[protocol].epwrite->bEndpointAddress),
usblp->buf, 0,
usblp->protocol[protocol].epwrite->bEndpointAddress),
usblp->writebuf, 0,
usblp_bulk_write, usblp);
usblp->bidir = (usblp->protocol[protocol].epread != 0);
if (usblp->bidir)
usb_fill_bulk_urb(usblp->readurb, usblp->dev,
usb_rcvbulkpipe(usblp->dev,
usblp->protocol[protocol].epread->bEndpointAddress),
usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE,
usblp->protocol[protocol].epread->bEndpointAddress),
usblp->readbuf, USBLP_BUF_SIZE,
usblp_bulk_read, usblp);
usblp->current_protocol = protocol;
......
......@@ -148,23 +148,31 @@ usb_descriptor_attr (bcdDevice, "%04x\n")
usb_descriptor_attr (bDeviceClass, "%02x\n")
usb_descriptor_attr (bDeviceSubClass, "%02x\n")
usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n")
void usb_create_driverfs_dev_files (struct usb_device *udev)
{
struct device *dev = &udev->dev;
/* current configuration's attributes */
device_create_file (dev, &dev_attr_bNumInterfaces);
device_create_file (dev, &dev_attr_bConfigurationValue);
device_create_file (dev, &dev_attr_bmAttributes);
device_create_file (dev, &dev_attr_bMaxPower);
/* device attributes */
device_create_file (dev, &dev_attr_idVendor);
device_create_file (dev, &dev_attr_idProduct);
device_create_file (dev, &dev_attr_bcdDevice);
device_create_file (dev, &dev_attr_bDeviceClass);
device_create_file (dev, &dev_attr_bDeviceSubClass);
device_create_file (dev, &dev_attr_bDeviceProtocol);
device_create_file (dev, &dev_attr_bNumConfigurations);
/* speed varies depending on how you connect the device */
device_create_file (dev, &dev_attr_speed);
// FIXME iff there are other speed configs, show how many
if (udev->descriptor.iManufacturer)
device_create_file (dev, &dev_attr_manufacturer);
......
......@@ -138,6 +138,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
hcd->pdev = dev;
hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->name;
hcd->controller = &dev->dev;
if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3:
......
......@@ -23,6 +23,11 @@
*/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#endif
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
......@@ -32,13 +37,6 @@
#include <linux/pci.h> /* for hcd->pdev and dma addressing */
#include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
#include "hcd.h"
......@@ -1090,6 +1088,7 @@ static int hcd_unlink_urb (struct urb *urb)
{
struct hcd_dev *dev;
struct usb_hcd *hcd = 0;
struct device *sys = 0;
unsigned long flags;
struct completion_splice splice;
int retval;
......@@ -1110,38 +1109,31 @@ static int hcd_unlink_urb (struct urb *urb)
*/
spin_lock_irqsave (&urb->lock, flags);
spin_lock (&hcd_data_lock);
if (!urb->hcpriv || urb->transfer_flags & URB_TIMEOUT_KILLED) {
retval = -EINVAL;
goto done;
}
if (!urb->dev || !urb->dev->bus) {
retval = -ENODEV;
goto done;
}
/* giveback clears dev; non-null means it's linked at this level */
dev = urb->dev->hcpriv;
sys = &urb->dev->dev;
hcd = urb->dev->bus->hcpriv;
if (!dev || !hcd) {
retval = -ENODEV;
goto done;
}
/* Except for interrupt transfers, any status except -EINPROGRESS
* means the HCD already started to unlink this URB from the hardware.
* So there's no more work to do.
*
* For interrupt transfers, this is the only way to trigger unlinking
* from the hardware. Since we (currently) overload urb->status to
* tell the driver to unlink, error status might get clobbered ...
* unless that transfer hasn't yet restarted. One such case is when
* the URB gets unlinked from its completion handler.
if (!urb->hcpriv) {
retval = -EINVAL;
goto done;
}
/* Any status except -EINPROGRESS means something already started to
* unlink this URB from the hardware. So there's no more work to do.
*
* FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
* FIXME use better explicit urb state
*/
if (urb->status != -EINPROGRESS
&& usb_pipetype (urb->pipe) != PIPE_INTERRUPT) {
if (urb->status != -EINPROGRESS) {
retval = -EINVAL;
goto done;
}
......@@ -1150,9 +1142,7 @@ static int hcd_unlink_urb (struct urb *urb)
* lower level hcd code is always async, locking on urb->status
* updates; an intercepted completion unblocks us.
*/
if ((urb->transfer_flags & URB_TIMEOUT_KILLED))
urb->status = -ETIMEDOUT;
else if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
if (in_interrupt ()) {
dbg ("non-async unlink in_interrupt");
retval = -EWOULDBLOCK;
......@@ -1177,29 +1167,34 @@ static int hcd_unlink_urb (struct urb *urb)
retval = 0;
} else {
retval = hcd->driver->urb_dequeue (hcd, urb);
// FIXME: if retval and we tried to splice, whoa!!
if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
/* hcds shouldn't really fail these calls, but... */
if (retval) {
dev_dbg (*sys, "dequeue %p --> %d\n", urb, retval);
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
spin_lock_irqsave (&urb->lock, flags);
urb->complete = splice.complete;
urb->context = splice.context;
spin_unlock_irqrestore (&urb->lock, flags);
}
goto bye;
}
}
/* block till giveback, if needed */
if (!(urb->transfer_flags & (URB_ASYNC_UNLINK|URB_TIMEOUT_KILLED))
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
dbg ("%s: wait for giveback urb %p",
hcd->self.bus_name, urb);
wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & URB_ASYNC_UNLINK) && retval == 0) {
if (urb->transfer_flags & URB_ASYNC_UNLINK)
return -EINPROGRESS;
}
goto bye;
dev_dbg (*sys, "wait for giveback urb %p\n", urb);
wait_for_completion (&splice.done);
return 0;
done:
spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags);
bye:
if (retval)
dbg ("%s: hcd_unlink_urb fail %d",
hcd ? hcd->self.bus_name : "(no bus?)",
retval);
if (retval && sys)
dev_dbg (*sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
return retval;
}
......
......@@ -74,10 +74,10 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct hc_driver *driver; /* hw-specific hooks */
int irq; /* irq allocated */
void *regs; /* device memory/io */
struct device *controller; /* handle to hardware */
/* a few non-PCI controllers exist, mostly for OHCI */
struct pci_dev *pdev; /* pci is typical */
struct device *parent; /* parent device driver */
#ifdef CONFIG_PCI
int region; /* pci region for regs */
u32 pci_state [16]; /* for PM state save */
......
......@@ -67,7 +67,7 @@ static void generic_release (struct device_driver * drv)
}
static struct device_driver usb_generic_driver = {
.name = "generic",
.name = "usb",
.bus = &usb_bus_type,
.probe = generic_probe,
.remove = generic_remove,
......@@ -514,17 +514,10 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* Some synchronization is important: removes can't start processing
* before the add-device processing completes, and vice versa. That keeps
* a stack of USB-related identifiers stable while they're in use. If we
* know that agents won't complete after they return (such as by forking
* a process that completes later), it's enough to just waitpid() for the
* agent -- as is currently done.
*
* The reason: we know we're called either from khubd (the typical case)
* or from root hub initialization (init, kapmd, modprobe, etc). In both
* cases, we know no other thread can recycle our address, since we must
* already have been serialized enough to prevent that.
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
......@@ -579,7 +572,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
scratch += length;
#endif
/* per-device configuration hacks are common */
/* per-device configurations are common */
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor,
......@@ -604,10 +597,9 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
/* a simple/common case: one config, one interface, one driver
* with current altsetting being a reasonable setting.
* everything needs a smart agent and usbfs; or can rely on
* device-specific binding policies.
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
......@@ -949,6 +941,24 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
int i;
int j;
/*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*
* Do it asap, so more driver model stuff (like the device.h message
* utilities) can be used in hcd submit/unlink code paths.
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
if (dev->dev.bus_id[0] == 0)
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
/* USB device state == default ... it's not usable yet */
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
*/
......@@ -1010,6 +1020,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
/* USB device state == addressed ... still not usable */
err = usb_get_device_descriptor(dev);
if (err < (signed)sizeof(dev->descriptor)) {
if (err < 0)
......@@ -1042,6 +1054,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
return 1;
}
/* USB device state == configured ... tell the world! */
dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
set_device_description (dev);
......@@ -1051,23 +1065,10 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
/*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
if (dev->dev.bus_id[0] == 0)
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
/* put into sysfs, with device and config specific files */
err = device_register (&dev->dev);
if (err)
return err;
/* add the USB device specific driverfs files */
usb_create_driverfs_dev_files (dev);
/* Register all of the interfaces for this device with the driver core.
......
......@@ -49,7 +49,7 @@ config USB_OHCI_HCD
The module will be called ohci-hcd.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
config USB_UHCI_HCD_ALT
config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support"
depends on USB
---help---
......
......@@ -5,7 +5,7 @@
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD_ALT) += uhci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811HS) += hc_sl811.o
......
......@@ -272,6 +272,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
{
u32 scratch;
u32 hw_curr;
struct list_head *entry;
struct ehci_qtd *td;
unsigned temp;
......@@ -279,20 +280,22 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
char *next = *nextp;
scratch = cpu_to_le32p (&qh->hw_info1);
temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x",
hw_curr = cpu_to_le32p (&qh->hw_current);
temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
scratch, cpu_to_le32p (&qh->hw_info2));
scratch, cpu_to_le32p (&qh->hw_info2),
hw_curr, cpu_to_le32p (&qh->hw_token));
size -= temp;
next += temp;
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd,
qtd_list);
td = list_entry (entry, struct ehci_qtd, qtd_list);
scratch = cpu_to_le32p (&td->hw_token);
temp = snprintf (next, size,
"\n\ttd/%p %s len=%d %08x urb %p",
"\n\t%std/%p %s len=%d %08x urb %p",
(hw_curr == td->qtd_dma) ? "*" : "",
td, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
......@@ -552,8 +555,8 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
size -= temp;
next += temp;
temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
temp = snprintf (next, size, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink);
size -= temp;
next += temp;
#endif
......
......@@ -494,8 +494,8 @@ static void ehci_stop (struct usb_hcd *hcd)
#ifdef EHCI_STATS
dbg ("irq normal %ld err %ld reclaim %ld",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
dbg ("complete %ld unlink %ld qpatch %ld",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
dbg ("complete %ld unlink %ld",
ehci->stats.complete, ehci->stats.unlink);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
......
......@@ -58,19 +58,23 @@ static void ehci_hcd_free (struct usb_hcd *hcd)
/* Allocate the key transfer structures from the previously allocated pool */
static void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
{
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END;
INIT_LIST_HEAD (&qtd->qtd_list);
}
static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
{
struct ehci_qtd *qtd;
dma_addr_t dma;
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) {
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END;
INIT_LIST_HEAD (&qtd->qtd_list);
}
if (qtd != 0)
ehci_qtd_init (qtd, dma);
return qtd;
}
......@@ -87,12 +91,21 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
qh = (struct ehci_qh *)
pci_pool_alloc (ehci->qh_pool, flags, &dma);
if (qh) {
memset (qh, 0, sizeof *qh);
atomic_set (&qh->refcount, 1);
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
if (!qh)
return qh;
memset (qh, 0, sizeof *qh);
atomic_set (&qh->refcount, 1);
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == 0) {
dbg ("no dummy td");
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
qh = 0;
}
return qh;
}
......@@ -115,6 +128,8 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
dbg ("unused qh not empty!");
BUG ();
}
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
}
......
......@@ -85,7 +85,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
/* update halted (but potentially linked) qh */
static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
static void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
{
qh->hw_current = 0;
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
......@@ -221,17 +221,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct urb *urb = qtd->urb;
u32 token = 0;
/* hc's on-chip qh overlay cache can overwrite our idea of
* next qtd ptrs, if we appended a qtd while the queue was
* advancing. (because we don't use dummy qtds.)
*/
if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current
&& qtd->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = qtd->hw_alt_next;
qh->hw_qtd_next = qtd->hw_next;
COUNT (ehci->stats.qpatch);
}
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
......@@ -495,8 +484,7 @@ qh_urb_transaction (
}
/* by default, enable interrupt on urb completion */
// ... do it always, unless we switch over to dummy qtds
// if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
return head;
......@@ -661,8 +649,15 @@ ehci_qh_make (
/* initialize sw and hw queues with these qtds */
if (!list_empty (qtd_list)) {
struct ehci_qtd *qtd;
/* hc's list view ends with dummy td; we might update it */
qtd = list_entry (qtd_list->prev, struct ehci_qtd, qtd_list);
qtd->hw_next = QTD_NEXT (qh->dummy->qtd_dma);
list_splice (qtd_list, &qh->qtd_list);
qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
qh_update (qh, qtd);
} else {
qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END;
}
......@@ -767,39 +762,48 @@ static struct ehci_qh *qh_append_tds (
/* append to tds already queued to this qh? */
if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
struct ehci_qtd *last_qtd;
u32 hw_next;
/* update the last qtd's "next" pointer */
// dbg_qh ("non-empty qh", ehci, qh);
last_qtd = list_entry (qh->qtd_list.prev,
struct ehci_qtd *dummy;
dma_addr_t dma;
u32 token;
/* to avoid racing the HC, use the dummy td instead of
* the first td of our list (becomes new dummy). both
* tds stay deactivated until we're done, when the
* HC is allowed to fetch the old dummy (4.10.2).
*/
token = qtd->hw_token;
qtd->hw_token = 0;
dummy = qh->dummy;
// dbg ("swap td %p with dummy %p", qtd, dummy);
dma = dummy->qtd_dma;
*dummy = *qtd;
dummy->qtd_dma = dma;
list_del (&qtd->qtd_list);
list_add (&dummy->qtd_list, qtd_list);
ehci_qtd_init (qtd, qtd->qtd_dma);
qh->dummy = qtd;
/* hc must see the new dummy at list end */
qtd = list_entry (qh->qtd_list.prev,
struct ehci_qtd, qtd_list);
hw_next = QTD_NEXT (qtd->qtd_dma);
last_qtd->hw_next = hw_next;
/* previous urb allows short rx? maybe optimize. */
if (!(last_qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
&& (epnum & 0x10)) {
// only the last QTD for now
last_qtd->hw_alt_next = hw_next;
}
qtd->hw_next = QTD_NEXT (dma);
/* qh_completions() may need to patch the qh overlay if
* the hc was advancing this queue while we appended.
* we know it can: last_qtd->hw_token has IOC set.
*
* or: use a dummy td (so the overlay gets the next td
* only when we set its active bit); fewer irqs.
*/
/* let the hc process these next qtds */
wmb ();
dummy->hw_token = token;
/* no URB queued */
} else {
// dbg_qh ("empty qh", ehci, qh);
struct ehci_qtd *last_qtd;
/* NOTE: we already canceled any queued URBs
* when the endpoint halted.
*/
/* make sure hc sees current dummy at the end */
last_qtd = list_entry (qtd_list->prev,
struct ehci_qtd, qtd_list);
last_qtd->hw_next = QTD_NEXT (qh->dummy->qtd_dma);
// dbg_qh ("empty qh", ehci, qh);
/* usb_clear_halt() means qh data toggle gets reset */
if (unlikely (!usb_gettoggle (urb->dev,
......
......@@ -31,11 +31,6 @@ struct ehci_stats {
/* termination of urbs from core */
unsigned long complete;
unsigned long unlink;
/* qhs patched to recover from td queueing race
* (can avoid by using 'dummy td', allowing fewer irqs)
*/
unsigned long qpatch;
};
/* ehci_hcd->lock guards shared data against other CPUs:
......@@ -311,6 +306,7 @@ struct ehci_qh {
dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */
struct ehci_qtd *dummy;
atomic_t refcount;
......
......@@ -24,7 +24,8 @@
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header
*/
static void urb_print (struct urb * urb, char * str, int small)
static void __attribute__((unused))
urb_print (struct urb * urb, char * str, int small)
{
unsigned int pipe= urb->pipe;
......@@ -204,10 +205,6 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
// dumps some of the state we know about
ohci_dump_status (controller);
#ifdef OHCI_VERBOSE_DEBUG
if (verbose)
ohci_dump_periodic (controller, "hcca");
#endif
if (controller->hcca)
dbg ("hcca frame #%04x", controller->hcca->frame_no);
ohci_dump_roothub (controller, 1);
......@@ -510,16 +507,16 @@ static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
static inline void create_debug_files (struct ohci_hcd *bus)
{
device_create_file (bus->hcd.parent, &dev_attr_async);
device_create_file (bus->hcd.parent, &dev_attr_periodic);
device_create_file (bus->hcd.controller, &dev_attr_async);
device_create_file (bus->hcd.controller, &dev_attr_periodic);
// registers
dbg ("%s: created debug files", bus->hcd.self.bus_name);
}
static inline void remove_debug_files (struct ohci_hcd *bus)
{
device_remove_file (bus->hcd.parent, &dev_attr_async);
device_remove_file (bus->hcd.parent, &dev_attr_periodic);
device_remove_file (bus->hcd.controller, &dev_attr_async);
device_remove_file (bus->hcd.controller, &dev_attr_periodic);
}
#else /* empty stubs for creating those files */
......
......@@ -271,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
#ifdef DEBUG
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
#endif
......@@ -514,7 +514,7 @@ static int hc_start (struct ohci_hcd *ohci)
usb_connect (udev);
udev->speed = USB_SPEED_FULL;
if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
if (usb_register_root_hub (udev, ohci->hcd.controller) != 0) {
usb_free_dev (udev);
ohci->hcd.self.root_hub = NULL;
disable (ohci);
......
......@@ -80,8 +80,6 @@ ohci_pci_start (struct usb_hcd *hcd)
}
ohci->regs = hcd->regs;
ohci->parent_dev = &ohci->hcd.pdev->dev;
if (hc_reset (ohci) < 0) {
ohci_stop (hcd);
return -ENODEV;
......
......@@ -110,10 +110,12 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
{
unsigned i;
#ifdef OHCI_VERBOSE_DEBUG
dbg ("%s: link %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval);
#endif
for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
struct ed **prev = &ohci->periodic [i];
......@@ -244,10 +246,12 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
}
ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval;
#ifdef OHCI_VERBOSE_DEBUG
dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval);
#endif
}
/* unlink an ed from one of the HC chains.
......@@ -414,7 +418,6 @@ static struct ed *ed_get (
}
}
ed->hwINFO = info;
}
done:
......
......@@ -176,7 +176,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
hcd->irq = dev->irq[1];
hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV;
hcd->parent = &dev->dev;
hcd->controller = &dev->dev;
retval = hcd_buffer_create (hcd);
if (retval != 0) {
......@@ -292,8 +292,6 @@ ohci_sa1111_start (struct usb_hcd *hcd)
}
ohci->regs = hcd->regs;
ohci->parent_dev = hcd->parent;
if (hc_reset (ohci) < 0) {
ohci_stop (hcd);
return -ENODEV;
......
......@@ -349,11 +349,6 @@ struct hash_list_t {
struct ohci_hcd {
spinlock_t lock;
/*
* parent device
*/
struct device *parent_dev;
/*
* I/O memory used to communicate with the HC (dma-consistent)
*/
......
......@@ -840,7 +840,7 @@ probe_scanner(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev (intf);
struct scn_usb_data *scn;
struct usb_host_interface *interface;
struct usb_host_endpoint *endpoint;
struct usb_endpoint_descriptor *endpoint;
int ep_cnt;
int ix;
......@@ -911,7 +911,6 @@ probe_scanner(struct usb_interface *intf,
}
interface = intf->altsetting;
endpoint = &interface->endpoint[0];
/*
* Start checking for two bulk endpoints OR two bulk endpoints *and* one
......@@ -929,22 +928,23 @@ probe_scanner(struct usb_interface *intf,
ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
while (ep_cnt < interface->desc.bNumEndpoints) {
endpoint = &interface->endpoint[ep_cnt].desc;
if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
if (!have_bulk_in && IS_EP_BULK_IN(endpoint)) {
ep_cnt++;
have_bulk_in = ep_cnt;
dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
continue;
}
if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
if (!have_bulk_out && IS_EP_BULK_OUT(endpoint)) {
ep_cnt++;
have_bulk_out = ep_cnt;
dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
continue;
}
if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
if (!have_intr && IS_EP_INTR(endpoint)) {
ep_cnt++;
have_intr = ep_cnt;
dbg("probe_scanner: intr_ep:%d", have_intr);
......
......@@ -211,10 +211,10 @@ static struct usb_device_id scanner_device_ids [] = {
MODULE_DEVICE_TABLE (usb, scanner_device_ids);
#define IS_EP_BULK(ep) ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
#define IS_EP_INTR(ep) ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
#define IS_EP_BULK(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
#define IS_EP_INTR(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
......
......@@ -1572,7 +1572,8 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id
int i;
char *c;
dbg("HID probe called for ifnum %d", intf->ifnum);
dbg("HID probe called for ifnum %d",
intf->altsetting->desc.bInterfaceNumber);
if (!(hid = usb_hid_configure(intf)))
return -EIO;
......@@ -1590,6 +1591,7 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id
dev_set_drvdata(&intf->dev, hid);
if (!hid->claimed) {
printk ("HID device not claimed by input or hiddev\n");
hid_disconnect(intf);
return -EIO;
}
......
......@@ -33,7 +33,7 @@ struct hid_usage_entry {
char *description;
};
static struct hid_usage_entry hid_usage_table[] = {
static const struct hid_usage_entry hid_usage_table[] = {
{ 0, 0, "Undefined" },
{ 1, 0, "GenericDesktop" },
{0, 0x01, "Pointer"},
......@@ -218,11 +218,95 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"},
{ 0x84, 0, "Power Device" },
{ 0x84, 0x02, "PresentStatus" },
{ 0x84, 0x03, "ChangeStatus" },
{ 0x84, 0x04, "UPS" },
{ 0x84, 0x05, "PowerSupply" },
{ 0x84, 0x10, "BatterySystem" },
{ 0x84, 0x11, "BatterySystemID" },
{ 0x84, 0x12, "Battery" },
{ 0x84, 0x13, "BatteryID" },
{ 0x84, 0x14, "Charger" },
{ 0x84, 0x15, "ChargerID" },
{ 0x84, 0x16, "PowerConverter" },
{ 0x84, 0x17, "PowerConverterID" },
{ 0x84, 0x18, "OutletSystem" },
{ 0x84, 0x19, "OutletSystemID" },
{ 0x84, 0x1a, "Input" },
{ 0x84, 0x1b, "InputID" },
{ 0x84, 0x1c, "Output" },
{ 0x84, 0x1d, "OutputID" },
{ 0x84, 0x1e, "Flow" },
{ 0x84, 0x1f, "FlowID" },
{ 0x84, 0x20, "Outlet" },
{ 0x84, 0x21, "OutletID" },
{ 0x84, 0x22, "Gang" },
{ 0x84, 0x24, "PowerSummary" },
{ 0x84, 0x25, "PowerSummaryID" },
{ 0x84, 0x30, "Voltage" },
{ 0x84, 0x31, "Current" },
{ 0x84, 0x32, "Frequency" },
{ 0x84, 0x33, "ApparentPower" },
{ 0x84, 0x35, "PercentLoad" },
{ 0x84, 0x40, "ConfigVoltage" },
{ 0x84, 0x41, "ConfigCurrent" },
{ 0x84, 0x43, "ConfigApparentPower" },
{ 0x84, 0x53, "LowVoltageTransfer" },
{ 0x84, 0x54, "HighVoltageTransfer" },
{ 0x84, 0x56, "DelayBeforeStartup" },
{ 0x84, 0x57, "DelayBeforeShutdown" },
{ 0x84, 0x58, "Test" },
{ 0x84, 0x5a, "AudibleAlarmControl" },
{ 0x84, 0x60, "Present" },
{ 0x84, 0x61, "Good" },
{ 0x84, 0x62, "InternalFailure" },
{ 0x84, 0x65, "Overload" },
{ 0x84, 0x66, "OverCharged" },
{ 0x84, 0x67, "OverTemperature" },
{ 0x84, 0x68, "ShutdownRequested" },
{ 0x84, 0x69, "ShutdownImminent" },
{ 0x84, 0x6b, "SwitchOn/Off" },
{ 0x84, 0x6c, "Switchable" },
{ 0x84, 0x6d, "Used" },
{ 0x84, 0x6e, "Boost" },
{ 0x84, 0x73, "CommunicationLost" },
{ 0x84, 0xfd, "iManufacturer" },
{ 0x84, 0xfe, "iProduct" },
{ 0x84, 0xff, "iSerialNumber" },
{ 0x85, 0, "Battery System" },
{ 0x85, 0x01, "SMBBatteryMode" },
{ 0x85, 0x02, "SMBBatteryStatus" },
{ 0x85, 0x03, "SMBAlarmWarning" },
{ 0x85, 0x04, "SMBChargerMode" },
{ 0x85, 0x05, "SMBChargerStatus" },
{ 0x85, 0x06, "SMBChargerSpecInfo" },
{ 0x85, 0x07, "SMBSelectorState" },
{ 0x85, 0x08, "SMBSelectorPresets" },
{ 0x85, 0x09, "SMBSelectorInfo" },
{ 0x85, 0x29, "RemainingCapacityLimit" },
{ 0x85, 0x2c, "CapacityMode" },
{ 0x85, 0x42, "BelowRemainingCapacityLimit" },
{ 0x85, 0x44, "Charging" },
{ 0x85, 0x45, "Discharging" },
{ 0x85, 0x4b, "NeedReplacement" },
{ 0x85, 0x66, "RemainingCapacity" },
{ 0x85, 0x68, "RunTimeToEmpty" },
{ 0x85, 0x6a, "AverageTimeToFull" },
{ 0x85, 0x83, "DesignCapacity" },
{ 0x85, 0x85, "ManufacturerDate" },
{ 0x85, 0x89, "iDeviceChemistry" },
{ 0x85, 0x8b, "Rechargable" },
{ 0x85, 0x8f, "iOEMInformation" },
{ 0x85, 0x8d, "CapacityGranularity1" },
{ 0x85, 0xd0, "ACPresent" },
/* pages 0xff00 to 0xffff are vendor-specific */
{ 0xffff, 0, "Vendor-specific-FF" },
{ 0, 0, NULL }
};
static void resolv_usage_page(unsigned page) {
struct hid_usage_entry *p;
const struct hid_usage_entry *p;
for (p = hid_usage_table; p->description; p++)
if (p->page == page) {
......@@ -233,13 +317,13 @@ static void resolv_usage_page(unsigned page) {
}
static void resolv_usage(unsigned usage) {
struct hid_usage_entry *p;
const struct hid_usage_entry *p;
resolv_usage_page(usage >> 16);
printk(".");
for (p = hid_usage_table; p->description; p++)
if (p->page == (usage >> 16)) {
for(++p; p->description && p->page == 0; p++)
for(++p; p->description && p->page != 0; p++)
if (p->usage == (usage & 0xffff)) {
printk("%s", p->description);
return;
......
......@@ -306,7 +306,7 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3
#define HID_BUFFER_SIZE 32
#define HID_CONTROL_FIFO_SIZE 64
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
#define HID_OUTPUT_FIFO_SIZE 64
struct hid_control_fifo {
......
......@@ -652,6 +652,15 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return copy_to_user((char *) arg, hid->name, len) ?
-EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
int len;
if (!hid->phys) return 0;
len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, hid->phys, len) ?
-EFAULT : len;
}
}
return -EINVAL;
}
......
......@@ -1214,7 +1214,6 @@ static struct video_device vicam_template = {
.type = VID_TYPE_CAPTURE,
.hardware = VID_HARDWARE_VICAM,
.fops = &vicam_fops,
// .initialize = vicam_video_init,
.minor = -1,
};
......
......@@ -550,6 +550,74 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/*-------------------------------------------------------------------------*/
static void unlink1_callback (struct urb *urb)
{
int status = urb->status;
// we "know" -EPIPE (stall) never happens
if (!status)
status = usb_submit_urb (urb, SLAB_ATOMIC);
if (status) {
if (status == -ECONNRESET || status == -ENOENT)
status = 0;
urb->status = status;
complete ((struct completion *) urb->context);
}
}
static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
{
struct urb *urb;
struct completion completion;
int retval = 0;
init_completion (&completion);
urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
if (async)
urb->transfer_flags |= URB_ASYNC_UNLINK;
urb->context = &completion;
urb->complete = unlink1_callback;
/* keep the endpoint busy. there are lots of hc/hcd-internal
* states, and testing should get to all of them over time.
*
* FIXME want additional tests for when endpoint is STALLing
* due to errors, or is just NAKing requests.
*/
if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) {
dbg ("submit/unlink fail %d", retval);
return retval;
}
/* unlinking that should always work. variable delay tests more
* hcd states and code paths, even with little other system load.
*/
wait_ms (jiffies % (2 * INTERRUPT_RATE));
retval = usb_unlink_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
dbg ("submit/unlink fail %d", retval);
return retval;
}
wait_for_completion (&completion);
retval = urb->status;
simple_free_urb (urb);
return retval;
}
static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
{
int retval = 0;
/* test sync and async paths */
retval = unlink1 (dev, pipe, len, 1);
if (!retval)
retval = unlink1 (dev, pipe, len, 0);
return retval;
}
/*-------------------------------------------------------------------------*/
/* We only have this one interface to user space, through usbfs.
* User mode code can scan usbfs to find N different devices (maybe on
* different busses) to use when testing, and allocate one thread per
......@@ -560,7 +628,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* video capture, and so on. Run different tests at different times, in
* different sequences. Nothing here should interact with other devices,
* except indirectly by consuming USB bandwidth and CPU resources for test
* threads and request completion.
* threads and request completion. But the only way to know that for sure
* is to test when HC queues are in use by many devices.
*/
static int
......@@ -761,13 +830,35 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
dbg ("ch9 subset failed, iterations left %d", i);
break;
/* test cases for the unlink/cancel codepaths need a thread to
* usb_unlink_urb() or usg_sg_cancel(), and a way to check if
* the urb/sg_request was properly canceled.
*
* for the unlink-queued cases, the usb_sg_*() code uses/tests
* the "streamed" cleanup mode, not the "packet" one
*/
// case 10: queued control
/* simple non-queued unlinks (ring with one urb) */
case 11:
if (dev->in_pipe == 0 || !param->length)
break;
retval = 0;
dbg ("%s TEST 11: unlink %d reads of %d",
dev->id, param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe, param->length);
if (retval)
dbg ("unlink reads failed, iterations left %d", i);
break;
case 12:
if (dev->out_pipe == 0 || !param->length)
break;
retval = 0;
dbg ("%s TEST 12: unlink %d writes of %d",
dev->id, param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe, param->length);
if (retval)
dbg ("unlink writes failed, iterations left %d", i);
break;
// FIXME unlink from queue (ring with N urbs)
// FIXME scatterlist cancel (needs helper thread)
}
do_gettimeofday (&param->duration);
......
......@@ -124,20 +124,23 @@ config USB_RTL8150
module, say M here and read <file:Documentation/modules.txt>.
config USB_USBNET
tristate "USB-to-USB Networking cable device support"
tristate "USB-to-USB Networking for cables, PDAs and other devices"
depends on USB && NET
---help---
This driver supports network links over USB with USB "Network"
or "data transfer" cables, often used to network laptops to PCs.
Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
(GeneLink), NetChip and Prolific. Intelligent USB devices could also
use this approach to provide Internet access, using standard USB
cabling. You can find these chips also on some motherboards with
USB PC2PC support.
(GeneLink), NetChip and Prolific. Some motherboards with USB PC2PC
support include such chips.
Intelligent USB devices, such as PDAs running Linux (like Yopy
and Zaurus, or iPaqs after upgrading to Linux) can use the same
approach to provide Internet access.
These links will have names like "usb0", "usb1", etc. They act
like two-node Ethernets, so you can use 802.1d Ethernet Bridging
(CONFIG_BRIDGE) to simplify your network routing.
(CONFIG_BRIDGE) to simplify your network routing. For more
information see <http://www.linux-usb.org/usbnet/>.
This code is also available as a kernel module (code which can be
inserted in and removed from the running kernel whenever you want).
......
......@@ -128,15 +128,8 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
result = usb_stor_bulk_msg (us, fxfr, opipe,
FCM_PACKET_LENGTH, &partial);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
US_DEBUGP ("Freecom readdata xport failure: r=%d, p=%d\n",
result, partial);
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_readdata(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
}
US_DEBUGP("Done issuing read request: %d %d\n", result, partial);
......@@ -171,15 +164,8 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
result = usb_stor_bulk_msg (us, fxfr, opipe,
FCM_PACKET_LENGTH, &partial);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n",
US_DEBUGP ("Freecom writedata xport failure: r=%d, p=%d\n",
result, partial);
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_writedata(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
}
US_DEBUGP("Done issuing write request: %d %d\n",
......@@ -238,13 +224,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -253,12 +232,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial);
US_DEBUGP("foo Status result %d %d\n", result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
......@@ -293,13 +266,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -308,12 +274,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
FCM_PACKET_LENGTH, &partial);
US_DEBUGP("bar Status result %d %d\n", result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
......@@ -372,10 +332,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
FCM_PACKET_LENGTH, &partial);
US_DEBUG(pdump ((void *) fst, partial));
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
......@@ -401,10 +357,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial);
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
......
......@@ -130,8 +130,6 @@
#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */
#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
#define ISD200_TRANSPORT_ABORTED 3 /* Transport aborted */
#define ISD200_TRANSPORT_SHORT 4 /* Transport short */
/* driver action codes */
#define ACTION_READ_STATUS 0
......@@ -394,138 +392,6 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb)
***********************************************************************/
/**************************************************************************
* ISD200 Bulk Transport
*
* Note: This routine was copied from the usb_stor_Bulk_transport routine
* located in the transport.c source file. The scsi command is limited to
* only 12 bytes while the CDB for the ISD200 must be 16 bytes.
*/
int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
union ata_cdb *AtaCdb, unsigned char AtaCdbLength )
{
struct bulk_cb_wrap bcb;
struct bulk_cs_wrap bcs;
int result;
unsigned int transfer_length;
int dir = srb->sc_data_direction;
srb->sc_data_direction = SCSI_DATA_WRITE;
transfer_length = usb_stor_transfer_length(srb);
srb->sc_data_direction = dir;
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(transfer_length);
bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
if (us->flags & US_FL_SCM_MULT_TARG)
bcb.Lun |= srb->target << 4;
bcb.Length = AtaCdbLength;
/* copy the command payload */
memset(bcb.CDB, 0, sizeof(bcb.CDB));
memcpy(bcb.CDB, AtaCdb, bcb.Length);
/* send it to out endpoint */
US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag,
(bcb.Lun >> 4), (bcb.Lun & 0x0F),
le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD)
return ISD200_TRANSPORT_ERROR;
/* if the command transfered well, then we go to the data stage */
if (transfer_length) {
unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ?
us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length);
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == USB_STOR_XFER_ABORTED)
return ISD200_TRANSPORT_ABORTED;
if (result == USB_STOR_XFER_ERROR)
return ISD200_TRANSPORT_ERROR;
}
/* See flow chart on pg 15 of the Bulk Only Transport spec for
* an explanation of how this code works.
*/
/* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* if the command was aborted, indicate that */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
}
/* if we still have a failure at this point, we're in trouble */
US_DEBUGP("Bulk status result = %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return ISD200_TRANSPORT_ERROR;
/* check bulk status */
US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
le32_to_cpu(bcs.Signature), bcs.Tag,
bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
bcs.Tag != bcb.Tag ||
bcs.Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n");
return ISD200_TRANSPORT_ERROR;
}
/* based on the status code, we report good or bad */
switch (bcs.Status) {
case US_BULK_STAT_OK:
/* command good -- note that we could be short on data */
if (srb->resid > 0)
return ISD200_TRANSPORT_SHORT;
return ISD200_TRANSPORT_GOOD;
case US_BULK_STAT_FAIL:
/* command failed */
return ISD200_TRANSPORT_FAILED;
case US_BULK_STAT_PHASE:
/* phase error */
usb_stor_Bulk_reset(us);
return ISD200_TRANSPORT_ERROR;
}
/* we should never get here, but if we do, we're in trouble */
return ISD200_TRANSPORT_ERROR;
}
/**************************************************************************
* isd200_action
*
......@@ -612,9 +478,11 @@ static int isd200_action( struct us_data *us, int action,
break;
}
status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic));
if (status != ISD200_TRANSPORT_GOOD &&
status != ISD200_TRANSPORT_SHORT) {
memcpy(srb.cmnd, &ata, sizeof(ata.generic));
status = usb_stor_Bulk_transport(&srb, us);
if (status == USB_STOR_TRANSPORT_GOOD)
status = ISD200_GOOD;
else {
US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status);
status = ISD200_ERROR;
/* need to reset device here */
......@@ -669,8 +537,8 @@ void isd200_invoke_transport( struct us_data *us,
/* send the command to the transport layer */
srb->resid = 0;
transferStatus = isd200_Bulk_transport(us, srb, ataCdb,
sizeof(ataCdb->generic));
memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic));
transferStatus = usb_stor_Bulk_transport(srb, us);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
......@@ -683,45 +551,37 @@ void isd200_invoke_transport( struct us_data *us,
switch (transferStatus) {
case ISD200_TRANSPORT_GOOD:
case USB_STOR_TRANSPORT_GOOD:
/* Indicate a good result */
srb->result = GOOD << 1;
break;
case ISD200_TRANSPORT_ABORTED:
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
US_DEBUGP("-- transport indicates command was aborted\n");
srb->result = DID_ABORT << 16;
break;
case ISD200_TRANSPORT_FAILED:
case USB_STOR_TRANSPORT_FAILED:
US_DEBUGP("-- transport indicates command failure\n");
need_auto_sense = 1;
break;
case ISD200_TRANSPORT_ERROR:
US_DEBUGP("-- transport indicates transport failure\n");
case USB_STOR_TRANSPORT_ERROR:
US_DEBUGP("-- transport indicates transport error\n");
srb->result = DID_ERROR << 16;
break;
case ISD200_TRANSPORT_SHORT:
srb->result = GOOD << 1;
if (!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
US_DEBUGP("-- unexpectedly short transfer\n");
need_auto_sense = 1;
}
break;
/* Need reset here */
return;
default:
US_DEBUGP("-- transport indicates unknown failure\n");
US_DEBUGP("-- transport indicates unknown error\n");
srb->result = DID_ERROR << 16;
/* Need reset here */
return;
}
if ((srb->resid > 0) &&
!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
US_DEBUGP("-- unexpectedly short transfer\n");
need_auto_sense = 1;
}
if (need_auto_sense) {
......@@ -729,14 +589,23 @@ void isd200_invoke_transport( struct us_data *us,
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- auto-sense aborted\n");
srb->result = DID_ABORT << 16;
} else if (result == ISD200_GOOD)
return;
}
if (result == ISD200_GOOD) {
isd200_build_sense(us, srb);
srb->result = CHECK_CONDITION << 1;
/* If things are really okay, then let's show that */
if ((srb->sense_buffer[2] & 0xf) == 0x0)
srb->result = GOOD << 1;
} else
srb->result = DID_ERROR << 16;
}
/* Regardless of auto-sense, if we _know_ we have an error
* condition, show that in the result code
*/
if (transferStatus == ISD200_TRANSPORT_FAILED)
if (transferStatus == USB_STOR_TRANSPORT_FAILED)
srb->result = CHECK_CONDITION << 1;
}
......
/*
* Common routines for a handful of drivers.
* Unrelated to CF/SM - just USB stuff.
*
* This is mostly a thin layer on top of transport.c.
* It converts routines that return values like -EPIPE
* into routines that return USB_STOR_TRANSPORT_ABORTED etc.
*
* There is also some debug printing here.
* Unrelated to CF/SM - just scatter-gather stuff.
*/
#include "debug.h"
#include "transport.h"
#include "usb.h"
#include "raw_bulk.h"
/*
......
......@@ -103,7 +103,7 @@ static int detect(struct SHT *sht)
*
* NOTE: There is no contention here, because we're already deregistered
* the driver and we're doing each virtual host in turn, not in parallel
* Synchronization: BLK, no spinlock.
* Synchronization: BKL, no spinlock.
*/
static int release(struct Scsi_Host *psh)
{
......
......@@ -562,12 +562,6 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
value, index, data, size);
US_DEBUGP("usb_stor_control_msg returned %d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- transfer aborted\n");
return USB_STOR_XFER_ABORTED;
}
/* a stall indicates a protocol error */
if (result == -EPIPE) {
US_DEBUGP("-- stall on control pipe\n");
......@@ -624,12 +618,6 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_STALLED;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- transfer aborted\n");
return USB_STOR_XFER_ABORTED;
}
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
......@@ -669,7 +657,7 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* initialize the scatter-gather request block */
US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %d bytes, "
"%d entires\n", length, num_sg);
"%d entries\n", length, num_sg);
result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, SLAB_NOIO);
if (result) {
......@@ -691,26 +679,27 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
}
}
/* wait for the completion of the transfer */
usb_sg_wait(us->current_sg);
clear_bit(US_FLIDX_CANCEL_SG, &us->flags);
result = us->current_sg->status;
partial = us->current_sg->bytes;
US_DEBUGP("usb_sg_wait() returned %d xferrerd %d/%d\n",
US_DEBUGP("usb_sg_wait() returned %d xferred %d/%d\n",
result, partial, length);
if (act_len)
*act_len = partial;
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x,"
US_DEBUGP("clearing endpoint halt for pipe 0x%x, "
"stalled at %d bytes\n", pipe, partial);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* NAK - that means we've tried this a few times already */
/* NAK - that means we've retried this a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
......@@ -738,10 +727,10 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
* Nore that this uses the usb_stor_bulk_transfer_buf() and
* Nore that this uses usb_stor_bulk_transfer_buf() and
* usb_stor_bulk_transfer_sglist() to achieve its goals --
* this function simply determines whether we're going to use
* scatter-gather or not, and acts apropriately.
* scatter-gather or not, and acts appropriately.
*/
int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
char *buf, unsigned int length_left, int use_sg, int *residual)
......@@ -1116,15 +1105,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) {
/* Reset flag for status notification */
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_control_msg(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) {
/* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -1137,12 +1117,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length);
US_DEBUGP("CBI data stage result is 0x%x\n", result);
/* report any errors */
if (result == USB_STOR_XFER_ABORTED) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == USB_STOR_XFER_ERROR) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_ERROR;
......@@ -1157,7 +1131,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("CBI interrupt aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
return USB_STOR_TRANSPORT_ERROR;
}
US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
......@@ -1222,13 +1196,6 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */
US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) {
/* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR;
......@@ -1242,14 +1209,8 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length);
US_DEBUGP("CB data stage result is 0x%x\n", result);
/* report any errors */
if (result == USB_STOR_XFER_ABORTED) {
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == USB_STOR_XFER_ERROR) {
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
}
}
/* STATUS STAGE */
......@@ -1319,12 +1280,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
......@@ -1336,10 +1291,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length);
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == USB_STOR_XFER_ABORTED)
return USB_STOR_TRANSPORT_ABORTED;
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -1353,12 +1304,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) {
......@@ -1366,12 +1311,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
}
/* if we still have a failure at this point, we're in trouble */
......
......@@ -121,7 +121,6 @@ struct bulk_cs_wrap {
#define USB_STOR_XFER_SHORT 1 /* transfered less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */
#define USB_STOR_XFER_ABORTED 4 /* transfer canceled */
/*
* Transport return codes
......
......@@ -437,41 +437,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = GOOD << 1;
}
/* Most USB devices can't handle START_STOP. But we
* need something for media-change, so we'll use TUR
* instead.
*
* We specifically allow this command through if either:
* (a) it's a load/eject command (cmnd[4] & 2)
* (b) it's a multi-target unit (i.e. legacy SCSI adaptor)
*/
else if (us->srb->cmnd[0] == START_STOP &&
!(us->srb->cmnd[4] & 2) &&
!(us->flags & US_FL_SCM_MULT_TARG)) {
unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
__u8 old_cmd_len;
US_DEBUGP("Converting START_STOP to TUR\n");
/* save old command */
memcpy(saved_cdb, us->srb->cmnd, us->srb->cmd_len);
old_cmd_len = us->srb->cmd_len;
/* set up new command -- preserve LUN */
us->srb->cmd_len = 6;
memset(us->srb->cmnd, 0, us->srb->cmd_len);
us->srb->cmnd[0] = TEST_UNIT_READY;
us->srb->cmnd[1] = saved_cdb[1] & 0xE0;
/* do command */
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us);
/* restore original command */
us->srb->cmd_len = old_cmd_len;
memcpy(us->srb->cmnd, saved_cdb, us->srb->cmd_len);
}
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
......
......@@ -443,19 +443,19 @@ extern void firmware_uregister(struct subsystem *);
#ifdef DEBUG
#define dev_dbg(dev, format, arg...) \
printk (KERN_DEBUG "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg)
(dev).driver->name , (dev).bus_id , ## arg)
#else
#define dev_dbg(dev, format, arg...) do {} while (0)
#endif
#define dev_err(dev, format, arg...) \
printk (KERN_ERR "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg)
(dev).driver->name , (dev).bus_id , ## arg)
#define dev_info(dev, format, arg...) \
printk (KERN_INFO "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg)
(dev).driver->name , (dev).bus_id , ## arg)
#define dev_warn(dev, format, arg...) \
printk (KERN_WARN "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg)
printk (KERN_WARNING "%s %s: " format , \
(dev).driver->name , (dev).bus_id , ## arg)
#endif /* _DEVICE_H_ */
......@@ -159,6 +159,7 @@ struct hiddev_usage_ref {
#define HIDIOCSFLAG _IOW('H', 0x0F, int)
#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref)
#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info)
#define HIDIOCGPHYS(len) _IOC(_IOC_READ, 'H', 0x12, len)
/*
* Flags to be used in HIDIOCSFLAG
......
......@@ -105,7 +105,7 @@ extern const char *print_tainted(void);
extern void dump_stack(void);
#if DEBUG
#ifdef DEBUG
#define pr_debug(fmt,arg...) \
printk(KERN_DEBUG fmt,##arg)
#else
......
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