阅读:3006回复:12
可否直接用汇编进行USB通讯,那位高手能告诉我具体I/O port?
可否直接用汇编进行USB通讯,那位高手能告诉我具体I/O port?
|
|
沙发#
发布于:2002-06-22 13:32
个人认为,不能简单的IO读写操作,因为下面有USB桥完成地层的工作
|
|
|
板凳#
发布于:2002-06-22 13:53
需要有驱动程序才行啊! 你指的汇编是用在什么地方,下位机?
|
|
地板#
发布于:2002-06-22 14:27
看一下usb controller的地址
|
|
地下室#
发布于:2002-06-22 17:59
支持spin。
以pc机为例,不同的主板芯片组,usb controller不同。 这要查具体的手册,呵呵。 提示一下: usb controller挂在PCI总线上,内部设置了fifo;通过一些寄存器;查询方式(假中断);需要实现request链表。 |
|
|
5楼#
发布于:2002-06-22 18:02
一般都是和intel兼容的.
|
|
|
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] |
|
7楼#
发布于:2002-06-23 14:32
可以参考linux下的实现
《linux内核源代码情景分析》 |
|
|
8楼#
发布于:2002-06-23 20:42
我在用C52芯片汇编写下位机,现正被那些描述符搞混了,C 的
资料好找,汇编的如何配置,如何与PC连机? 快告诉我好吗? E_MAIL:raymondarc@21cn.com |
|
9楼#
发布于:2002-07-02 13:42
别做梦了,用IO端口访问USB Device是不可能的。不过对于特定的USB Host芯片,IC设计人员为了Debug的需要,会设置一些寄存器,通过往里面写,就可以把数据发出去。而且还不能读。当然,这些寄存器对一般用户来说是没有任何作用的。你如果想了解多一点,那去看OHCL,UHCL吧。不过在DOS底下访问USB还是有办法的,以后再慢慢告诉你。
---------- 请多支持国产IC业 |
|
10楼#
发布于:2002-07-02 14:13
不同意楼上的!!!
我已经用c做过了直接访问usb host controller的程序! 详细说明见上 |
|
|
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); } |
|
12楼#
发布于:2002-07-02 14:23
我来仔细看看
|
|
|