mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
Initial checkin of polling USB stack
This commit is contained in:
parent
edefdfccab
commit
803eeae5d2
16 changed files with 4127 additions and 0 deletions
6
util/baremetal/usb/COPYING
Normal file
6
util/baremetal/usb/COPYING
Normal file
|
@ -0,0 +1,6 @@
|
|||
USB for the bare metal toolkit
|
||||
Most of this is copyright 2003 Steven James <pyro@linuxlabs.com>
|
||||
and Linux Labs http://www.linuxlabs.com
|
||||
|
||||
Licensed under the GNU General Public License.
|
||||
Portions are borrowed from LinuxBIOS itself and other sources.
|
68
util/baremetal/usb/Makefile
Normal file
68
util/baremetal/usb/Makefile
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
CC = gcc
|
||||
#INCLUDE = -I/usr/src/linux/include
|
||||
ARCH = i386
|
||||
CFLAGS = -I ../include -I ../include/$(ARCH) -O2 -DDEBUG -DZKERNEL_START=0xfff00000
|
||||
|
||||
#CFLAGS = -g -O2 $(INCLUDE)
|
||||
KFLAGS = -g -O2 -D__KERNEL__ -DDEBUG -DKERNEL -DMODULE -I/usr/src/linux/include
|
||||
LIBS = -lusb
|
||||
|
||||
DEPS = uhci.o usb_scsi_low.o debug.o scsi_cmds.o pci_util.o block_fill_inbuf.o ../lib/baremetal.a
|
||||
|
||||
LD = ld
|
||||
KERN_LDFLAGS = -r --whole-archive
|
||||
|
||||
PREFIX = /usr
|
||||
TARGETS = roothub kerntest test
|
||||
|
||||
all: usbboot.elf usb_stream.a
|
||||
|
||||
usbboot.elf: $(DEPS) main.o
|
||||
ld -defsym HEAPSIZE=0x8000 -T elfImage.lds main.o $(DEPS) -o usbboot.elf
|
||||
|
||||
usb_stream.a: $(DEPS)
|
||||
ar -cr usb_stream.a $(DEPS)
|
||||
|
||||
test: test.c uhci.[ch] pci_util.o debug.[ch]
|
||||
$(CC) -g -DDEBUG -DUDEBUG -o test test.c uhci.c pci_util.o debug.c
|
||||
|
||||
kerntest: kernel_test.o
|
||||
|
||||
kernel_test.o: kernel_uhci.o pci_util.o kernel_debug.o kernel_pci_util.o kernel_usb_scsi_low.o kernel_scsi_cmds.o
|
||||
$(LD) $(KERN_LDFLAGS) -o kernel_test.o kernel_uhci.o kernel_pci_util.o kernel_debug.o kernel_usb_scsi_low.o kernel_scsi_cmds.o
|
||||
|
||||
kernel_uhci.o: uhci.c uhci.h
|
||||
$(CC) $(KFLAGS) -o kernel_uhci.o -c uhci.c
|
||||
|
||||
kernel_usb_scsi_low.o : usb_scsi_low.c
|
||||
$(CC) $(KFLAGS) -o kernel_usb_scsi_low.o -c usb_scsi_low.c
|
||||
|
||||
kernel_scsi_cmds.o : scsi_cmds.c
|
||||
$(CC) $(KFLAGS) -o kernel_scsi_cmds.o -c scsi_cmds.c
|
||||
|
||||
kernel_debug.o: debug.c debug.h
|
||||
$(CC) $(KFLAGS) -o kernel_debug.o -c debug.c
|
||||
|
||||
kernel_pci_util.o: pci_util.c pci_util.h
|
||||
$(CC) $(KFLAGS) -o kernel_pci_util.o -c pci_util.c
|
||||
|
||||
roothub: roothub.c pci_util.o
|
||||
$(CC) $(CFLAGS) -o roothub roothub.c pci_util.o
|
||||
|
||||
strip: $(TARGETS)
|
||||
strip $(TARGETS)
|
||||
|
||||
install: strip
|
||||
install -d $(PREFIX)/bin
|
||||
cp -a $(TARGETS) $(PREFIX)/bin
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS) *.o
|
||||
|
||||
distclean: clean
|
||||
rm -f roothub.tar.gz
|
||||
|
||||
tardist: distclean
|
||||
tar -C .. --exclude CVS -cvzf roothub.tar.gz thumb
|
||||
|
184
util/baremetal/usb/block_fill_inbuf.c
Normal file
184
util/baremetal/usb/block_fill_inbuf.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include <printk.h>
|
||||
#include <stdlib.h>
|
||||
#include <subr.h>
|
||||
#include <stddef.h>
|
||||
#include <rom/read_bytes.h>
|
||||
//#include <delay.h>
|
||||
|
||||
#include <string.h>
|
||||
//#include <floppy_subr.h>
|
||||
#include "uhci.h"
|
||||
|
||||
|
||||
typedef struct block_device {
|
||||
void (*shutdown)(void);
|
||||
int (*read)(int drive, void *buffer, unsigned int block);
|
||||
int blocks;
|
||||
int block_size;
|
||||
} block_device_t;
|
||||
|
||||
typedef struct partition_entry {
|
||||
uchar boot_flag;
|
||||
|
||||
uchar chs[7];
|
||||
|
||||
unsigned int lba_start;
|
||||
unsigned int lba_len;
|
||||
} __attribute__ ((packed)) partition_entry_t;
|
||||
|
||||
typedef struct partition {
|
||||
char loader[446];
|
||||
partition_entry_t entry[4];
|
||||
char sig[2];
|
||||
} __attribute__ ((packed)) partition_t;
|
||||
|
||||
unsigned char usb_device_address=0;
|
||||
|
||||
/* read a sector or a partial sector */
|
||||
extern int ll_read_block(unsigned char device, void *buffer, unsigned int block, unsigned int count);
|
||||
|
||||
extern int block_read_sector(int drive, void * buffer, unsigned int block, int byte_offset,
|
||||
int n_bytes);
|
||||
|
||||
static unsigned long offset;
|
||||
static unsigned long partition_start;
|
||||
static unsigned long partition_end;
|
||||
|
||||
static int init_bytes(void)
|
||||
{
|
||||
int i,res;
|
||||
int error_count=100;
|
||||
partition_t part;
|
||||
unsigned char sense_data[32];
|
||||
|
||||
// find first usb device
|
||||
|
||||
while(error_count && (res = poll_usb())) // keep polling usb until no more devices are enumerated
|
||||
if(res<0)
|
||||
if(!--error_count)
|
||||
printk("There is a USB device, but it won't init! This is a bad thing.\n");
|
||||
|
||||
for(i=0; i< next_usb_dev ; i++) {
|
||||
if(usb_device[i].class == 0x08 && usb_device[i].subclass == 0x06 && usb_device[i].protocol == 0x50) {
|
||||
printk("Found USB block device %u\n", i);
|
||||
usb_device_address = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!usb_device_address) {
|
||||
printk("Massive failure, no suitable USB device!\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
printk("Requesting initial sense data\n");
|
||||
request_sense( usb_device_address, sense_data, 32);
|
||||
PrintSense(sense_data, 32);
|
||||
|
||||
// get_capacity(addr, &block_count, &block_len);
|
||||
// printk("%u %u byte blocks\n", block_count, block_len);
|
||||
|
||||
res = ll_read_block(usb_device_address, &part, 0, 1);
|
||||
|
||||
printk("ll_read_block returns %d\n", res);
|
||||
|
||||
res=-1;
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
printk("%u: boot=%02x, start=%08x length=%08x\n",i, part.entry[i].boot_flag, part.entry[i].lba_start, part.entry[i].lba_len);
|
||||
if(part.entry[i].boot_flag & 0x80) {
|
||||
printk("Using partition %u\n", i);
|
||||
partition_start = part.entry[i].lba_start;
|
||||
partition_end = partition_start + part.entry[i].lba_len;
|
||||
res=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void fini_bytes(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#define CHUNK_SIZE 16384
|
||||
#define BLOCK_PER_CHUNK CHUNK_SIZE/512
|
||||
|
||||
static unsigned char buffer[CHUNK_SIZE];
|
||||
static unsigned int block_num = 0;
|
||||
static unsigned int first_fill = 1;
|
||||
|
||||
static byte_offset_t usb_read(void *vdest, byte_offset_t offset, byte_offset_t count)
|
||||
{
|
||||
byte_offset_t bytes = 0;
|
||||
unsigned char *dest = vdest;
|
||||
|
||||
//printk_debug("ide_read count = %x\n", count);
|
||||
while (bytes < count) {
|
||||
unsigned int byte_offset, len;
|
||||
int result;
|
||||
int i, j;
|
||||
|
||||
/* The block is not cached in memory or frist time called */
|
||||
if (block_num != offset / CHUNK_SIZE || first_fill) {
|
||||
block_num = offset / CHUNK_SIZE;
|
||||
printk_notice (".");
|
||||
ll_read_block(usb_device_address, buffer, partition_start + block_num*BLOCK_PER_CHUNK, BLOCK_PER_CHUNK);
|
||||
first_fill = 0;
|
||||
#if 0
|
||||
//printk_debug("ide_read offset = %x\n", offset);
|
||||
//printk_debug("ide_read block_num = %x\n", block_num);
|
||||
for (i = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
printk_debug("%02x ", buffer[i*16 +j]);
|
||||
}
|
||||
printk_debug("\n");
|
||||
}
|
||||
|
||||
printk_debug("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
byte_offset = offset % CHUNK_SIZE;
|
||||
len = CHUNK_SIZE - byte_offset;
|
||||
if (len > (count - bytes)) {
|
||||
len = (count - bytes);
|
||||
}
|
||||
|
||||
memcpy(dest, buffer + byte_offset, len);
|
||||
|
||||
offset += len;
|
||||
bytes += len;
|
||||
dest += len;
|
||||
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static byte_offset_t read_bytes(void *vdest, byte_offset_t count)
|
||||
{
|
||||
byte_offset_t len;
|
||||
|
||||
len = usb_read(vdest, offset, count);
|
||||
if (len > 0) {
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static byte_offset_t skip_bytes(byte_offset_t count)
|
||||
{
|
||||
offset += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
struct stream usb_stream __stream = {
|
||||
.init = init_bytes,
|
||||
.read = read_bytes,
|
||||
.skip = skip_bytes,
|
||||
.fini = fini_bytes,
|
||||
};
|
403
util/baremetal/usb/debug.c
Normal file
403
util/baremetal/usb/debug.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "uhci.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/string.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
void dump_link( link_pointer_t *link, char *prefix)
|
||||
{
|
||||
DPRINTF("%saddr: %p\n", prefix, MEM_ADDR(link->link) );
|
||||
DPRINTF("%s raw addr: %p\n", prefix, (link->link) <<4 );
|
||||
DPRINTF("%sterminate: %u\n", prefix, link->terminate);
|
||||
DPRINTF("%squeue: %u\n", prefix, link->queue);
|
||||
DPRINTF("%sdepth: %u\n", prefix, link->depth);
|
||||
}
|
||||
|
||||
void dump_frame_list( link_pointer_t *addr, char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF("%sFRAMELIST:\n",prefix);
|
||||
|
||||
for(i=0;i<10; i++) {
|
||||
dump_link(addr+i, prefix);
|
||||
if(addr[i].queue)
|
||||
dump_queue_head( MEM_ADDR(addr[i].link), "");
|
||||
else
|
||||
dump_td( MEM_ADDR(addr[i].link), "");
|
||||
}
|
||||
}
|
||||
|
||||
void dump_hex(uchar *data, int len, char *prefix)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while(i<len) {
|
||||
if(!i%16)
|
||||
DPRINTF("\n%s %04x: ", prefix, i);
|
||||
else
|
||||
DPRINTF(": ");
|
||||
|
||||
DPRINTF("%02x", data[i++]);
|
||||
}
|
||||
|
||||
DPRINTF("\n");
|
||||
}
|
||||
|
||||
void dump_uhci(unsigned short port)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
DPRINTF("UHCI at %04x\n", port);
|
||||
#ifdef __KERNEL__
|
||||
value = inw(port);
|
||||
DPRINTF("Command: %04x\n", value);
|
||||
|
||||
value = inw(port+2);
|
||||
DPRINTF("USBSTS: %04x\n", value);
|
||||
|
||||
value = inw(port+4);
|
||||
DPRINTF("USBINTR: %04x\n", value);
|
||||
|
||||
value = inw(port+6);
|
||||
DPRINTF("FRNUM: %04x\n", value);
|
||||
|
||||
value = inl(port+8);
|
||||
DPRINTF("FLBASEADD: %08x\n", value);
|
||||
|
||||
value = inb(port+0x0c);
|
||||
DPRINTF("SOFMOD: %02x\n", value);
|
||||
|
||||
value = inw(port+0x10);
|
||||
DPRINTF("PORTSTS1: %04x\n", value);
|
||||
|
||||
value = inw(port+0x12);
|
||||
DPRINTF("PORTSTS2: %04x\n", value);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void dump_td( td_t *td, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0]='\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%sTD(%p):\n", prefix, td);
|
||||
|
||||
switch(td->packet_type) {
|
||||
case SETUP_TOKEN:
|
||||
DPRINTF("%stype: SETUP\n", prefix);
|
||||
break;
|
||||
case OUT_TOKEN:
|
||||
DPRINTF("%stype: OUT\n", prefix);
|
||||
break;
|
||||
case IN_TOKEN:
|
||||
DPRINTF("%stype: IN\n", prefix);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%stype: INVALID (%02x)\n", prefix, td->packet_type);
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("%sretries: %u\n", prefix, td->retrys);
|
||||
|
||||
if(td->isochronous)
|
||||
DPRINTF("%sisochronous\n", prefix);
|
||||
|
||||
if(td->interrupt)
|
||||
DPRINTF("%sIOC\n", prefix);
|
||||
|
||||
if(td->lowspeed)
|
||||
DPRINTF("%slowspeed\n", prefix);
|
||||
|
||||
if(td->detect_short)
|
||||
DPRINTF("%sDETECT_SHORT\n", prefix);
|
||||
|
||||
DPRINTF("%sactive: %u\n", prefix, td->active);
|
||||
DPRINTF("%sdevice_addr: %02x\n", prefix, td->device_addr);
|
||||
DPRINTF("%sendpoint: %1x\n", prefix, td->endpoint);
|
||||
DPRINTF("%sdata_toggle: %1u\n", prefix, td->data_toggle);
|
||||
DPRINTF("%smax_transfer: %u\n", prefix, td->max_transfer);
|
||||
DPRINTF("%sactual: %u\n", prefix, td->actual);
|
||||
DPRINTF("%slink:\n", prefix);
|
||||
|
||||
if(td->stall)
|
||||
DPRINTF("%sSTALL\n", prefix);
|
||||
|
||||
if(td->bitstuff)
|
||||
DPRINTF("%sBITSTUFF ERROR\n", prefix);
|
||||
|
||||
if(td->crc)
|
||||
DPRINTF("%sCRC ERROR\n", prefix);
|
||||
|
||||
if(td->nak)
|
||||
DPRINTF("%sNAK ERROR\n", prefix);
|
||||
|
||||
if(td->babble)
|
||||
DPRINTF("%sBABBLE ERROR\n", prefix);
|
||||
|
||||
if(td->buffer_error)
|
||||
DPRINTF("%sBUFFER ERROR\n", prefix);
|
||||
|
||||
if(MEM_ADDR(td->link.link) == td) {
|
||||
DPRINTF("link loops back to me!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_link(&(td->link), newpre);
|
||||
if(!td->link.terminate) {
|
||||
if(td->link.queue)
|
||||
dump_queue_head(MEM_ADDR(td->link.link), prefix );
|
||||
else
|
||||
dump_td(MEM_ADDR(td->link.link), prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_queue_head( queue_head_t *qh, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%sQUEUE HEAD(%p):\n", prefix, qh);
|
||||
DPRINTF("%sdepth:\n", prefix);
|
||||
dump_link( &(qh->depth), newpre);
|
||||
|
||||
if(!qh->depth.terminate)
|
||||
if(qh->depth.queue)
|
||||
dump_queue_head(MEM_ADDR(qh->depth.link), newpre);
|
||||
else
|
||||
dump_td( MEM_ADDR(qh->depth.link), newpre);
|
||||
|
||||
|
||||
DPRINTF("%sbredth:\n", prefix);
|
||||
dump_link( &(qh->bredth), newpre);
|
||||
if(!qh->bredth.terminate)
|
||||
if(qh->bredth.queue)
|
||||
dump_queue_head(MEM_ADDR(qh->bredth.link), newpre);
|
||||
else
|
||||
dump_td( MEM_ADDR(qh->bredth.link), newpre);
|
||||
}
|
||||
|
||||
void dump_transaction( transaction_t *trans, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
|
||||
DPRINTF("%s TRANSACTION(%p):\n", prefix, trans);
|
||||
dump_queue_head( trans->qh, newpre);
|
||||
|
||||
DPRINTF("%s TDs:\n", prefix);
|
||||
dump_td( trans->td_list, newpre);
|
||||
|
||||
DPRINTF("\n");
|
||||
if(trans->next)
|
||||
dump_transaction(trans->next, prefix);
|
||||
}
|
||||
|
||||
void dump_usbdev( usbdev_t *dev, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
int i;
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%saddress: %u\n", prefix, dev->address);
|
||||
DPRINTF("%sclass: %u\n", prefix, dev->class);
|
||||
DPRINTF("%ssubclass: %u\n", prefix, dev->subclass);
|
||||
DPRINTF("%sbulk_in: %u\n", prefix, dev->bulk_in);
|
||||
DPRINTF("%sbulk_out: %u\n", prefix, dev->bulk_out);
|
||||
DPRINTF("%sinterrupt: %u\n", prefix, dev->interrupt);
|
||||
|
||||
DPRINTF("%sep toggle:\n", prefix);
|
||||
for(i=0;i<MAX_EP;i++)
|
||||
DPRINTF("%s%u\n", newpre, dev->toggle[i]);
|
||||
|
||||
DPRINTF("%sep max_packet:\n", prefix);
|
||||
for(i=0;i<MAX_EP;i++)
|
||||
DPRINTF("%s%u\n", newpre, dev->max_packet[i]);
|
||||
}
|
||||
|
||||
void dump_all_usbdev(char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<MAX_USB_DEV;i++) {
|
||||
if(usb_device[i].address) {
|
||||
DPRINTF("%sDEVICE: %u\n", prefix, i);
|
||||
dump_usbdev( usb_device +i, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_device_descriptor( device_descriptor_t *des, char *prefix)
|
||||
{
|
||||
DPRINTF("%sbLength: %02x\n", prefix, des->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, des->type);
|
||||
DPRINTF("%sbcdVersion: %1u%1u\n", prefix, des->bcdVersion[1], des->bcdVersion[0]);
|
||||
DPRINTF("%sClass: %02x\n",prefix, des->Class);
|
||||
DPRINTF("%sSubClass: %02x\n",prefix, des->SubClass);
|
||||
DPRINTF("%sprotocol: %02x\n",prefix, des->protocol);
|
||||
DPRINTF("%smax_packet: %u\n",prefix, des->max_packet);
|
||||
DPRINTF("%sidVendor: %04x\n", prefix, des->idVendor);
|
||||
DPRINTF("%sidProduct: %04x\n", prefix, des->idProduct);
|
||||
DPRINTF("%sbcdDeviceVersion: %u%u\n", prefix, des->bcdDevice[1], des->bcdDevice[0]);
|
||||
DPRINTF("%siManufacturor: %02x\n", prefix, des->iManufacturor);
|
||||
DPRINTF("%siProduct: %02x\n", prefix, des->iProduct);
|
||||
DPRINTF("%siSerial: %02x\n", prefix, des->iSerial);
|
||||
DPRINTF("%sbNumConfig: %02x\n", prefix, des->bNumConfig);
|
||||
|
||||
}
|
||||
|
||||
void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix)
|
||||
{
|
||||
|
||||
DPRINTF("%sbLength: %02x\n", prefix, iface->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, iface->type);
|
||||
DPRINTF("%sbInterfaceNumber: %02x\n", prefix, iface->bInterfaceNumber);
|
||||
DPRINTF("%sbAlternateSetting: %02x\n", prefix, iface->bAlternateSetting);
|
||||
DPRINTF("%sbNumEndpoints: %02x\n", prefix, iface->bNumEndpoints);
|
||||
DPRINTF("%sbInterfaceClass: %02x\n", prefix, iface->bInterfaceClass);
|
||||
DPRINTF("%sbInterfaceSubClass: %02x\n", prefix, iface->bInterfaceSubClass);
|
||||
DPRINTF("%sbInterfaceProtocol: %02x\n", prefix, iface->bInterfaceProtocol);
|
||||
DPRINTF("%siInterface: %02x\n", prefix, iface->iInterface);
|
||||
}
|
||||
|
||||
void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix)
|
||||
{
|
||||
|
||||
DPRINTF("%sbLength: %02x\n", prefix, ep->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, ep->type);
|
||||
DPRINTF("%sbEndpointAddress: %02x\n", prefix, ep->bEndpointAddress);
|
||||
DPRINTF("%sbmAttributes: %02x\n", prefix, ep->bmAttributes);
|
||||
DPRINTF("%swMaxPacketSize: %02x\n", prefix, ep->wMaxPacketSize);
|
||||
DPRINTF("%sbInterval: %02x\n", prefix, ep->bInterval);
|
||||
}
|
||||
|
||||
void dump_config_descriptor( uchar *des, char *prefix) // YES uchar *
|
||||
{
|
||||
config_descriptor_t *config;
|
||||
interface_descriptor_t *iface;
|
||||
endpoint_descriptor_t *ep;
|
||||
char newpre[64];
|
||||
int i;
|
||||
|
||||
memset(newpre,0,sizeof(newpre));
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
config = (config_descriptor_t *) des;
|
||||
iface = (interface_descriptor_t *) (des + config->bLength);
|
||||
ep = (endpoint_descriptor_t *) (des + config->bLength + iface->bLength);
|
||||
|
||||
// now, the config itself
|
||||
DPRINTF("%sbLength: %02x\n", prefix, config->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, config->type);
|
||||
DPRINTF("%swTotalLength: %04x\n", prefix, config->wTotalLength);
|
||||
DPRINTF("%sbNumInterfaces: %02x\n", prefix, config->bNumInterfaces);
|
||||
DPRINTF("%sbConfigurationValue: %02x\n", prefix, config->bConfigurationValue);
|
||||
DPRINTF("%siConfiguration: %02x\n", prefix, config->iConfiguration);
|
||||
DPRINTF("%sbmAttributes: %02x\n", prefix, config->bmAttributes);
|
||||
|
||||
DPRINTF("%sbMaxPower: %02x\n", prefix, config->bMaxPower);
|
||||
|
||||
DPRINTF("\n%sInterface(%p):\n", prefix, iface);
|
||||
dump_interface_descriptor(iface, newpre);
|
||||
|
||||
newpre[1] = '\t';
|
||||
strcpy(newpre+2, prefix);
|
||||
|
||||
for(i=0; i<iface->bNumEndpoints; i++) {
|
||||
DPRINTF("\n%sEndpoint (%p):\n", newpre+1, ep+i);
|
||||
dump_endpoint_descriptor( ep+i, newpre);
|
||||
}
|
||||
}
|
||||
|
||||
// Some control message bmRequestType defines
|
||||
#define CTRL_DEVICE 0
|
||||
#define CONTROL_INTERFACE 1
|
||||
#define CONTROL_ENDPOINT 2
|
||||
#define CONTROL_OTHER 3
|
||||
#define CONTROL_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define CONTROL_TYPE_STD 0
|
||||
#define CONTROL_TYPE_CLASS 0x20
|
||||
#define CONTROL_CLASS_VENDOR 0x40
|
||||
#define CONTROL_CLASS_MASK 0x60
|
||||
|
||||
#define CONTROL_OUT 0
|
||||
#define CONTROL_IN 0x80
|
||||
#define CONTROL_DIR_MASK 0x80
|
||||
|
||||
// bRequest values
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
#define SYNC_FRAME 12
|
||||
|
||||
// descriptor types
|
||||
#define DEVICE_DESC 1
|
||||
#define CONFIGURATION_DESC 2
|
||||
#define STRING_DESC 3
|
||||
#define INTERFACE_DESC 4
|
||||
#define ENDPOINT_DESC 5
|
||||
#define OTHERSPEED_DESC 7
|
||||
#define POWER_DESC 8
|
||||
|
||||
// features
|
||||
#define FEATURE_HALT 0
|
||||
void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix)
|
||||
{
|
||||
DPRINTF("%sbmRequestType: %02x\n", prefix, msg->bmRequestType);
|
||||
DPRINTF("%sbRequest: %02x\n", prefix, msg->bRequest);
|
||||
DPRINTF("%swValue: %04x\n", prefix, msg->wValue);
|
||||
DPRINTF("%swIndex: %04x\n", prefix, msg->wIndex);
|
||||
DPRINTF("%swLength: %04x\n", prefix, msg->wLength);
|
||||
}
|
||||
|
26
util/baremetal/usb/debug.h
Normal file
26
util/baremetal/usb/debug.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include "uhci.h"
|
||||
|
||||
#ifndef KERNEL
|
||||
#include <printk.h>
|
||||
#define DPRINTF( x...) printk(x)
|
||||
#else
|
||||
#define DPRINTF( x...) printk("<1>" x)
|
||||
#endif
|
||||
|
||||
void dump_hex(uchar *data, int len, char *prefix);
|
||||
void dump_link( link_pointer_t *link, char *prefix);
|
||||
void dump_td( td_t *td, char *prefix);
|
||||
void dump_queue_head( queue_head_t *qh, char *prefix);
|
||||
void dump_transaction( transaction_t *trans, char *prefix);
|
||||
void dump_usbdev( usbdev_t *dev, char *prefix);
|
||||
//void dump_all_usbdev(char *prefix);
|
||||
void dump_device_descriptor( device_descriptor_t *des, char *prefix);
|
||||
void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix);
|
||||
void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix);
|
||||
void dump_config_descriptor( uchar *des, char *prefix);
|
||||
void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix);
|
||||
|
||||
#endif
|
57
util/baremetal/usb/elfImage.lds
Normal file
57
util/baremetal/usb/elfImage.lds
Normal file
|
@ -0,0 +1,57 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
HEAPSIZE = DEFINED(HEAPSIZE) ? HEAPSIZE : 0x8000;
|
||||
|
||||
ENTRY(main)
|
||||
SECTIONS
|
||||
{
|
||||
/* . = 0x10000 - (elf_note - elf_header); */
|
||||
. = 0x30000000;
|
||||
_text = .; /* Text and read-only data */
|
||||
.text . : {
|
||||
*(.text)
|
||||
*(.fixup)
|
||||
*(.gnu.warning)
|
||||
} = 0x9090
|
||||
.rodata (.): { *(.rodata) }
|
||||
.kstrtab (.): { *(.kstrtab) }
|
||||
|
||||
|
||||
. = ALIGN(16); /* Exception table */
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
.data (.): { /* Data */
|
||||
*(.data)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
|
||||
_edata = .; /* End of data section */
|
||||
__bss_start = .; /* BSS */
|
||||
.bss (.): {
|
||||
*(.bss)
|
||||
_ebss = .;
|
||||
|
||||
_heap = .;
|
||||
. += HEAPSIZE;
|
||||
_eheap = .;
|
||||
}
|
||||
_end = . ;
|
||||
|
||||
_ram_seg = _text;
|
||||
_eram_seg = _end;
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
122
util/baremetal/usb/ide_fill_inbuf.c
Normal file
122
util/baremetal/usb/ide_fill_inbuf.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include <printk.h>
|
||||
#include <stdlib.h>
|
||||
#include <subr.h>
|
||||
#include <stddef.h>
|
||||
#include <rom/read_bytes.h>
|
||||
#include <delay.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <floppy_subr.h>
|
||||
|
||||
/* read a sector or a partial sector */
|
||||
extern int ide_read_sector(int drive, void * buffer, unsigned int block, int byte_offset,
|
||||
int n_bytes);
|
||||
extern int ide_init(void);
|
||||
|
||||
static unsigned long offset;
|
||||
static int init_bytes(void)
|
||||
{
|
||||
int i,res;
|
||||
|
||||
printk_debug ("Trying polled ide\n");
|
||||
printk_debug ("Waiting for ide disks to spin up\n");
|
||||
printk_notice ("This is a hard coded delay and longer than necessary.\n");
|
||||
for (i = 0; i < 2; i++) {
|
||||
printk_notice (".");
|
||||
delay(1);
|
||||
}
|
||||
printk_info ("\n");
|
||||
|
||||
#ifdef ONE_TRACK
|
||||
offset = (ONE_TRACK*512);
|
||||
#else
|
||||
offset = 0x7e00;
|
||||
#endif
|
||||
res = ide_init();
|
||||
delay(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void fini_bytes(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned char buffer[512];
|
||||
static unsigned int block_num = 0;
|
||||
static unsigned int first_fill = 1;
|
||||
#ifndef IDE_BOOT_DRIVE
|
||||
#define IDE_BOOT_DRIVE 0
|
||||
#endif
|
||||
static byte_offset_t ide_read(void *vdest, byte_offset_t offset, byte_offset_t count)
|
||||
{
|
||||
byte_offset_t bytes = 0;
|
||||
unsigned char *dest = vdest;
|
||||
|
||||
//printk_debug("ide_read count = %x\n", count);
|
||||
while (bytes < count) {
|
||||
unsigned int byte_offset, len;
|
||||
int result;
|
||||
int i, j;
|
||||
|
||||
/* The block is not cached in memory or frist time called */
|
||||
if (block_num != offset / 512 || first_fill) {
|
||||
block_num = offset / 512;
|
||||
printk_notice (".");
|
||||
ide_read_sector(IDE_BOOT_DRIVE, buffer, block_num,
|
||||
0, 512);
|
||||
first_fill = 0;
|
||||
#if 0
|
||||
//printk_debug("ide_read offset = %x\n", offset);
|
||||
//printk_debug("ide_read block_num = %x\n", block_num);
|
||||
for (i = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
printk_debug("%02x ", buffer[i*16 +j]);
|
||||
}
|
||||
printk_debug("\n");
|
||||
}
|
||||
|
||||
printk_debug("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
byte_offset = offset % 512;
|
||||
len = 512 - byte_offset;
|
||||
if (len > (count - bytes)) {
|
||||
len = (count - bytes);
|
||||
}
|
||||
|
||||
memcpy(dest, buffer + byte_offset, len);
|
||||
|
||||
offset += len;
|
||||
bytes += len;
|
||||
dest += len;
|
||||
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static byte_offset_t read_bytes(void *vdest, byte_offset_t count)
|
||||
{
|
||||
byte_offset_t len;
|
||||
|
||||
len = ide_read(vdest, offset, count);
|
||||
if (len > 0) {
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static byte_offset_t skip_bytes(byte_offset_t count)
|
||||
{
|
||||
offset += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct stream ide_stream __stream = {
|
||||
.init = init_bytes,
|
||||
.read = read_bytes,
|
||||
.skip = skip_bytes,
|
||||
.fini = fini_bytes,
|
||||
};
|
56
util/baremetal/usb/main.c
Normal file
56
util/baremetal/usb/main.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "uhci.h"
|
||||
#include "debug.h"
|
||||
#include <arch/io.h>
|
||||
#include <rom/read_bytes.h>
|
||||
|
||||
struct lb_memory *lbmem;
|
||||
extern int usec_offset;
|
||||
|
||||
extern struct stream usb_stream;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned char value;
|
||||
|
||||
printk("LinuxLabs USB bootloader\n");
|
||||
|
||||
outb( 0x30, 0x70); // reset primary boot
|
||||
outb( 0xff, 0x71);
|
||||
lbmem = get_lbmem();
|
||||
|
||||
init_devices();
|
||||
uhci_init();
|
||||
|
||||
usb_stream.init();
|
||||
elfboot(&usb_stream, lbmem);
|
||||
|
||||
while(1) {
|
||||
poll_usb();
|
||||
// usec_offset+=10;
|
||||
// printk("USEC_OFFSET = %d\n", usec_offset);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
62
util/baremetal/usb/pci_util.c
Normal file
62
util/baremetal/usb/pci_util.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <asm/io.h>
|
||||
|
||||
|
||||
unsigned long int pci_read_config_long(unsigned long address)
|
||||
{
|
||||
unsigned short res;
|
||||
|
||||
unsigned port = 0xcfc + (address & 0x03);
|
||||
address &= ~0x03;
|
||||
|
||||
outl(address | 0x80000000 , 0xcf8);
|
||||
res = inw(port);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
unsigned int pci_read_config_word(unsigned long address)
|
||||
{
|
||||
unsigned short res;
|
||||
|
||||
unsigned port = 0xcfc + (address & 0x03);
|
||||
address &= ~0x03;
|
||||
|
||||
outl(address | 0x80000000 , 0xcf8);
|
||||
res = inw(port);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
unsigned char pci_read_config_byte(unsigned long address)
|
||||
{
|
||||
unsigned char res;
|
||||
|
||||
unsigned port = 0xcfc + (address & 0x03);
|
||||
address &= ~0x03;
|
||||
|
||||
outl(address | 0x80000000 , 0xcf8);
|
||||
res = inb(port);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
int pci_write_config_word(unsigned long address, unsigned short value)
|
||||
{
|
||||
unsigned port = 0xcfc + (address & 0x03);
|
||||
|
||||
address &= ~0x03;
|
||||
|
||||
outl(address | 0x80000000 , 0xcf8);
|
||||
outw(value, port);
|
||||
}
|
||||
|
||||
int pci_write_config_byte(unsigned long address, unsigned char value)
|
||||
{
|
||||
unsigned port = 0xcfc + (address & 0x03);
|
||||
|
||||
address &= ~0x03;
|
||||
|
||||
outl(address | 0x80000000 , 0xcf8);
|
||||
outb(value, port);
|
||||
}
|
||||
|
12
util/baremetal/usb/pci_util.h
Normal file
12
util/baremetal/usb/pci_util.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef PCI_UTIL_H
|
||||
#define PCI_UTIL_H
|
||||
|
||||
#define PCI_ADDR( b, d, f, i) 0x80000000 | (b<<16) | (d<<11) | (f<<8) | (i)
|
||||
|
||||
unsigned long int pci_read_config_long(unsigned long address);
|
||||
unsigned int pci_read_config_word(unsigned long address);
|
||||
unsigned char pci_read_config_byte(unsigned long address);
|
||||
int pci_write_config_word(unsigned long address, unsigned short value);
|
||||
int pci_write_config_byte(unsigned long address, unsigned char value);
|
||||
|
||||
#endif
|
523
util/baremetal/usb/scsi_cmds.c
Normal file
523
util/baremetal/usb/scsi_cmds.c
Normal file
|
@ -0,0 +1,523 @@
|
|||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
#include "usb_scsi_low.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *) 0x0
|
||||
#endif
|
||||
|
||||
typedef unsigned char devhandle;
|
||||
devhandle sgh;
|
||||
|
||||
#define ntohl htonl
|
||||
unsigned int htonl( unsigned int in)
|
||||
{
|
||||
unsigned int out;
|
||||
int i;
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
out <<= 8;
|
||||
out |= (in & 0xff);
|
||||
in >>=8;
|
||||
}
|
||||
|
||||
return(out);
|
||||
}
|
||||
|
||||
unsigned short htons( unsigned short in)
|
||||
{
|
||||
unsigned short out;
|
||||
int i;
|
||||
|
||||
for(i=0; i<2; i++) {
|
||||
out <<= 8;
|
||||
out |= (in & 0xff);
|
||||
in >>=8;
|
||||
}
|
||||
|
||||
return(out);
|
||||
}
|
||||
|
||||
typedef struct sense_data {
|
||||
uchar code;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:4;
|
||||
|
||||
uchar additional_code;
|
||||
uchar qualifier;
|
||||
|
||||
uchar res2[3];
|
||||
|
||||
uchar length;
|
||||
} __attribute__ ((packed)) sense_data_t;
|
||||
|
||||
typedef struct fixed_sense_data {
|
||||
uchar code:7;
|
||||
uchar valid:1;
|
||||
|
||||
uchar obs1;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:1;
|
||||
uchar ili:1;
|
||||
uchar eom:1;
|
||||
uchar mark:1;
|
||||
|
||||
unsigned int info;
|
||||
|
||||
uchar add_len;
|
||||
} __attribute__ ((packed)) fixed_sense_data_t;
|
||||
|
||||
typedef struct additional_fixed_data {
|
||||
unsigned int info;
|
||||
|
||||
uchar code;
|
||||
uchar qualifier;
|
||||
uchar fru;
|
||||
|
||||
uchar specific[3];
|
||||
} __attribute__ ((packed)) additional_fixed_data_t;
|
||||
|
||||
|
||||
void PrintSense(uchar *sense)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF( "sense data ");
|
||||
for(i=0;i<32; i++)
|
||||
DPRINTF( ":%02x", sense[i]);
|
||||
DPRINTF("\n\n");
|
||||
|
||||
if( (sense[0] & 0x7f) >=0x72) {
|
||||
sense_data_t *sd = (sense_data_t *) sense;
|
||||
uchar *pos = sense+sizeof(sense_data_t);
|
||||
uchar remaining = sd->length;
|
||||
int dlen;
|
||||
|
||||
DPRINTF("code = %02x, key = %1x, additional = %02x, qual = %02x\n", sd->code, sd->sense_key, sd->additional_code, sd->qualifier);
|
||||
|
||||
while(remaining) {
|
||||
DPRINTF("type = %02x", pos[0]);
|
||||
dlen = pos[1];
|
||||
pos+=2;
|
||||
remaining -=2;
|
||||
|
||||
for(i=0; i<dlen; i++)
|
||||
DPRINTF( ": %02x", pos[i]);
|
||||
|
||||
DPRINTF("\n");
|
||||
pos+=i;
|
||||
remaining -=i;
|
||||
}
|
||||
|
||||
} else {
|
||||
fixed_sense_data_t *fd = (fixed_sense_data_t *) sense;
|
||||
uchar remaining = fd->add_len;
|
||||
additional_fixed_data_t *afd;
|
||||
|
||||
|
||||
DPRINTF("code = %02x key = %1x\n", fd->code, fd->sense_key);
|
||||
if(fd->mark)
|
||||
DPRINTF("filemark ");
|
||||
|
||||
if(fd->eom)
|
||||
DPRINTF(" End Of Media ");
|
||||
|
||||
if(fd->ili)
|
||||
DPRINTF("Illegal instruction");
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
if(fd->valid)
|
||||
DPRINTF( "(valid) ");
|
||||
|
||||
DPRINTF( "Info: %08x\n", ntohl(fd->info));
|
||||
|
||||
afd = (additional_fixed_data_t *) (sense + 8);
|
||||
|
||||
// while(remaining) {
|
||||
if(remaining) {
|
||||
DPRINTF("command info = %08x\n", ntohl(afd->info));
|
||||
DPRINTF("code = %02x, qual = %02x, fru = %02x\n", afd->code, afd->qualifier, afd->fru);
|
||||
DPRINTF("sense key data = %02x:%02x:%02x\n\n", afd->specific[2], afd->specific[1], afd->specific[0]);
|
||||
|
||||
afd++;
|
||||
remaining -= sizeof(additional_fixed_data_t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef struct query_response {
|
||||
uchar type:5;
|
||||
uchar qualifier:3;
|
||||
|
||||
uchar reserved1:7;
|
||||
uchar removable:1;
|
||||
|
||||
uchar version;
|
||||
|
||||
uchar ResponseDataFormat:4; // should == 2
|
||||
uchar HiSup:1; // report luns cmd supported
|
||||
uchar NormACA:1;
|
||||
uchar obsolete:1;
|
||||
uchar aerc:1;
|
||||
|
||||
uchar AdditionalLength; // length of vendor specific data (beyond 96 bytes)
|
||||
|
||||
uchar reserved2:7;
|
||||
uchar sccs:1; // have raid controller
|
||||
|
||||
uchar addr16:1; //
|
||||
uchar obsolete2:2;
|
||||
uchar MChnger:1; // media changer
|
||||
uchar MultiP:1; // multi port
|
||||
uchar vs:1; // ???
|
||||
uchar EncServ:1; // enclosure service
|
||||
uchar BQue:1; // basic command queueing
|
||||
|
||||
uchar vs2:1;
|
||||
uchar CmdQue:1; // full command queueing
|
||||
uchar obsolete4:1;
|
||||
uchar linked:1;
|
||||
uchar sync:1;
|
||||
uchar wbus16:1; //
|
||||
uchar obsolete3:1;
|
||||
uchar RelAddr:1; // treletive addressing
|
||||
|
||||
char vendor[8];
|
||||
char product[16];
|
||||
char revision[4];
|
||||
char vendor_data[20];
|
||||
|
||||
uchar ius:1;
|
||||
uchar qas:1;
|
||||
uchar clocking:2; //
|
||||
uchar reserved3:4;
|
||||
|
||||
unsigned short version_desc[8];
|
||||
|
||||
char reserved4[21];
|
||||
} query_response_t;
|
||||
|
||||
typedef struct ReadBlockCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar reserved:2;
|
||||
uchar fua:1; // force unit access flush to media
|
||||
uchar dpo:1; // direct page out, do not cache
|
||||
uchar reserved2:3;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short block_count;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadBlockCMD_t ;
|
||||
|
||||
int ll_read_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
|
||||
if(ret<0) {
|
||||
DPRINTF("ERROR: ll_read_block( %u, %p, %u, %u) = %d\n", sgd, buffer, blocknum, count, ret);
|
||||
PrintSense(sensedat);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
|
||||
}
|
||||
|
||||
int ll_write_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = WRITE_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_TO_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct ReadLongCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar correct:1;
|
||||
uchar reserved:5;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short length;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadLongCMD_t ;
|
||||
|
||||
int ll_read_long(devhandle sgd, char *buffer, int blocknum, int size)
|
||||
{
|
||||
int ret;
|
||||
ReadLongCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_LONG;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.length = htons(size);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, size, sensedat, sizeof(sensedat));
|
||||
return(ret);
|
||||
}
|
||||
|
||||
unsigned char ReadCapacityCMD[10] = { READ_CAPACITY, 0, 0,0,0,0, 0,0,0, 0};
|
||||
|
||||
struct ReadCapacityResponse {
|
||||
unsigned int block_address;
|
||||
unsigned int block_length;
|
||||
};
|
||||
|
||||
int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len)
|
||||
{
|
||||
int ret;
|
||||
struct ReadCapacityResponse response;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, ReadCapacityCMD, sizeof(ReadCapacityCMD), SG_DXFER_FROM_DEV, &response, sizeof(response), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("ERROR:get capacity: %d\n", ret);
|
||||
PrintSense(sensedat);
|
||||
}
|
||||
|
||||
|
||||
*block_count = ntohl(response.block_address) +1;
|
||||
*blk_len = ntohl(response.block_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#define INQ_REP_LEN 96
|
||||
unsigned char InquiryCMD[6] = { INQUIRY, 0, 0, 0, INQ_REP_LEN, 0};
|
||||
|
||||
int query(devhandle sgd, query_response_t *qr)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, InquiryCMD, sizeof(InquiryCMD), SG_DXFER_FROM_DEV, qr, sizeof(query_response_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
DPRINTF("query: IOCTL");
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct lun_list {
|
||||
unsigned int list_length;
|
||||
unsigned int reserved;
|
||||
unsigned long long lun[16];
|
||||
} lun_list_t;
|
||||
|
||||
#define REPORT_LUNS 0xa0
|
||||
unsigned char ReportLunsCMD[12] = { REPORT_LUNS, 0, 2, 0, 0, 0, 0, 0, 0, 128, 0, 0 };
|
||||
|
||||
int ReportLUNS(devhandle sgd, lun_list_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
memset (list, 0, sizeof(lun_list_t));
|
||||
ret = scsi_command(sgd, ReportLunsCMD, sizeof(ReportLunsCMD), SG_DXFER_FROM_DEV, list, sizeof(lun_list_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
DPRINTF("Report Luns: IOCTL");
|
||||
|
||||
list->list_length = ntohl(list->list_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct command_descriptor {
|
||||
uchar opcode;
|
||||
uchar reserved;
|
||||
unsigned short service_action;
|
||||
uchar reserved2;
|
||||
|
||||
uchar action_valid:1;
|
||||
uchar reserved3:7;
|
||||
|
||||
unsigned short cdb_len;
|
||||
} __attribute__ ((packed)) command_descriptor_t;
|
||||
|
||||
typedef struct report_opcodes_result {
|
||||
unsigned long length;
|
||||
|
||||
command_descriptor_t command[256];
|
||||
} __attribute__ ((packed)) report_opcode_result_t;
|
||||
|
||||
|
||||
#define REPORT_OPCODES 0xa3
|
||||
|
||||
typedef struct report_opcodes_cmd {
|
||||
uchar cmd;
|
||||
uchar reserved[5];
|
||||
unsigned int reply_len;
|
||||
uchar reserved2;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReportOpcodesCMD_t;
|
||||
|
||||
//ReportOpcodesCMD_t ReportOpcodesCMD = { cmd : REPORT_OPCODES, reply_len: htonl(sizeof(report_opcode_result_t)) };
|
||||
|
||||
int ReportOpCodes(devhandle sgd, report_opcode_result_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
ReportOpcodesCMD_t ReportOpcodesCMD;
|
||||
|
||||
memset (list, 0, sizeof(report_opcode_result_t));
|
||||
ReportOpcodesCMD.cmd = REPORT_OPCODES;
|
||||
ReportOpcodesCMD.reply_len = htonl( sizeof(report_opcode_result_t));
|
||||
|
||||
ret = scsi_command(sgd, &ReportOpcodesCMD, sizeof(ReportOpcodesCMD_t), SG_DXFER_FROM_DEV, list, sizeof(report_opcode_result_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
DPRINTF("Report Luns: IOCTL");
|
||||
|
||||
list->length = ntohl(list->length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
#define READ_ATTRIBUTE 0x8c
|
||||
#define VOLUME_LIST 2
|
||||
#define PARTITION_LIST 3
|
||||
|
||||
typedef struct read_attribute_cmd {
|
||||
uchar cmd;
|
||||
|
||||
uchar action:5;
|
||||
uchar res:3;
|
||||
|
||||
uchar restricted[3];
|
||||
|
||||
uchar volume;
|
||||
uchar res2;
|
||||
uchar partition;
|
||||
|
||||
ushort attribute;
|
||||
unsigned int reply_len;
|
||||
uchar res3;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadAttributeCMD_t;
|
||||
|
||||
int CheckVolumes(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = VOLUME_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("Report Volumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int CheckPartitions(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = PARTITION_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("Report PARTITIONVolumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int UnitReady(devhandle sgd)
|
||||
{
|
||||
uchar cmd[6];
|
||||
uchar sensedat[32];
|
||||
int ret;
|
||||
|
||||
memset(cmd,0,sizeof(cmd));
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, NULL, 0, sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("UnitReady :");
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
450
util/baremetal/usb/scsi_cmds.h
Normal file
450
util/baremetal/usb/scsi_cmds.h
Normal file
|
@ -0,0 +1,450 @@
|
|||
#include "scsi_low.h"
|
||||
|
||||
typedef struct sense_data {
|
||||
uchar code;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:4;
|
||||
|
||||
uchar additional_code;
|
||||
uchar qualifier;
|
||||
|
||||
uchar res2[3];
|
||||
|
||||
uchar length;
|
||||
} __attribute__ ((packed)) sense_data_t;
|
||||
|
||||
typedef struct fixed_sense_data {
|
||||
uchar code:7;
|
||||
uchar valid:1;
|
||||
|
||||
uchar obs1;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:1;
|
||||
uchar ili:1;
|
||||
uchar eom:1;
|
||||
uchar mark:1;
|
||||
|
||||
unsigned int info;
|
||||
|
||||
uchar add_len;
|
||||
} __attribute__ ((packed)) fixed_sense_data_t;
|
||||
|
||||
typedef struct additional_fixed_data {
|
||||
unsigned int info;
|
||||
|
||||
uchar code;
|
||||
uchar qualifier;
|
||||
uchar fru;
|
||||
|
||||
uchar specific[3];
|
||||
} __attribute__ ((packed)) additional_fixed_data_t;
|
||||
|
||||
|
||||
void PrintSense(uchar *sense)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF("sense data ");
|
||||
for(i=0;i<32; i++)
|
||||
DPRINTF( ":%02x", sense[i]);
|
||||
DPRINTF( "\n\n");
|
||||
|
||||
if( (sense[0] & 0x7f) >=0x72) {
|
||||
sense_data_t *sd = (sense_data_t *) sense;
|
||||
uchar *pos = sense+sizeof(sense_data_t);
|
||||
uchar remaining = sd->length;
|
||||
int dlen;
|
||||
|
||||
DPRINTF( "code = %02x, key = %1x, additional = %02x, qual = %02x\n", sd->code, sd->sense_key, sd->additional_code, sd->qualifier);
|
||||
|
||||
while(remaining) {
|
||||
DPRINTF("type = %02x", pos[0]);
|
||||
dlen = pos[1];
|
||||
pos+=2;
|
||||
remaining -=2;
|
||||
|
||||
for(i=0; i<dlen; i++)
|
||||
DPRINTF( ": %02x", pos[i]);
|
||||
|
||||
DPRINTF("\n");
|
||||
pos+=i;
|
||||
remaining -=i;
|
||||
}
|
||||
|
||||
} else {
|
||||
fixed_sense_data_t *fd = (fixed_sense_data_t *) sense;
|
||||
uchar remaining = fd->add_len;
|
||||
additional_fixed_data_t *afd;
|
||||
|
||||
|
||||
DPRINTF("code = %02x key = %1x\n", fd->code, fd->sense_key);
|
||||
if(fd->mark)
|
||||
DPRINTF("filemark ");
|
||||
|
||||
if(fd->eom)
|
||||
DPRINTF(" End Of Media ");
|
||||
|
||||
if(fd->ili)
|
||||
DPRINTF("Illegal instruction");
|
||||
|
||||
DPRINTF(out,"\n");
|
||||
|
||||
if(fd->valid)
|
||||
DPRINTF("(valid) ");
|
||||
|
||||
DPRINTF("Info: %08x\n", ntohl(fd->info));
|
||||
|
||||
afd = (additional_fixed_data_t *) (sense + 8);
|
||||
|
||||
while(remaining) {
|
||||
DPRINTF( "command info = %08x\n", ntohl(afd->info));
|
||||
DPRINTF( "code = %02x, qual = %02x, fru = %02x\n", afd->code, afd->qualifier, afd->fru);
|
||||
DPRINTF( "sense key data = %02x:%02x:%02x\n\n", afd->specific[2], afd->specific[1], afd->specific[0]);
|
||||
|
||||
afd++;
|
||||
remaining -= sizeof(additional_fixed_data_t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef struct query_response {
|
||||
uchar type:5;
|
||||
uchar qualifier:3;
|
||||
|
||||
uchar reserved1:7;
|
||||
uchar removable:1;
|
||||
|
||||
uchar version;
|
||||
|
||||
uchar ResponseDataFormat:4; // should == 2
|
||||
uchar HiSup:1; // report luns cmd supported
|
||||
uchar NormACA:1;
|
||||
uchar obsolete:1;
|
||||
uchar aerc:1;
|
||||
|
||||
uchar AdditionalLength; // length of vendor specific data (beyond 96 bytes)
|
||||
|
||||
uchar reserved2:7;
|
||||
uchar sccs:1; // have raid controller
|
||||
|
||||
uchar addr16:1; //
|
||||
uchar obsolete2:2;
|
||||
uchar MChnger:1; // media changer
|
||||
uchar MultiP:1; // multi port
|
||||
uchar vs:1; // ???
|
||||
uchar EncServ:1; // enclosure service
|
||||
uchar BQue:1; // basic command queueing
|
||||
|
||||
uchar vs2:1;
|
||||
uchar CmdQue:1; // full command queueing
|
||||
uchar obsolete4:1;
|
||||
uchar linked:1;
|
||||
uchar sync:1;
|
||||
uchar wbus16:1; //
|
||||
uchar obsolete3:1;
|
||||
uchar RelAddr:1; // treletive addressing
|
||||
|
||||
char vendor[8];
|
||||
char product[16];
|
||||
char revision[4];
|
||||
char vendor_data[20];
|
||||
|
||||
uchar ius:1;
|
||||
uchar qas:1;
|
||||
uchar clocking:2; //
|
||||
uchar reserved3:4;
|
||||
|
||||
unsigned short version_desc[8];
|
||||
|
||||
char reserved4[21];
|
||||
} query_response_t;
|
||||
|
||||
typedef struct ReadBlockCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar reserved:2;
|
||||
uchar fua:1; // force unit access flush to media
|
||||
uchar dpo:1; // direct page out, do not cache
|
||||
uchar reserved2:3;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short block_count;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadBlockCMD_t ;
|
||||
|
||||
int ll_read_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
return(ret);
|
||||
|
||||
}
|
||||
|
||||
int ll_write_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = WRITE_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_TO_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct ReadLongCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar correct:1;
|
||||
uchar reserved:5;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short length;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadLongCMD_t ;
|
||||
|
||||
int ll_read_long(devhandle sgd, char *buffer, int blocknum, int size)
|
||||
{
|
||||
int ret;
|
||||
ReadLongCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_LONG;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.length = htons(size);
|
||||
|
||||
ret = scsi_command( sgd, &rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, size, sensedat, sizeof(sensedat));
|
||||
return(ret);
|
||||
}
|
||||
|
||||
unsigned char ReadCapacityCMD[10] = { READ_CAPACITY, 0, 0,0,0,0, 0,0,0, 0};
|
||||
|
||||
struct ReadCapacityResponse {
|
||||
unsigned int block_address;
|
||||
unsigned int block_length;
|
||||
};
|
||||
|
||||
int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len)
|
||||
{
|
||||
int ret;
|
||||
struct ReadCapacityResponse response;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, ReadCapacityCMD, sizeof(ReadCapacityCMD), SG_DXFER_FROM_DEV, &response, sizeof(response), sensedat, sizeof(sensedat) );
|
||||
if(ret<0)
|
||||
perror("get capacity: IOCTL");
|
||||
|
||||
|
||||
*block_count = ntohl(response.block_address) +1;
|
||||
*blk_len = ntohl(response.block_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#define INQ_REP_LEN 96
|
||||
unsigned char InquiryCMD[6] = { INQUIRY, 0, 0, 0, INQ_REP_LEN, 0};
|
||||
|
||||
int query(devhandle sgd, query_response_t *qr)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, InquiryCMD, sizeof(InquiryCMD), SG_DXFER_FROM_DEV, qr, sizeof(query_response_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
perror("query: IOCTL");
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct lun_list {
|
||||
unsigned int list_length;
|
||||
unsigned int reserved;
|
||||
unsigned long long lun[16];
|
||||
} lun_list_t;
|
||||
|
||||
#define REPORT_LUNS 0xa0
|
||||
unsigned char ReportLunsCMD[12] = { REPORT_LUNS, 0, 2, 0, 0, 0, 0, 0, 0, 128, 0, 0 };
|
||||
|
||||
int ReportLUNS(devhandle sgd, lun_list_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
memset (list, 0, sizeof(lun_list_t));
|
||||
ret = scsi_command(sgd, ReportLunsCMD, sizeof(ReportLunsCMD), SG_DXFER_FROM_DEV, list, sizeof(lun_list_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
perror("Report Luns: IOCTL");
|
||||
|
||||
list->list_length = ntohl(list->list_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct command_descriptor {
|
||||
uchar opcode;
|
||||
uchar reserved;
|
||||
unsigned short service_action;
|
||||
uchar reserved2;
|
||||
|
||||
uchar action_valid:1;
|
||||
uchar reserved3:7;
|
||||
|
||||
unsigned short cdb_len;
|
||||
} __attribute__ ((packed)) command_descriptor_t;
|
||||
|
||||
typedef struct report_opcodes_result {
|
||||
unsigned long length;
|
||||
|
||||
command_descriptor_t command[256];
|
||||
} __attribute__ ((packed)) report_opcode_result_t;
|
||||
|
||||
|
||||
#define REPORT_OPCODES 0xa3
|
||||
|
||||
typedef struct report_opcodes_cmd {
|
||||
uchar cmd;
|
||||
uchar reserved[5];
|
||||
unsigned int reply_len;
|
||||
uchar reserved2;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReportOpcodesCMD_t;
|
||||
|
||||
//ReportOpcodesCMD_t ReportOpcodesCMD = { cmd : REPORT_OPCODES, reply_len: htonl(sizeof(report_opcode_result_t)) };
|
||||
|
||||
int ReportOpCodes(devhandle sgd, report_opcode_result_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
ReportOpcodesCMD_t ReportOpcodesCMD;
|
||||
|
||||
memset (list, 0, sizeof(report_opcode_result_t));
|
||||
ReportOpcodesCMD.cmd = REPORT_OPCODES;
|
||||
ReportOpcodesCMD.reply_len = htonl( sizeof(report_opcode_result_t));
|
||||
|
||||
ret = scsi_command(sgd, &ReportOpcodesCMD, sizeof(ReportOpcodesCMD_t), SG_DXFER_FROM_DEV, list, sizeof(report_opcode_result_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0)
|
||||
perror("Report Luns: IOCTL");
|
||||
|
||||
list->length = ntohl(list->length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
#define READ_ATTRIBUTE 0x8c
|
||||
#define VOLUME_LIST 2
|
||||
#define PARTITION_LIST 3
|
||||
|
||||
typedef struct read_attribute_cmd {
|
||||
uchar cmd;
|
||||
|
||||
uchar action:5;
|
||||
uchar res:3;
|
||||
|
||||
uchar restricted[3];
|
||||
|
||||
uchar volume;
|
||||
uchar res2;
|
||||
uchar partition;
|
||||
|
||||
ushort attribute;
|
||||
unsigned int reply_len;
|
||||
uchar res3;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadAttributeCMD_t;
|
||||
|
||||
int CheckVolumes(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = VOLUME_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
perror("Report Volumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int CheckPartitions(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = PARTITION_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
perror("Report PARTITIONVolumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int UnitReady(devhandle sgd)
|
||||
{
|
||||
uchar cmd[6];
|
||||
uchar sensedat[32];
|
||||
int ret;
|
||||
|
||||
memset(cmd,0,sizeof(cmd));
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, NULL, 0, sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
perror("UnitReady :");
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
1663
util/baremetal/usb/uhci.c
Normal file
1663
util/baremetal/usb/uhci.c
Normal file
File diff suppressed because it is too large
Load diff
334
util/baremetal/usb/uhci.h
Normal file
334
util/baremetal/usb/uhci.h
Normal file
|
@ -0,0 +1,334 @@
|
|||
#ifndef UHCI_H
|
||||
#define UHCI_H
|
||||
|
||||
/*
|
||||
* The link pointer is multi use. Some fields are valid only for some uses.
|
||||
* In other cases, they must be 0
|
||||
*
|
||||
*/
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
#ifndef KERNEL
|
||||
typedef unsigned short ushort;
|
||||
#endif
|
||||
|
||||
#define MAX_POLLDEV 10
|
||||
|
||||
#define MAX_TRANSACTIONS 10
|
||||
#define MAX_QUEUEHEAD 255
|
||||
#define MAX_TD 1024
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define virt_to_bus
|
||||
#define bus_to_virt
|
||||
#endif
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define LINK_ADDR(x) ((unsigned int)x >> 4)
|
||||
#define MEM_ADDR(x) (void *) ( ((unsigned int) (x))<<4)
|
||||
#else
|
||||
#define LINK_ADDR(x) ( virt_to_bus(x) >> 4)
|
||||
#define MEM_ADDR(x) (void *) ( bus_to_virt( ((unsigned int) (x)) <<4) )
|
||||
#endif
|
||||
|
||||
typedef struct link_pointer {
|
||||
unsigned long terminate:1;
|
||||
unsigned long queue:1;
|
||||
unsigned long depth:1;
|
||||
unsigned long reserved:1;
|
||||
unsigned long link:28;
|
||||
} __attribute__ ((packed)) link_pointer_t;
|
||||
|
||||
#define SETUP_TOKEN 0x2d
|
||||
#define IN_TOKEN 0x69
|
||||
#define OUT_TOKEN 0xe1
|
||||
|
||||
#define CTRL_RETRIES 3
|
||||
#define CONTROL_STS_RETRIES 0
|
||||
|
||||
// Some control message bmRequestType defines
|
||||
#define CTRL_DEVICE 0
|
||||
#define CONTROL_INTERFACE 1
|
||||
#define CONTROL_ENDPOINT 2
|
||||
#define CONTROL_OTHER 3
|
||||
#define CONTROL_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define CONTROL_TYPE_STD 0
|
||||
#define CONTROL_TYPE_CLASS 0x20
|
||||
#define CONTROL_CLASS_VENDOR 0x40
|
||||
#define CONTROL_CLASS_MASK 0x60
|
||||
|
||||
#define CONTROL_OUT 0
|
||||
#define CONTROL_IN 0x80
|
||||
#define CONTROL_DIR_MASK 0x80
|
||||
|
||||
// bRequest values
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
#define SYNC_FRAME 12
|
||||
|
||||
// some port features
|
||||
#define PORT_CONNECTION 0
|
||||
#define PORT_ENABLE 1
|
||||
#define PORT_SUSPEND 2
|
||||
#define PORT_OVER_CURRENT 3
|
||||
#define PORT_RESET 4
|
||||
#define PORT_POWER 8
|
||||
#define PORT_LOW_SPEED 9
|
||||
#define C_PORT_CONNECTION 16
|
||||
#define C_PORT_ENABLE 17
|
||||
#define C_PORT_SUSPEND 18
|
||||
#define C_PORT_OVER_CURRENT 19
|
||||
#define C_PORT_RESET 20
|
||||
|
||||
// descriptor types
|
||||
#define DEVICE_DESC 1
|
||||
#define CONFIGURATION_DESC 2
|
||||
#define STRING_DESC 3
|
||||
#define INTERFACE_DESC 4
|
||||
#define ENDPOINT_DESC 5
|
||||
#define OTHERSPEED_DESC 7
|
||||
#define POWER_DESC 8
|
||||
|
||||
// features
|
||||
#define FEATURE_HALT 0
|
||||
|
||||
typedef struct td {
|
||||
|
||||
link_pointer_t link;
|
||||
|
||||
unsigned long actual:11; // actual length
|
||||
unsigned long reserved2:5;
|
||||
|
||||
// status/error flags
|
||||
unsigned long res1:1;
|
||||
unsigned long bitstuff:1;
|
||||
unsigned long crc:1;
|
||||
unsigned long nak:1;
|
||||
unsigned long babble:1;
|
||||
unsigned long buffer_error:1;
|
||||
unsigned long stall:1;
|
||||
unsigned long active:1;
|
||||
|
||||
unsigned long interrupt:1; // interrupt on complete
|
||||
unsigned long isochronous:1;
|
||||
unsigned long lowspeed:1;
|
||||
unsigned long retrys:2;
|
||||
unsigned long detect_short:1;
|
||||
unsigned long reserved3:2;
|
||||
|
||||
unsigned long packet_type:8; // one of in (0x69), out (0xe1) or setup (0x2d)
|
||||
unsigned long device_addr:7;
|
||||
unsigned long endpoint:4;
|
||||
unsigned long data_toggle:1;
|
||||
unsigned long reserved:1;
|
||||
unsigned long max_transfer:11; // misnamed. Desired length might be better
|
||||
|
||||
void *buffer;
|
||||
unsigned long data[4]; // free use by driver
|
||||
} __attribute__ ((packed)) td_t;
|
||||
|
||||
typedef struct queue_head {
|
||||
link_pointer_t bredth; // depth must = 0
|
||||
link_pointer_t depth; // depth may vary randomly, ignore
|
||||
unsigned long int udata[2];
|
||||
} __attribute__ ((packed)) queue_head_t;
|
||||
|
||||
typedef struct transaction {
|
||||
queue_head_t *qh;
|
||||
td_t *td_list;
|
||||
struct transaction *next;
|
||||
} transaction_t;
|
||||
|
||||
#define MAX_USB_DEV 127
|
||||
#define MAX_EP 8
|
||||
|
||||
typedef struct usbdev {
|
||||
unsigned short port;
|
||||
uchar address;
|
||||
uchar controller;
|
||||
uchar class;
|
||||
uchar subclass;
|
||||
uchar protocol;
|
||||
uchar bulk_in;
|
||||
uchar bulk_out;
|
||||
uchar interrupt;
|
||||
uchar lowspeed;
|
||||
uchar toggle[MAX_EP];
|
||||
unsigned short max_packet[MAX_EP];
|
||||
void *private;
|
||||
} usbdev_t;
|
||||
|
||||
|
||||
typedef struct device_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bcdVersion[2];
|
||||
uchar Class;
|
||||
uchar SubClass;
|
||||
uchar protocol;
|
||||
uchar max_packet;
|
||||
|
||||
unsigned short idVendor;
|
||||
unsigned short idProduct;
|
||||
|
||||
uchar bcdDevice[2];
|
||||
uchar iManufacturor;
|
||||
uchar iProduct;
|
||||
uchar iSerial;
|
||||
uchar bNumConfig;
|
||||
} __attribute__ ((packed)) device_descriptor_t;
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
|
||||
typedef struct config_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
unsigned short wTotalLength;
|
||||
uchar bNumInterfaces;
|
||||
uchar bConfigurationValue;
|
||||
uchar iConfiguration;
|
||||
|
||||
uchar bmAttributes;
|
||||
uchar bMaxPower;
|
||||
} __attribute__ ((packed)) config_descriptor_t;
|
||||
|
||||
typedef struct interface_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bInterfaceNumber;
|
||||
uchar bAlternateSetting;
|
||||
|
||||
uchar bNumEndpoints;
|
||||
uchar bInterfaceClass;
|
||||
uchar bInterfaceSubClass;
|
||||
uchar bInterfaceProtocol;
|
||||
uchar iInterface;
|
||||
} __attribute__ ((packed)) interface_descriptor_t;
|
||||
|
||||
typedef struct endpoint_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bEndpointAddress;
|
||||
uchar bmAttributes;
|
||||
unsigned short wMaxPacketSize;
|
||||
uchar bInterval;
|
||||
} __attribute__ ((packed)) endpoint_descriptor_t;
|
||||
|
||||
typedef struct ctrl_msg {
|
||||
uchar bmRequestType;
|
||||
uchar bRequest;
|
||||
unsigned short wValue;
|
||||
unsigned short wIndex;
|
||||
unsigned short wLength;
|
||||
} __attribute__ ((packed)) ctrl_msg_t;
|
||||
|
||||
// Some descriptors for hubs, will be moved later
|
||||
typedef struct hub_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bNbrPorts;
|
||||
ushort wHubCharacteristics;
|
||||
uchar bPwrOn2PwrGood;
|
||||
uchar bHubCntrCurrent;
|
||||
|
||||
uchar DeviceRemovable; // assume bNbrPorts <=8
|
||||
uchar PortPwrCntrMask;
|
||||
} __attribute__ ((packed)) hub_descriptor_t;
|
||||
|
||||
//#####################################################
|
||||
int wait_head( queue_head_t *head, int count);
|
||||
|
||||
extern queue_head_t *free_qh;
|
||||
extern queue_head_t *queue_heads;
|
||||
|
||||
queue_head_t *new_queue_head(void);
|
||||
void free_queue_head( queue_head_t *qh);
|
||||
void init_qh(void);
|
||||
|
||||
extern td_t *free_td_list;
|
||||
extern td_t *tds;
|
||||
|
||||
void init_td(void);
|
||||
td_t *new_td(void);
|
||||
td_t *find_last_td(td_t *td);
|
||||
void free_td( td_t *td);
|
||||
link_pointer_t *queue_end( queue_head_t *queue);
|
||||
void add_td( queue_head_t *head, td_t *td);
|
||||
|
||||
extern transaction_t transactions[MAX_TRANSACTIONS];
|
||||
extern transaction_t *free_transactions;
|
||||
|
||||
void init_transactions(void);
|
||||
void free_transaction( transaction_t *trans );
|
||||
transaction_t *new_transaction(td_t *td);
|
||||
transaction_t *add_transaction( transaction_t *trans, td_t *td);
|
||||
|
||||
extern link_pointer_t *frame_list[];
|
||||
|
||||
void init_framelist(uchar dev);
|
||||
|
||||
extern unsigned int hc_base[];
|
||||
#define USBCMD hc_base
|
||||
#define USBSTS (hc_base + 0x02)
|
||||
#define USBINTR (hc_base + 0x04)
|
||||
#define FRNUM ( hc_base + 0x06)
|
||||
#define FLBASE ( hc_base + 0x08)
|
||||
#define SOFMOD ( hc_base + 0x0c)
|
||||
#define PORTSC1 ( hc_base + 0x10)
|
||||
#define PORTSC2 ( hc_base + 0x12)
|
||||
|
||||
#define USBCMDRUN 0x01
|
||||
|
||||
#define USBSTSHALTED 0x20
|
||||
|
||||
void hc_reset(uchar dev);
|
||||
int hc_stop(void);
|
||||
int hc_start(uchar dev);
|
||||
int hc_init(uchar dev, uchar function);
|
||||
|
||||
extern queue_head_t *sched_queue[];
|
||||
|
||||
void init_sched(uchar dev);
|
||||
void uhci_init(void);
|
||||
int poll_queue_head( queue_head_t *qh);
|
||||
int wait_queue_complete( queue_head_t *qh);
|
||||
|
||||
extern int next_usb_dev;
|
||||
usbdev_t usb_device[MAX_USB_DEV];
|
||||
|
||||
|
||||
extern int num_polls;
|
||||
extern int (*devpoll[MAX_POLLDEV])(uchar);
|
||||
extern uchar parm[MAX_POLLDEV];
|
||||
|
||||
void init_devices(void);
|
||||
transaction_t *_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
transaction_t *ctrl_msg(uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, uchar *data);
|
||||
int schedule_transaction( uchar dev, transaction_t *trans);
|
||||
int wait_transaction( transaction_t *trans);
|
||||
void unlink_transaction( uchar dev, transaction_t *trans);
|
||||
int bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
int usb_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, void *data);
|
||||
inline int set_address(uchar address);
|
||||
inline int clear_stall(uchar device, uchar endpoint);
|
||||
int configure_device(unsigned short port, uchar controller, unsigned int lowspeed);
|
||||
#endif
|
151
util/baremetal/usb/usb_scsi_low.c
Normal file
151
util/baremetal/usb/usb_scsi_low.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
#include "usb_scsi_low.h"
|
||||
|
||||
//#include <scsi/scsi.h>
|
||||
|
||||
#define SG_DXFER_FROM_DEV -3
|
||||
#define SG_DXFER_TO_DEV -2
|
||||
|
||||
#define REQUEST_SENSE 0x03
|
||||
|
||||
#define CBW_SIG 43425355
|
||||
|
||||
typedef struct usb_cbw {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int transfer_len; // this is exclusive of cbw and csw
|
||||
|
||||
uchar res1:7;
|
||||
uchar direction:1; // 1 = device to host (read)
|
||||
|
||||
uchar lun:4;
|
||||
uchar res:4;
|
||||
|
||||
uchar cbw_len:5; // the length of the SCSI command
|
||||
uchar res3:3;
|
||||
|
||||
uchar scsi_cmd[16];
|
||||
} __attribute__ ((packed)) usb_cbw_t;
|
||||
|
||||
#define CSW_SIG 53425355
|
||||
|
||||
typedef struct usb_csw {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int residue;
|
||||
uchar status;
|
||||
} __attribute__ ((packed)) usb_csw_t;
|
||||
|
||||
|
||||
int scsi_command( uchar device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, char *sense_data, int sense_len)
|
||||
{
|
||||
usb_cbw_t cbw;
|
||||
usb_csw_t csw;
|
||||
int ret;
|
||||
|
||||
memset(&cbw,0,sizeof(usb_cbw_t));
|
||||
memset(&csw,0,sizeof(usb_csw_t));
|
||||
|
||||
cbw.signature = CBW_SIG;
|
||||
cbw.tag = 777;
|
||||
|
||||
memcpy(cbw.scsi_cmd, cmd, cmd_len);
|
||||
cbw.cbw_len = cmd_len;
|
||||
|
||||
if(direction == SG_DXFER_FROM_DEV)
|
||||
cbw.direction=1;
|
||||
|
||||
cbw.transfer_len = data_len;
|
||||
|
||||
ret = bulk_transfer(device, 2, sizeof(cbw), (uchar *) &cbw);
|
||||
if(ret<0)
|
||||
DPRINTF("ERROR:Bulk write:\n");
|
||||
|
||||
if(data_len)
|
||||
if(cbw.direction) {
|
||||
// DPRINTF("scsi_command reading %u bytes\n", data_len);
|
||||
ret = bulk_transfer(device, 0x81, data_len, data);
|
||||
// DPRINTF("scsi_command read %u bytes\n", ret);
|
||||
if(ret<0 || ret <data_len)
|
||||
DPRINTF("ERROR:Bulk read data ret = %d\n", ret);
|
||||
} else {
|
||||
// DPRINTF("scsi_command writing %u bytes\n", data_len);
|
||||
ret = bulk_transfer(device, 0x2, data_len, data);
|
||||
// DPRINTF("scsi_command wrote %u bytes\n", ret);
|
||||
if(ret<0)
|
||||
DPRINTF("ERROR:Bulk write data\n");
|
||||
}
|
||||
|
||||
// DPRINTF("scsi_command fetching csw\n");
|
||||
ret = bulk_transfer(device, 0x81, sizeof(csw), (uchar *) &csw);
|
||||
// DPRINTF("scsi_command csw is %d bytes\n", ret);
|
||||
if(ret<0 || ret < sizeof(csw)) {
|
||||
DPRINTF("ERROR: Bulk read CSW ret = %d\n", ret);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(csw.status) {
|
||||
DPRINTF("CSW: residue = %08x, status = %02x\n", csw.residue, csw.status);
|
||||
DPRINTF("Getting sense data\n");
|
||||
request_sense( device, sense_data, sense_len);
|
||||
return(-csw.status);
|
||||
}
|
||||
|
||||
return(data_len - csw.residue);
|
||||
}
|
||||
|
||||
int request_sense( uchar device, char *sense_data, int len)
|
||||
{
|
||||
usb_cbw_t cbw;
|
||||
usb_csw_t csw;
|
||||
int ret;
|
||||
|
||||
memset(&cbw,0,sizeof(usb_cbw_t));
|
||||
memset(&csw,0,sizeof(usb_csw_t));
|
||||
|
||||
cbw.signature = CBW_SIG;
|
||||
cbw.tag = 666;
|
||||
|
||||
cbw.scsi_cmd[0] = REQUEST_SENSE;
|
||||
cbw.scsi_cmd[4] = len;
|
||||
cbw.cbw_len = 6;
|
||||
cbw.direction=1;
|
||||
cbw.transfer_len = len;
|
||||
|
||||
ret = bulk_transfer(device, 2, sizeof(usb_cbw_t), (uchar *) &cbw);
|
||||
if(ret<0 || ret < sizeof(usb_cbw_t))
|
||||
DPRINTF("ERROR: sense Bulk write ret = %d\n", ret);
|
||||
|
||||
|
||||
ret = bulk_transfer(device, 0x81, len, sense_data);
|
||||
if(ret<0 || ret < len)
|
||||
DPRINTF("ERROR: sense Bulk read data ret = %d\n", ret);
|
||||
|
||||
ret = bulk_transfer(device, 0x81, sizeof(usb_csw_t), (uchar *) &csw);
|
||||
if(ret<0 || ret < sizeof(usb_csw_t))
|
||||
DPRINTF("ERROR: sense Bulk read CSW ret = %d\n", ret);
|
||||
|
||||
return(-csw.status);
|
||||
}
|
10
util/baremetal/usb/usb_scsi_low.h
Normal file
10
util/baremetal/usb/usb_scsi_low.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef _USB_SCSI_LOW_H
|
||||
#define _USB_SCSI_LOW_H
|
||||
|
||||
#define SG_DXFER_FROM_DEV -3
|
||||
#define SG_DXFER_TO_DEV -2
|
||||
|
||||
int scsi_command( unsigned char device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, char *sense_data, int sense_len);
|
||||
int request_sense( unsigned char device, char *sense_data, int len);
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue