Initial checkin of polling USB stack

This commit is contained in:
Steven James 2004-01-30 00:08:45 +00:00
parent edefdfccab
commit 803eeae5d2
16 changed files with 4127 additions and 0 deletions

View 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.

View 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

View 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
View 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);
}

View 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

View 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) }
}

View 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
View 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);
}

View 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);
}

View 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

View 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);
}

View 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

File diff suppressed because it is too large Load diff

334
util/baremetal/usb/uhci.h Normal file
View 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

View 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);
}

View 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