aiherong
驱动牛犊
驱动牛犊
  • 注册日期2002-06-07
  • 最后登录2007-01-10
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
阅读:3006回复:12

可否直接用汇编进行USB通讯,那位高手能告诉我具体I/O port?

楼主#
更多 发布于:2002-06-22 12:20
可否直接用汇编进行USB通讯,那位高手能告诉我具体I/O port?
oceanlee
驱动牛犊
驱动牛犊
  • 注册日期2001-11-22
  • 最后登录2006-02-05
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-06-22 13:32
个人认为,不能简单的IO读写操作,因为下面有USB桥完成地层的工作
OceanLee
shlei20
驱动牛犊
驱动牛犊
  • 注册日期2002-02-01
  • 最后登录2003-02-08
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-06-22 13:53
需要有驱动程序才行啊! 你指的汇编是用在什么地方,下位机?
spin
驱动小牛
驱动小牛
  • 注册日期2001-04-17
  • 最后登录2015-10-27
  • 粉丝1
  • 关注0
  • 积分46分
  • 威望354点
  • 贡献值0点
  • 好评度41点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-06-22 14:27
看一下usb controller的地址
zhuzc
驱动中牛
驱动中牛
  • 注册日期2001-09-01
  • 最后登录2005-04-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-06-22 17:59
支持spin。

以pc机为例,不同的主板芯片组,usb controller不同。

这要查具体的手册,呵呵。

提示一下:
usb controller挂在PCI总线上,内部设置了fifo;通过一些寄存器;查询方式(假中断);需要实现request链表。
我是树上的那只鸟,整理着自己的羽毛,看着城市的喧嚣……
zhuzc
驱动中牛
驱动中牛
  • 注册日期2001-09-01
  • 最后登录2005-04-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-06-22 18:02
一般都是和intel兼容的.
我是树上的那只鸟,整理着自己的羽毛,看着城市的喧嚣……
kelvin9230
驱动牛犊
驱动牛犊
  • 注册日期2002-03-19
  • 最后登录2003-06-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-06-22 21:42
Sure you can!!! It is not so difficault as someone think.
PC\'s USB host controller is PCI device.
If you want to control USB host controller, you should first find the PCI device. Get the USB host controller\'s base address and IRQ.
First you should be familiar with PCI.
My advice is that:
Get the PCI sepc and read it. Then write some PCI device driver for learning.
Cann\'t you see BIOS that can boot from a USB device. It is written in asm.


[编辑 -  6/22/02 by  kelvin9230]
zhuzc
驱动中牛
驱动中牛
  • 注册日期2001-09-01
  • 最后登录2005-04-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-06-23 14:32
可以参考linux下的实现

《linux内核源代码情景分析》
我是树上的那只鸟,整理着自己的羽毛,看着城市的喧嚣……
raymondarc
驱动牛犊
驱动牛犊
  • 注册日期2002-06-19
  • 最后登录2002-06-29
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-06-23 20:42
我在用C52芯片汇编写下位机,现正被那些描述符搞混了,C 的
资料好找,汇编的如何配置,如何与PC连机?
快告诉我好吗?
E_MAIL:raymondarc@21cn.com
kermit_shie
驱动牛犊
驱动牛犊
  • 注册日期2002-04-24
  • 最后登录2007-06-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-07-02 13:42
别做梦了,用IO端口访问USB Device是不可能的。不过对于特定的USB Host芯片,IC设计人员为了Debug的需要,会设置一些寄存器,通过往里面写,就可以把数据发出去。而且还不能读。当然,这些寄存器对一般用户来说是没有任何作用的。你如果想了解多一点,那去看OHCL,UHCL吧。不过在DOS底下访问USB还是有办法的,以后再慢慢告诉你。


----------
请多支持国产IC业

zhuzc
驱动中牛
驱动中牛
  • 注册日期2001-09-01
  • 最后登录2005-04-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-07-02 14:13
不同意楼上的!!!

我已经用c做过了直接访问usb host controller的程序!

详细说明见上
我是树上的那只鸟,整理着自己的羽毛,看着城市的喧嚣……
kelvin9230
驱动牛犊
驱动牛犊
  • 注册日期2002-03-19
  • 最后登录2003-06-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-07-02 14:13
Part of UHCI driver for DOS. Modified from Linux source code.


#include <stdio.h>
#include <mem.h>
#include <string.h>
#include <dos.h>
#include <alloc.h>
#include <stdlib.h>

#include \"uhci.h\"
#include \"utils.h\"
#include \"port.h\"
#include \"scsi.h\"

extern unsigned long interrupt_count;
extern unsigned long interrupt_status;

unsigned short interrupt_array[256];


unsigned long tmpbuf1[UHCI_NUMFRAMES * 2];
unsigned long *frame;

unsigned long in_toggle = 1;
unsigned long out_toggle = 1;

int irq;
unsigned int io_addr;

struct uhci_td skeltd_pool[UHCI_NUM_SKELTD * 2];
struct uhci_qh skelqh_pool[UHCI_NUM_SKELQH * 2];
struct uhci_td *skeltd;
struct uhci_qh *skelqh;

unsigned char td_bitmap[UHCI_NUM_TD/8];
unsigned char qh_bitmap[UHCI_NUM_QH/8];
struct uhci_td td_pool[UHCI_NUM_TD * 2];
struct uhci_td *tdpoolp;
struct uhci_qh qh_pool[UHCI_NUM_QH * 2];
struct uhci_qh *qhpoolp;

struct us_data us_data;
struct scsi_cmnd cmnd;

void uhci_fill_td(struct uhci_td *td, unsigned long status, unsigned long info, unsigned long buffer)
{
td->status = status;
td->info = info;
td->buffer = buffer;
}

void init_uhci(void)
{
int i;
skeltd = (struct uhci_td *)align_to((void far *)skeltd_pool, 16);
skelqh = (struct uhci_qh *)align_to((void far *)skelqh_pool, 16);
tdpoolp = (struct uhci_td *)align_to((void far *)td_pool, 16);
qhpoolp = (struct uhci_qh *)align_to((void far *)qh_pool, 16);
frame = (unsigned long *)align_to((void far *)tmpbuf1, 4096);

memset(frame, 0, sizeof(tmpbuf1[UHCI_NUMFRAMES]));
memset(skeltd, 0, sizeof(skeltd_pool[UHCI_NUM_SKELTD]));
memset(skelqh, 0, sizeof(skelqh_pool[UHCI_NUM_SKELQH]));
memset(tdpoolp, 0, sizeof(td_pool[UHCI_NUM_TD]));
memset(qhpoolp, 0, sizeof(qh_pool[UHCI_NUM_QH]));

for(i = 1; i < 9; i ++)
{
struct uhci_td *td = &skeltd;
uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7F << 8) | USB_PID_IN, 0);
td->link = segoff_to_linear((void far *)&skeltd[i-1]);
}
uhci_fill_td(&skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7F << 8) | USB_PID_IN, 0);
skel_int1_td.link = segoff_to_linear((void far *)&skel_ls_control_qh) | UHCI_PTR_QH;

skel_ls_control_qh.link = segoff_to_linear((void far *)&skel_hs_control_qh) | UHCI_PTR_QH;
skel_ls_control_qh.element =  UHCI_PTR_TERM;

skel_hs_control_qh.link = segoff_to_linear((void far *)&skel_bulk_qh) | UHCI_PTR_QH;
skel_hs_control_qh.element =  UHCI_PTR_TERM;

skel_bulk_qh.link = segoff_to_linear((void far *)&skel_term_qh) | UHCI_PTR_QH;
skel_bulk_qh.element =  UHCI_PTR_TERM;

uhci_fill_td(&skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7F << 8) | USB_PID_IN, 0);
skel_term_td.link = UHCI_PTR_TERM;

skel_term_qh.link = UHCI_PTR_TERM;
// skel_term_qh.element =  segoff_to_linear((void far *)&skel_term_td) ;
skel_term_qh.element =  UHCI_PTR_TERM;

for (i = 0; i < UHCI_NUMFRAMES; i++)
{
struct uhci_td *irqno = &skel_int1_td;
if (i & 1)
{
irqno++;
if (i & 2)
{
irqno++;
if (i & 4)
{
irqno++;
if (i & 8)
{
irqno++;
if (i & 16)
{
irqno++;
if (i & 32)
{
irqno++;
if (i & 64)
irqno++;
}
}
}
}
}
}

frame =  segoff_to_linear((void far *)irqno) ;
}
}


void reset_hc(void)
{
outport(io_addr + USBCMD, USBCMD_GRESET);
wait(50);
// sleep(1);
outport(io_addr + USBCMD, 0);
wait(10);
// sleep(1);
}

void start_hc(void)
{
int timeout = 1000;
/*
* Reset the HC - this will force us to get a
* new notification of any already connected
* ports due to the virtual disconnect that it
* implies.
*/
outport(io_addr + USBCMD, USBCMD_HCRESET);
while (inport(io_addr + USBCMD) & USBCMD_HCRESET)
{
if (!--timeout)
{
printf(\"uhci: USBCMD_HCRESET timed out!\\n\");
break;
}
}
/* Turn on all interrupts */
outport(io_addr + USBINTR, USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);

/* Start at frame 0 */
outport(io_addr + USBFRNUM, 0);
outpd((unsigned short)(io_addr + USBFLBASEADD), segoff_to_linear((void far *)frame));

/* Run and mark it configured with a 64-byte max packet */
outport(io_addr + USBCMD, USBCMD_RS | USBCMD_CF | USBCMD_MAXP);

}
/*
void irq_redirect(void)
{
        unsigned char tmp;
        int i;
        disable();
        tmp = inportb(0xa1);
        outportb(0xa0, 0x11);
        outportb(0xa1, 0x70);
        outportb(0xa1, 0x02);
        outportb(0xa1, 0x01);
        outportb(0xa1, tmp);
        enable();
}
*/
void interrupt(far *old_vect)();

/*a shared IRQ11*/
void interrupt uhci_interrupt(void)
{
unsigned short status;
status = inport(io_addr + USBSTS);
wait(1);
        if (status & (USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD | USBSTS_HSE
                        | USBSTS_HCPE | USBSTS_HCH))
{
//                interrupt_array[interrupt_count] = status;
                interrupt_status = status;
interrupt_count ++;

/* printf(\"in uhci interrupt\\n\");
if (status & USBSTS_RD)
printf(\"uhci: host system error, PCI problems?\\n\");
if (status & USBSTS_HSE)
printf(\"uhci: host system error, PCI problems?\\n\");
if (status & USBSTS_HCPE)
printf(\"uhci: host controller process error. something bad happened\\n\");
if (status & USBSTS_HCH)
printf(\"uhci: host controller halted. very bad\\n\");
*/ }
outport(io_addr + USBSTS, status);
wait(1);
outportb(0x20, 0x20);
wait(1);
outportb(0xa0, 0x20);
wait(1);
}

void replace_vect(int irqno)
{
disable();
if(irqno <= 7)
{
old_vect = getvect(8 + irqno);
setvect(8 + irqno, uhci_interrupt);
}
else if(irqno <= 15)
{
old_vect = getvect(0x70 + (irqno - 8));
setvect(0x70 + (irqno - 8), uhci_interrupt);
}
else
;
enable();
return;
}

void restore_vect(int irqno)
{
disable();
if(irqno <= 7)
setvect(8 + irqno, old_vect);
else if(irqno <= 15)
setvect(0x70 + (irqno - 8), old_vect);
else
;
enable();
return;
}

void enable_irq(int irqno)
{
        unsigned char tmp;
disable();
        tmp = (unsigned char)inportb(0x21);
        wait(1);
        outportb(0x21, tmp & 0xFB);
wait(1);
        tmp = (unsigned char)inportb(0xA1);
        outportb(0xA1, tmp &  ~(1 << ((unsigned char)irqno - 8)));
wait(1);
  enable();
}

int alloc_qh(struct uhci_qh **pp)
{
int i, j;
for(i = 0; i < UHCI_NUM_QH; i++)
{
if((qh_bitmap[i/8] & (0x01 << (i%8))) == 0)
{
*pp = &qhpoolp;
qh_bitmap[i/8] |= (0x01 << (i%8));
return 0;
}
}
*pp = 0;
return 1;
}

int alloc_td(struct uhci_td **pp)
{
int i, j;
for(i = 0; i < UHCI_NUM_TD; i++)
{
if((td_bitmap[i/8] & (0x01 << (i%8))) == 0)
{
*pp = &tdpoolp;
td_bitmap[i/8] |= (0x01 << (i%8));
return 0;
}
}
*pp = 0;
return 1;
}

int insert_td(struct uhci_qh *qh, struct uhci_td *td, unsigned char term)
{
if((qh->element & 0xFFFFFFF0) == 0)
{
qh->element = segoff_to_linear((void far *)td);
if(term)
td->link |= 1;
}
else
{
struct uhci_td *p;
p = (struct uhci_td *)linear_to_off(qh->element & 0xFFFFFFF0);
while(p->link & 0xFFFFFFF0)
p = (struct uhci_td *)linear_to_off(p->link & 0xFFFFFFF0);
p->link = segoff_to_linear((void far *)td);
if(term)
td->link |= 1;
}
return 0;
}

int insert_qh(struct uhci_qh *chain, struct uhci_qh *qh)
{
unsigned long next;
next = chain->link;
qh->link = next;
chain->link = segoff_to_linear((void far *)qh) | 2;
// chain->link = segoff_to_linear((void far *)qh);
return 0;
}



/**
 * usb_alloc_urb - creates a new urb for a USB driver to use
 * @iso_packets: number of iso packets for this urb
 *
 * Creates an urb for the USB driver to use and returns a pointer to it.
 * If no memory is available, NULL is returned.
 *
 * If the driver want to use this urb for interrupt, control, or bulk
 * endpoints, pass \'0\' as the number of iso packets.
 *
 * The driver should call usb_free_urb() when it is finished with the urb.
 */
struct urb *usb_alloc_urb(int iso_packets)
{
struct urb *urb;

urb = (struct urb *)malloc(sizeof(struct urb) + iso_packets * sizeof(struct iso_packet_descriptor));
if (!urb) {
printf(\"malloc failed\\n\");
return 0;
}
memset(urb, 0, sizeof(*urb));
return urb;
}

/**
 * usb_free_urb - frees the memory used by a urb
 * @urb: pointer to the urb to free
 *
 * If an urb is created with a call to usb_create_urb() it should be
 * cleaned up with a call to usb_free_urb() when the driver is finished
 * with it.
 */
void usb_free_urb(struct urb *urb)
{
if (urb)
free(urb);
}

int uhci_unlink_urb (struct urb *urb)
{
/* uhci_t *s;
unsigned long flags=0;
dbg(\"uhci_unlink_urb called for %p\",urb);
if (!urb || !urb->dev) // you never know...
return -EINVAL;

s = (uhci_t*) urb->dev->bus->hcpriv;

if (usb_pipedevice (urb->pipe) == s->rh.devnum)
return rh_unlink_urb (urb);

if (!urb->hcpriv)
return -EINVAL;

if (urb->transfer_flags & USB_ASYNC_UNLINK) {
int ret;

       spin_lock_irqsave (&s->urb_list_lock, flags);

// The URB needs to be locked if called outside completion context

if (!in_interrupt())
spin_lock(&urb->lock);

uhci_release_bandwidth(urb);
ret = uhci_unlink_urb_async(s, urb);

if (!in_interrupt())
spin_unlock(&urb->lock);

spin_unlock_irqrestore (&s->urb_list_lock, flags);

return ret;
}
else
return uhci_unlink_urb_sync(s, urb);*/
return 0;
}


int uhci_submit_control_urb(struct urb *urb)
{
struct uhci_qh *qh;
struct uhci_td *td;
struct device_request *dr;
unsigned long status;
unsigned long info;
unsigned long len;
char * data;
unsigned long maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
        maxsze = 8;
alloc_qh(&qh);
alloc_td(&td);
// status = TD_CTRL_IOC | TD_CTRL_ACTIVE | (3L << 27);
status = TD_CTRL_ACTIVE | (3L << 27);
//        info = 0x00000000L | USB_PID_SETUP;
        info = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;

uhci_fill_td(td, status, info | (7L << 21), segoff_to_linear((void far *)(urb->setup_packet)));
insert_td(qh, td, 0);

len = urb->transfer_buffer_length;
data = urb->transfer_buffer;
info = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);

while (len > 0) {
int pktsze = len;

alloc_td (&td);
              if (pktsze > maxsze)
                        pktsze = maxsze;

                info ^= (1L << TD_TOKEN_TOGGLE);   // toggle DATA0/1

// Status, pktsze bytes of data
                uhci_fill_td (td, status, info | ((unsigned long)(pktsze - 1) << 21), segoff_to_linear((void far *)data));

insert_td (qh, td, 0); // queue \'data stage\'-td in qh

data += pktsze;
len -= pktsze;
}

info &= ~UHCI_PID;

if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
info |= USB_PID_IN;
else
info |= USB_PID_OUT;

        info |= (1L << TD_TOKEN_TOGGLE);   /* End in Data1 */

alloc_td(&td);
uhci_fill_td(td, status |TD_CTRL_IOC, info | (UHCI_NULL_DATA_SIZE << 21), (unsigned long)0);
insert_td(qh, td, 1);
insert_qh (&skel_hs_control_qh, qh);
return 0;
}

int uhci_submit_bulk_urb (struct urb *urb)
{
struct uhci_qh *qh = 0;
struct uhci_td *td = 0;
struct device_request *dr;
unsigned long status;
unsigned long info;
unsigned long len;
char * data;
unsigned long maxsze;
unsigned long tmplong;
        unsigned long tmplong2;
struct usb_device *tmpdev;
tmpdev = (struct usb_device *)(urb->dev);
        tmpdev->epmaxpacketin[1] = 0x40;
tmpdev->epmaxpacketout[2] = 0x40;
tmplong = usb_pipeout (urb->pipe);
        tmplong2 = tmplong;
        if(tmplong2)
{
maxsze = urb->dev->epmaxpacketout[usb_pipeendpoint(urb->pipe)];
}
else
       {

                tmplong = usb_pipeendpoint(urb->pipe);
                maxsze = urb->dev->epmaxpacketin[usb_pipeendpoint(urb->pipe)];
       }
// maxsze = usb_maxpacket (urb->dev, urb->pipe, tmplong);
alloc_qh(&qh);
alloc_td(&td);
// status = TD_CTRL_IOC | TD_CTRL_ACTIVE | (3L << 27);
status = TD_CTRL_ACTIVE | (3L << 27);
len = urb->transfer_buffer_length;
data = urb->transfer_buffer;
info = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
while (len > 0) {
int pktsze = len;

alloc_td (&td);
              if (pktsze > maxsze)
                        pktsze = maxsze;

// Status, pktsze bytes of data
                if(tmplong2)
{
out_toggle ^= 1;
info = (info & (~(1L << TD_TOKEN_TOGGLE))) | (out_toggle << TD_TOKEN_TOGGLE);
}
else
{
               in_toggle ^= 1;
info = (info & (~(1L << TD_TOKEN_TOGGLE))) | (in_toggle << TD_TOKEN_TOGGLE);
}
uhci_fill_td (td, status, info | ((unsigned long)(pktsze - 1) << 21), segoff_to_linear((void far *)data));
/* if(tmplong)
info = (info & (~(1L << TD_TOKEN_TOGGLE))) | (out_toggle << TD_TOKEN_TOGGLE);
else
info = (info & (~(1L << TD_TOKEN_TOGGLE))) | (in_toggle << TD_TOKEN_TOGGLE);*/
              //  info ^= (1L << TD_TOKEN_TOGGLE);   // toggle DATA0/1
insert_td (qh, td, 0); // queue \'data stage\'-td in qh

data += pktsze;
len -= pktsze;
}
td->link |= 1;
insert_qh (&skel_hs_control_qh, qh);
return 0;
}

void insert_int_td(struct uhci_td *chain, struct uhci_td *td)
{

unsigned long next;
next = chain->link;
td->link = next;
chain->link = segoff_to_linear((void far *)td);
return 0;
}



/*-------------------------------------------------------------------*/
// submits USB interrupt (ie. polling ;-)
// ASAP-flag set implicitely
// if period==0, the transfer is only done once

int uhci_submit_int_urb (void)
{
struct uhci_qh *qh;
struct uhci_td *td;
struct device_request *dr;
unsigned long status;
unsigned long info = 0;
unsigned long len;
char * data;
unsigned long maxsze;
        maxsze = 8;
alloc_td(&td);

status = TD_CTRL_ACTIVE | TD_CTRL_IOC | (3L << 27);
info = (0xb1L << 8) | 0x69 | (7L << 21);

uhci_fill_td(td, status, info, 0);
insert_int_td(&skel_int2_td, td);
return 0;

}
/*-------------------------------------------------------------------*/
int uhci_submit_iso_urb (struct urb *urb)
{
return 0;
}

int uhci_submit_urb(struct urb *urb)
{

if(usb_pipetype (urb->pipe) == PIPE_BULK)
{
uhci_submit_bulk_urb (urb);
}
else
{
switch (usb_pipetype (urb->pipe))
{
case PIPE_ISOCHRONOUS:
if (urb->bandwidth == 0)
uhci_submit_iso_urb(urb);
break;
case PIPE_INTERRUPT:
uhci_submit_int_urb();
break;
case PIPE_CONTROL:
uhci_submit_control_urb (urb);
break;
}
}
return 0;
}





// Starts urb and waits for completion or timeout
int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
int status;
 
status = uhci_submit_urb(urb);
/* if (status) {
// something went wrong
usb_free_urb(urb);
return status;
}

if (!status) {
// timeout
printf(\"usb_control/bulk_msg: timeout\\n\");
uhci_unlink_urb(urb);  // remove urb safely
status = 1;
} else
status = urb->status;

if (actual_length)
*actual_length = urb->actual_length;
*/
usb_free_urb(urb);
   return status;
}

/**
 * uhci_control_msg - Builds a control urb, sends it off and waits for completion
 * @dev: pointer to the usb device to send the message to
 * @pipe: endpoint \"pipe\" to send the message to
 * @request: USB message request value
 * @requesttype: USB message request type value
 * @value: USB message value
 * @index: USB message index value
 * @data: pointer to the data to send
 * @size: length in bytes of the data to send
 * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
 *
 * This function sends a simple control message to a specified endpoint
 * and waits for the message to complete, or timeout.
 *
 * If successful, it returns 0, othwise a negative error number.
 *
 * Don\'t use this function from within an interrupt context, like a
 * bottom half handler.  If you need a asyncronous message, or need to send
 * a message from within interrupt context, use usb_submit_urb()
 */
int uhci_control_msg(struct usb_device *dev, unsigned long pipe, unsigned char request, unsigned char requesttype,
unsigned short value, unsigned short index, void *data, unsigned short size, long timeout)
{

struct urb *urb;
struct device_request *dr;
int ret;
int length;
dr = (struct device_request *)malloc(sizeof(struct device_request));

if (!dr)
return 1;

dr->requesttype = requesttype;
dr->request = request;
dr->value = value;
dr->index = index;
dr->length = size;


urb = usb_alloc_urb(0);
if (!urb)
{
printf(\"Out of memory\\n\");
return 1;
}

FILL_CONTROL_URB(urb, dev, pipe, (unsigned char*)dr, data, size);   /* build urb */

ret = usb_start_wait_urb(urb, timeout, &length);
free(dr);
if (ret < 0)
return ret;
else
return length;
}

/**
 * uhci_bulk_msg - Builds a bulk urb, sends it off and waits for completion
 * @usb_dev: pointer to the usb device to send the message to
 * @pipe: endpoint \"pipe\" to send the message to
 * @data: pointer to the data to send
 * @len: length in bytes of the data to send
 * @actual_length: pointer to a location to put the actual length transfered in bytes
 * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
 *
 * This function sends a simple bulk message to a specified endpoint
 * and waits for the message to complete, or timeout.
 *
 * If successful, it returns 0, othwise a negative error number.
 * The number of actual bytes transferred will be plaed in the
 * actual_timeout paramater.
 *
 * Don\'t use this function from within an interrupt context, like a
 * bottom half handler.  If you need a asyncronous message, or need to
 * send a message from within interrupt context, use usb_submit_urb()
 */
int uhci_bulk_msg(struct usb_device *usb_dev, unsigned long pipe, void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;

if (len < 0)
return -1;

urb=usb_alloc_urb(0);
if (!urb)
return -1;

FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len);

return usb_start_wait_urb(urb,timeout,actual_length);
}

/* This is a version of usb_clear_halt() that doesn\'t read the status from
 * the device -- this is because some devices crash their internal firmware
 * when the status is requested after a halt
 */
int usb_stor_clear_halt(struct usb_device *dev, int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);

result = uhci_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
endp, NULL, 0, HZ * 3);

return 0;
}


int usb_bulk_only_mass_stor_reset(struct us_data *us)
{
uhci_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0, HZ*5);
usb_stor_clear_halt(us->pusb_dev,
   usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
usb_stor_clear_halt(us->pusb_dev,
   usb_sndbulkpipe(us->pusb_dev, us->ep_out));
}

int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
return uhci_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, HZ * GET_TIMEOUT);
}

int usb_set_address(struct usb_device *dev)
{
return uhci_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, 0, dev->devnum, 0, NULL, 0, HZ * GET_TIMEOUT);
}

int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
{

memset(buf,0,size);
return uhci_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + index, langid, buf, size, HZ * GET_TIMEOUT);
}

int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
int i = 5;
int result;

memset(buf,0,size); // Make sure we parse really received data

result = uhci_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(type << 8) + index, 0, buf, size, HZ * GET_TIMEOUT);
return result;
}

int usb_get_device_descriptor(struct usb_device *dev)
{
int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
    sizeof(dev->descriptor));
return ret;
}

int usb_get_configuration(struct usb_device *dev)
{
int result;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
  struct usb_config_descriptor *desc;

if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
printf(\"too many configurations\\n\");
return -1;
}

if (dev->descriptor.bNumConfigurations < 1) {
printf(\"not enough configurations\\n\");
return -1;
}

dev->config = (struct usb_config_descriptor *)
malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
if (!dev->config)
{
printf(\"out of memory\\n\");
return -1;
}
memset(dev->config, 0, dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));

dev->rawdescriptors = (char **)malloc(sizeof(char *) * dev->descriptor.bNumConfigurations);
if (!dev->rawdescriptors)
{
printf(\"out of memory\\n\");
return -1;
}

buffer = malloc(8);
if (!buffer)
{
printf(\"unable to allocate memory for configuration descriptors\");
return -1;
}
desc = (struct usb_config_descriptor *)buffer;

for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++)
{
/* We grab the first 8 bytes so we know how long the whole */
/*  configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
if (result < 8)
{
if (result < 0)
printf(\"unable to get descriptor\\n\");
else
{
printf(\"config descriptor too short (expected %i, got %i)\", 8, result);
result = -1;
}
}

     /* Get the full buffer */
length = desc->wTotalLength;

bigbuffer = malloc(length);
if (!bigbuffer)
{
printf(\"unable to allocate memory for configuration descriptors\\n\");
result = -1;
}

/* Now that we know the length, get the whole thing */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
if (result < 0)
{
printf(\"couldn\'t get all of config descriptors\\n\");
free(bigbuffer);
}

if (result < length)
{
printf(\"config descriptor too short (expected %i, got %i)\\n\", length, result);
result = -1;
free(bigbuffer);
}

dev->rawdescriptors[cfgno] = bigbuffer;
/*
result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
if (result > 0)
dbg(\"descriptor data left\");
else if (result < 0) {
result = -EINVAL;
goto err;*/
}
}

void usb_set_maxpacket(struct usb_device *dev)
{
int i, b;

for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *ifp = dev->actconfig->interface + i;
struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
struct usb_endpoint_descriptor *ep = as->endpoint;
int e;

for (e=0; e<as->bNumEndpoints; e++) {
b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
dev->epmaxpacketout = ep[e].wMaxPacketSize;
dev->epmaxpacketin = ep[e].wMaxPacketSize;
}
else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
if (ep[e].wMaxPacketSize > dev->epmaxpacketout)
dev->epmaxpacketout = ep[e].wMaxPacketSize;
}
else {
if (ep[e].wMaxPacketSize > dev->epmaxpacketin )
dev->epmaxpacketin = ep[e].wMaxPacketSize;
}
}
}
}

int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_config_descriptor *cp = NULL;

for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
if (dev->config.bConfigurationValue == configuration) {
cp = &dev->config;
break;
}
}
if (!cp)
{
printf(\"selecting invalid configuration %d\\n\", configuration);
return -1;
}

if ((ret = uhci_control_msg(dev, usb_sndctrlpipe(dev, 0),
   USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, HZ * SET_TIMEOUT)) < 0)
return ret;

dev->actconfig = cp;
dev->toggle[0] = 0;
dev->toggle[1] = 0;
usb_set_maxpacket(dev);

return 0;
}


int usb_set_configuration_test(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_config_descriptor *cp = NULL;

        for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
if (dev->config.bConfigurationValue == configuration) {
cp = &dev->config;
break;
}
}
if (!cp)
{
printf(\"selecting invalid configuration %d\\n\", configuration);
return -1;
}

uhci_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, HZ * SET_TIMEOUT);
return 0;
}


void clear_status(void)
{
unsigned short status;
status = inport(io_addr + USBSTS);
wait(1);
outport(io_addr + USBSTS, status);
wait(1);
}


/*
 * Transfer one SCSI scatter-gather buffer via bulk transfer
 *
 * Note that this function is necessary because we want the ability to
 * use scatter-gather memory.  Good performance is achieved by a combination
 * of scatter-gather and clustering (which makes each chunk bigger).
 *
 * Note that the lower layer will always retry when a NAK occurs, up to the
 * timeout limit.  Thus we don\'t have to worry about it for individual
 * packets.
 */
int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
{
int result;
int partial;
unsigned long pipe;

/* calculate the appropriate pipe information */
if (us->srb->sc_data_direction == SCSI_DATA_READ)
                pipe = usb_rcvbulkpipe(us->pusb_dev, (unsigned long)(us->ep_in));
else
                pipe = usb_sndbulkpipe(us->pusb_dev, (unsigned long)(us->ep_out));

/* transfer the data */
printf(\"usb_stor_transfer_partial(): xfer %d bytes\\n\", length);
result = uhci_bulk_msg(us->pusb_dev, pipe, buf,  length, &partial,HZ * GET_TIMEOUT);
printf(\"usb_stor_bulk_msg() returned %d xferred %d/%d\\n\",
 result, partial, length);

/* if we stall, we need to clear it before we go on */
/* did we send all the data? */
if (partial == length) {
printf(\"usb_stor_transfer_partial(): transfer complete\\n\");
return US_BULK_TRANSFER_GOOD;
}

/* uh oh... we have an error code, so something went wrong. */
if (result) {
/* the catch-all case */
printf(\"usb_stor_transfer_partial(): unknown error\\n\");
return US_BULK_TRANSFER_FAILED;
}

/* no error code, so we must have transferred some data,
* just not all of it */
return US_BULK_TRANSFER_SHORT;
}


/* Calculate the length of the data transfer (not the command) for any
 * given SCSI command
 */
unsigned int usb_stor_transfer_length(struct scsi_cmnd *srb)
{
       int i;
int doDefault = 0;
unsigned int len = 0;
unsigned int total = 0;
/*struct scatterlist *sg;*/

/* This table tells us:
  X = command not supported
  L = return length in cmnd[4] (8 bits).
  M = return length in cmnd[8] (8 bits).
  G = return length in cmnd[3] and cmnd[4] (16 bits)
  H = return length in cmnd[7] and cmnd[8] (16 bits)
  I = return length in cmnd[8] and cmnd[9] (16 bits)
  C = return length in cmnd[2] to cmnd[5] (32 bits)
  D = return length in cmnd[6] to cmnd[9] (32 bits)
  B = return length in blocksize so we use buff_len
  R = return length in cmnd[2] to cmnd[4] (24 bits)
  S = return length in cmnd[3] to cmnd[5] (24 bits)
  T = return length in cmnd[6] to cmnd[8] (24 bits)
  U = return length in cmnd[7] to cmnd[9] (24 bits)
  0-9 = fixed return length
  V = 20 bytes
  W = 24 bytes
  Z = return length is mode dependant or not in command, use buff_len
*/

static char *lengths =

     /* 0123456789ABCDEF   0123456789ABCDEF */

\"00XLZ6XZBXBBXXXB\" \"00LBBLG0R0L0GG0X\"  /* 00-1F */
\"XXXXT8XXB4B0BBBB\" \"ZZZ0B00HCSSZTBHH\"  /* 20-3F */
\"M0HHB0X000H0HH0X\" \"XHH0HHXX0TH0H0XX\"  /* 40-5F */
\"XXXXXXXXXXXXXXXX\" \"XXXXXXXXXXXXXXXX\"  /* 60-7F */
\"XXXXXXXXXXXXXXXX\" \"XXXXXXXXXXXXXXXX\"  /* 80-9F */
\"X0XXX00XB0BXBXBB\" \"ZZZ0XUIDU000XHBX\"  /* A0-BF */
\"XXXXXXXXXXXXXXXX\" \"XXXXXXXXXXXXXXXX\"  /* C0-DF */
\"XDXXXXXXXXXXXXXX\" \"XXW00HXXXXXXXXXX\"; /* E0-FF */

/* Commands checked in table:

  CHANGE_DEFINITION 40
  COMPARE 39
  COPY 18
  COPY_AND_VERIFY 3a
  ERASE 19
  ERASE_10 2c
  ERASE_12 ac
  EXCHANGE_MEDIUM a6
  FORMAT_UNIT 04
  GET_DATA_BUFFER_STATUS 34
  GET_MESSAGE_10 28
  GET_MESSAGE_12 a8
  GET_WINDOW 25   !!! Has more data than READ_CAPACITY, need to fix table
  INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len
  INQUIRY 12
  LOAD_UNLOAD 1b
  LOCATE 2b
  LOCK_UNLOCK_CACHE 36
  LOG_SELECT 4c
  LOG_SENSE 4d
  MEDIUM_SCAN 38     !!! This was M
  MODE_SELECT6 15
  MODE_SELECT_10 55
  MODE_SENSE_6 1a
  MODE_SENSE_10 5a
  MOVE_MEDIUM a5
  OBJECT_POSITION 31  !!! Same as SEARCH_DATA_EQUAL
  PAUSE_RESUME 4b
  PLAY_AUDIO_10 45
  PLAY_AUDIO_12 a5
  PLAY_AUDIO_MSF 47
  PLAY_AUDIO_TRACK_INDEX 48
     PLAY_AUDIO_TRACK_RELATIVE_10 49
  PLAY_AUDIO_TRACK_RELATIVE_12 a9
  POSITION_TO_ELEMENT 2b
         PRE-FETCH 34
  PREVENT_ALLOW_MEDIUM_REMOVAL 1e
  PRINT 0a             !!! Same as WRITE_6 but is always in bytes
  READ_6 08
  READ_10 28
  READ_12 a8
  READ_BLOCK_LIMITS 05
  READ_BUFFER 3c
  READ_CAPACITY 25
  READ_CDROM_CAPACITY 25
  READ_DEFECT_DATA 37
  READ_DEFECT_DATA_12 b7
  READ_ELEMENT_STATUS b8 !!! Think this is in bytes
  READ_GENERATION 29 !!! Could also be M?
  READ_HEADER 44     !!! This was L
  READ_LONG 3e
  READ_POSITION 34   !!! This should be V but conflicts with PRE-FETCH
  READ_REVERSE 0f
  READ_SUB-CHANNEL 42 !!! Is this in bytes?
  READ_TOC 43         !!! Is this in bytes?
  READ_UPDATED_BLOCK 2d
  REASSIGN_BLOCKS 07
  RECEIVE 08        !!! Same as READ_6 probably in bytes though
  RECEIVE_DIAGNOSTIC_RESULTS 1c
  RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes
  RELEASE_UNIT 17
  REQUEST_SENSE 03
  REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes
  RESERVE_UNIT 16
  REWIND 01
  REZERO_UNIT 01
  SCAN 1b          !!! Conflicts with various commands, should be L
  SEARCH_DATA_EQUAL 31
  SEARCH_DATA_EQUAL_12 b1
  SEARCH_DATA_LOW 30
  SEARCH_DATA_LOW_12 b0
  SEARCH_DATA_HIGH 32
  SEARCH_DATA_HIGH_12 b2
  SEEK_6 0b         !!! Conflicts with SLEW_AND_PRINT
  SEEK_10 2b
  SEND 0a           !!! Same as WRITE_6, probably in bytes though
  SEND 2a           !!! Similar to WRITE_10 but for scanners
  SEND_DIAGNOSTIC 1d
  SEND_MESSAGE_6 0a   !!! Same as WRITE_6 - is in bytes
  SEND_MESSAGE_10 2a  !!! Same as WRITE_10 - is in bytes
  SEND_MESSAGE_12 aa  !!! Same as WRITE_12 - is in bytes
  SEND_OPC 54
  SEND_VOLUME_TAG b6 !!! Think this is in bytes
  SET_LIMITS 33
  SET_LIMITS_12 b3
  SET_WINDOW 24
  SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6
  SPACE 11
  START_STOP_UNIT 1b
  STOP_PRINT 1b
  SYNCHRONIZE_BUFFER 10
  SYNCHRONIZE_CACHE 35
  TEST_UNIT_READY 00
  UPDATE_BLOCK 3d
  VERIFY 13
  VERIFY 2f
  VERIFY_12 af
  WRITE_6 0a
  WRITE_10 2a
  WRITE_12 aa
  WRITE_AND_VERIFY 2e
  WRITE_AND_VERIFY_12 ae
  WRITE_BUFFER 3b
  WRITE_FILEMARKS 10
  WRITE_LONG 3f
  WRITE_SAME 41
*/

switch (lengths[srb->cmnd[0]]) {
case \'L\':
len = srb->cmnd[4];
break;
case \'M\':
len = srb->cmnd[8];
break;
case \'0\':
case \'1\':
case \'2\':
case \'3\':
case \'4\':
case \'5\':
case \'6\':
case \'7\':
case \'8\':
case \'9\':
len = lengths[srb->cmnd[0]]-\'0\';
break;

case \'G\':
len = (((unsigned int)srb->cmnd[3])<<8) |
srb->cmnd[4];
break;
case \'H\':
len = (((unsigned int)srb->cmnd[7])<<8) |
srb->cmnd[8];
break;
case \'I\':
len = (((unsigned int)srb->cmnd[8])<<8) |
srb->cmnd[9];
break;
case \'R\':
len = (((unsigned int)srb->cmnd[2])<<16) |
(((unsigned int)srb->cmnd[3])<<8) |
srb->cmnd[4];
break;
case \'S\':
len = (((unsigned int)srb->cmnd[3])<<16) |
(((unsigned int)srb->cmnd[4])<<8) |
srb->cmnd[5];
break;
case \'T\':
len = (((unsigned int)srb->cmnd[6])<<16) |
(((unsigned int)srb->cmnd[7])<<8) |
srb->cmnd[8];
break;
case \'U\':
len = (((unsigned int)srb->cmnd[7])<<16) |
(((unsigned int)srb->cmnd[8])<<8) |
srb->cmnd[9];
break;
case \'C\':
len = (((unsigned int)srb->cmnd[2])<<24) |
(((unsigned int)srb->cmnd[3])<<16) |
(((unsigned int)srb->cmnd[4])<<8) |
srb->cmnd[5];
break;
case \'D\':
len = (((unsigned int)srb->cmnd[6])<<24) |
(((unsigned int)srb->cmnd[7])<<16) |
(((unsigned int)srb->cmnd[8])<<8) |
srb->cmnd[9];
break;
case \'V\':
len = 20;
break;
case \'W\':
len = 24;
break;
case \'B\':
/* Use buffer size due to different block sizes */
doDefault = 1;
break;
case \'X\':
printf(\"Error: UNSUPPORTED COMMAND %02X\\n\",
srb->cmnd[0]);
doDefault = 1;
break;
case \'Z\':
/* Use buffer size due to mode dependence */
doDefault = 1;
break;
default:
printf(\"Error: COMMAND %02X out of range or table inconsistent (%c).\\n\",
srb->cmnd[0], lengths[srb->cmnd[0]] );
doDefault = 1;
}
len = srb->request_bufflen;
return len;
}


/*
 * Transfer an entire SCSI command\'s worth of data payload over the bulk
 * pipe.
 *
 * Note that this uses usb_stor_transfer_partial to achieve it\'s goals -- this
 * function simply determines if we\'re going to use scatter-gather or not,
 * and acts appropriately.  For now, it also re-interprets the error codes.
 */
void usb_stor_transfer(struct scsi_cmnd *srb, struct us_data* us)
{
int i;
int result = -1;
unsigned int total_transferred = 0;
unsigned int transfer_amount;

/* calculate how much we want to transfer */
transfer_amount = usb_stor_transfer_length(srb);

/* was someone foolish enough to request more data than available
* buffer space? */
if (transfer_amount > srb->request_bufflen)
transfer_amount = srb->request_bufflen;

/* no scatter-gather, just make the request */
result = usb_stor_transfer_partial(us, srb->request_buffer, transfer_amount);

/* return the result in the data structure itself */
srb->result = result;
}

int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap bcb;
struct bulk_cs_wrap bcs;
int result;
unsigned long pipe;
int partial;

/* set up the command wrapper */
bcb.Signature = US_BULK_CB_SIGN;
bcb.DataTransferLength = usb_stor_transfer_length(srb);
bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
bcb.Length = srb->cmd_len;

/* construct the pipe handle */
pipe = usb_sndbulkpipe(us->pusb_dev, (unsigned long)(us->ep_out));
/* copy the command payload */
memset(bcb.CDB, 0, sizeof(bcb.CDB));
memcpy(bcb.CDB, srb->cmnd, bcb.Length);

/* send it to out endpoint */
printf(\"Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\\n\",
 bcb.Signature, bcb.Tag,
 (bcb.Lun >> 4), (bcb.Lun & 0x0F),
 bcb.DataTransferLength, bcb.Flags, bcb.Length);
result = uhci_bulk_msg(us->pusb_dev, pipe, &bcb, US_BULK_CB_WRAP_LEN, &partial, HZ * SET_TIMEOUT);
printf(\"Bulk command transfer result=%d\\n\", result);

/* if the command transfered well, then we go to the data stage */
if (result == 0) {
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
usb_stor_transfer(srb, us);
                        sleep(1);
printf(\"Bulk data transfer result 0x%x\\n\",
 srb->result);

/* if it was aborted, we need to indicate that */
if (srb->result == USB_STOR_TRANSPORT_ABORTED)
return USB_STOR_TRANSPORT_ABORTED;
}
}

/* See flow chart on pg 15 of the Bulk Only Transport spec for
* an explanation of how this code works.
*/

/* construct the pipe handle */
pipe = usb_rcvbulkpipe(us->pusb_dev, (unsigned long)(us->ep_in));

/* get CSW for device status */
printf(\"Attempting to get CSW...\\n\");
result = uhci_bulk_msg(us, pipe, &bcs, US_BULK_CS_WRAP_LEN, &partial, HZ * SET_TIMEOUT);
// sleep(1);
// usb_bulk_only_mass_stor_reset(us);
// sleep(1);

/* if we still have a failure at this point, we\'re in trouble */
printf(\"Bulk status result = %d\\n\", result);
if (result) {
return USB_STOR_TRANSPORT_ERROR;
}

/* check bulk status */
printf(\"Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\\n\",
bcs.Signature, bcs.Tag,
 bcs.Residue, bcs.Status);

if (bcs.Signature != US_BULK_CS_SIGN ||
   bcs.Tag != bcb.Tag ||
   bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
printf(\"Bulk logical error\\n\");
return USB_STOR_TRANSPORT_ERROR;
}

/* based on the status code, we report good or bad */
switch (bcs.Status) {
case US_BULK_STAT_OK:
/* command good -- note that data could be short */
return USB_STOR_TRANSPORT_GOOD;

case US_BULK_STAT_FAIL:
/* command failed */
return USB_STOR_TRANSPORT_FAILED;

case US_BULK_STAT_PHASE:
/* phase error -- note that a transport reset will be
* invoked by the invoke_transport() function
*/
return USB_STOR_TRANSPORT_ERROR;
}

/* we should never get here, but if we do, we\'re in trouble */
return USB_STOR_TRANSPORT_ERROR;
}

/***********************************************************************
 * Transport routines
 ***********************************************************************/

/* Invoke the transport and basic error-handling/recovery methods
 *
 * This is used by the protocol layers to actually send the message to
 * the device and recieve the response.
 */
void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result;

/* send the command to the transport layer */
result = usb_stor_Bulk_transport(srb, us);
}

void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}

zhuzc
驱动中牛
驱动中牛
  • 注册日期2001-09-01
  • 最后登录2005-04-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-07-02 14:23
我来仔细看看
我是树上的那只鸟,整理着自己的羽毛,看着城市的喧嚣……
游客

返回顶部