From ec92a0d748044d0ac60d662890f0c00475d854a2 Mon Sep 17 00:00:00 2001 From: wdenk Date: Tue, 27 Aug 2002 09:44:07 +0000 Subject: [PATCH] Das U-Boot: Universal Boot Loader --- common/cmd_reginfo.c | 180 +++++++++++++ common/cmd_scsi.c | 597 +++++++++++++++++++++++++++++++++++++++++++ common/cmd_usb.c | 595 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1372 insertions(+) create mode 100644 common/cmd_reginfo.c create mode 100644 common/cmd_scsi.c create mode 100644 common/cmd_usb.c diff --git a/common/cmd_reginfo.c b/common/cmd_reginfo.c new file mode 100644 index 0000000000..1986c22579 --- /dev/null +++ b/common/cmd_reginfo.c @@ -0,0 +1,180 @@ +/* + * (C) Copyright 2000 + * Subodh Nijsure, SkyStream Networks, snijsure@skystream.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#if defined(CONFIG_8xx) +#include +#elif defined (CONFIG_405GP) +#include +#endif +#if (CONFIG_COMMANDS & CFG_CMD_REGINFO) + +int do_reginfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +#if defined(CONFIG_8xx) + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + volatile sysconf8xx_t *sysconf = &immap->im_siu_conf; + volatile sit8xx_t *timers = &immap->im_sit; + + /* Hopefully more PowerPC knowledgable people will add code to display + * other useful registers + */ + + printf("\nSystem Configuration registers\n"); + + printf("\tIMMR\t0x%08X\n", get_immr(0)); + + printf("\tSIUMCR\t0x%08X", sysconf->sc_siumcr); + printf("\tSYPCR\t0x%08X\n",sysconf->sc_sypcr); + + printf("\tSWT\t0x%08X", sysconf->sc_swt); + printf("\tSWSR\t0x%04X\n", sysconf->sc_swsr); + + printf("\tSIPEND\t0x%08X\tSIMASK\t0x%08X\n", + sysconf->sc_sipend, sysconf->sc_simask); + printf("\tSIEL\t0x%08X\tSIVEC\t0x%08X\n", + sysconf->sc_siel, sysconf->sc_sivec); + printf("\tTESR\t0x%08X\tSDCR\t0x%08X\n", + sysconf->sc_tesr, sysconf->sc_sdcr); + + printf("Memory Controller Registers\n"); + + printf("\tBR0\t0x%08X\tOR0\t0x%08X \n", memctl->memc_br0, memctl->memc_or0); + printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", memctl->memc_br1, memctl->memc_or1); + printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", memctl->memc_br2, memctl->memc_or2); + printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", memctl->memc_br3, memctl->memc_or3); + printf("\tBR4\t0x%08X\tOR4\t0x%08X \n", memctl->memc_br4, memctl->memc_or4); + printf("\tBR5\t0x%08X\tOR5\t0x%08X \n", memctl->memc_br5, memctl->memc_or5); + printf("\tBR6\t0x%08X\tOR6\t0x%08X \n", memctl->memc_br6, memctl->memc_or6); + printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", memctl->memc_br7, memctl->memc_or7); + printf("\n"); + + printf("\tmamr\t0x%08X\tmbmr\t0x%08X \n", + memctl->memc_mamr, memctl->memc_mbmr ); + printf("\tmstat\t0x%08X\tmptpr\t0x%08X \n", + memctl->memc_mstat, memctl->memc_mptpr ); + printf("\tmdr\t0x%08X \n", memctl->memc_mdr); + + printf("\nSystem Integration Timers\n"); + printf("\tTBSCR\t0x%08X\tRTCSC\t0x%08X \n", + timers->sit_tbscr, timers->sit_rtcsc); + printf("\tPISCR\t0x%08X \n", timers->sit_piscr); + + /* + * May be some CPM info here? + */ + +/* DBU[dave@cray.com] For the CRAY-L1, but should be generically 405gp */ +#elif defined (CONFIG_405GP) + printf("\n405GP registers; MSR=%x\n",mfmsr()); + printf ("\nUniversal Interrupt Controller Regs\n" +"uicsr uicsrs uicer uiccr uicpr uictr uicmsr uicvr uicvcr" +"\n" +"%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", + mfdcr(uicsr), + mfdcr(uicsrs), + mfdcr(uicer), + mfdcr(uiccr), + mfdcr(uicpr), + mfdcr(uictr), + mfdcr(uicmsr), + mfdcr(uicvr), + mfdcr(uicvcr)); + + printf ("\nMemory (SDRAM) Configuration\n" +"besra besrsa besrb besrsb bear mcopt1 rtr pmit\n"); + + mtdcr(memcfga,mem_besra); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_besrsa); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_besrb); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_besrsb); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_bear); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_mcopt1); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_rtr); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_pmit); printf ("%08x ", mfdcr(memcfgd)); + + printf ("\n" +"mb0cf mb1cf mb2cf mb3cf sdtr1 ecccf eccerr\n"); + mtdcr(memcfga,mem_mb0cf); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_mb1cf); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_mb2cf); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_mb3cf); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_sdtr1); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_ecccf); printf ("%08x ", mfdcr(memcfgd)); + mtdcr(memcfga,mem_eccerr); printf ("%08x ", mfdcr(memcfgd)); + + printf ("\n\n" +"DMA Channels\n" +"dmasr dmasgc dmaadr\n" "%08x %08x %08x\n" +"dmacr_0 dmact_0 dmada_0 dmasa_0 dmasb_0\n" "%08x %08x %08x %08x %08x\n" +"dmacr_1 dmact_1 dmada_1 dmasa_1 dmasb_1\n" "%08x %08x %08x %08x %08x\n", +mfdcr(dmasr), mfdcr(dmasgc),mfdcr(dmaadr), +mfdcr(dmacr0), mfdcr(dmact0),mfdcr(dmada0), mfdcr(dmasa0), mfdcr(dmasb0), +mfdcr(dmacr1), mfdcr(dmact1),mfdcr(dmada1), mfdcr(dmasa1), mfdcr(dmasb1)); + + printf ( +"dmacr_2 dmact_2 dmada_2 dmasa_2 dmasb_2\n" "%08x %08x %08x %08x %08x\n" +"dmacr_3 dmact_3 dmada_3 dmasa_3 dmasb_3\n" "%08x %08x %08x %08x %08x\n", +mfdcr(dmacr2), mfdcr(dmact2),mfdcr(dmada2), mfdcr(dmasa2), mfdcr(dmasb2), +mfdcr(dmacr3), mfdcr(dmact3),mfdcr(dmada3), mfdcr(dmasa3), mfdcr(dmasb3) ); + + printf ("\n" +"External Bus\n" +"pbear pbesr0 pbesr1 epcr\n"); + mtdcr(ebccfga,pbear); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pbesr0); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pbesr1); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,epcr); printf ("%08x ", mfdcr(ebccfgd)); + + printf ("\n" +"pb0cr pb0ap pb1cr bp1ap pb2cr pb2ap pb3cr pb3ap\n"); + mtdcr(ebccfga,pb0cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb0ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb1cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb1ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb2cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb2ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb3cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb3ap); printf ("%08x ", mfdcr(ebccfgd)); + + printf ("\n" +"pb4cr pb4ap pb5cr bp5ap pb6cr pb6ap pb7cr pb7ap\n"); + mtdcr(ebccfga,pb4cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb4ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb5cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb5ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb6cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb6ap); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb7cr); printf ("%08x ", mfdcr(ebccfgd)); + mtdcr(ebccfga,pb7ap); printf ("%08x ", mfdcr(ebccfgd)); + + printf ("\n\n"); +#endif /*(CONFIG_405GP)*/ + + return 0; +} + +#endif /* CONFIG_8xx && CFG_CMD_REGINFO */ diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c new file mode 100644 index 0000000000..9b5c69b32b --- /dev/null +++ b/common/cmd_scsi.c @@ -0,0 +1,597 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * + */ + +/* + * SCSI support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef SCSI_DEBUG + +#ifdef SCSI_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_SCSI) + +#ifdef CONFIG_SCSI_SYM53C8XX +#define SCSI_VEND_ID 0x1000 +#ifndef CONFIG_SCSI_DEV_ID +#define SCSI_DEV_ID 0x0001 +#else +#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID +#endif +#else +#error CONFIG_SCSI_SYM53C8XX must be defined +#endif + + +static ccb tempccb; /* temporary scsi command buffer */ + +static unsigned char tempbuff[512]; /* temporary data buffer */ + +static int scsi_max_devs; /* number of highest available scsi device */ + +static int scsi_curr_dev; /* current device */ + +static block_dev_desc_t scsi_dev_desc[CFG_SCSI_MAX_DEVICE]; + +/******************************************************************************** + * forward declerations of some Setup Routines + */ +void scsi_setup_test_unit_ready(ccb * pccb); +void scsi_setup_read_capacity(ccb * pccb); +void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks); +void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks); +void scsi_setup_inquiry(ccb * pccb); +void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len); + + +ulong scsi_read(int device, ulong blknr, ulong blkcnt, ulong *buffer); + + +/********************************************************************************* + * (re)-scan the scsi bus and reports scsi device info + * to the user if mode = 1 + */ +void scsi_scan(int mode) +{ + unsigned char i,perq,modi,lun; + unsigned long capacity,blksz; + ccb* pccb=(ccb *)&tempccb; + + if(mode==1) { + printf("scanning bus for devices...\n"); + } + for(i=0;itarget=i; + for(lun=0;lunlun=lun; + pccb->pdata=(unsigned char *)&tempbuff; + pccb->datalen=512; + scsi_setup_inquiry(pccb); + if(scsi_exec(pccb)!=TRUE) { + if(pccb->contr_stat==SCSI_SEL_TIME_OUT) { + PRINTF("Selection timeout ID %d\n",pccb->target); + continue; /* selection timeout => assuming no device present */ + } + scsi_print_error(pccb); + continue; + } + perq=tempbuff[0]; + modi=tempbuff[1]; + if((perq & 0x1f)==0x1f) { + continue; /* skip unknown devices */ + } + if((modi&0x80)==0x80) /* drive is removable */ + scsi_dev_desc[scsi_max_devs].removable=TRUE; + /* get info for this device */ + scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].vendor[0],&tempbuff[8],8); + scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].product[0],&tempbuff[16],16); + scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].revision[0],&tempbuff[32],4); + scsi_dev_desc[scsi_max_devs].target=pccb->target; + scsi_dev_desc[scsi_max_devs].lun=pccb->lun; + + pccb->datalen=0; + scsi_setup_test_unit_ready(pccb); + if(scsi_exec(pccb)!=TRUE) { + if(scsi_dev_desc[scsi_max_devs].removable==TRUE) { + scsi_dev_desc[scsi_max_devs].type=perq; + goto removable; + } + scsi_print_error(pccb); + continue; + } + pccb->datalen=8; + scsi_setup_read_capacity(pccb); + if(scsi_exec(pccb)!=TRUE) { + scsi_print_error(pccb); + continue; + } + capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)| + ((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]); + blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)| + ((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]); + scsi_dev_desc[scsi_max_devs].lba=capacity; + scsi_dev_desc[scsi_max_devs].blksz=blksz; + scsi_dev_desc[scsi_max_devs].type=perq; + init_part(&scsi_dev_desc[scsi_max_devs]); +removable: + if(mode==1) { + printf (" Device %d: ", scsi_max_devs); + dev_print(&scsi_dev_desc[scsi_max_devs]); + } /* if mode */ + scsi_max_devs++; + } /* next LUN */ + } + if(scsi_max_devs>0) + scsi_curr_dev=0; + else + scsi_curr_dev=-1; +} + + + +void scsi_init(void) +{ + int busdevfunc; + + busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */ + if(busdevfunc==-1) { + printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID); + return; + } +#ifdef DEBUG + else { + printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7); + } +#endif + scsi_low_level_init(busdevfunc); + scsi_scan(1); +} + +block_dev_desc_t * scsi_get_dev(int dev) +{ + return((block_dev_desc_t *)&scsi_dev_desc[dev]); +} + + + +/****************************************************************************** + * scsi boot command intepreter. Derived from diskboot + */ +int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *boot_device = NULL; + char *ep; + int dev, part = 0; + ulong cnt; + ulong addr; + disk_partition_t info; + image_header_t *hdr; + int rcode = 0; + + switch (argc) { + case 1: + addr = CFG_LOAD_ADDR; + boot_device = getenv ("bootdevice"); + break; + case 2: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = getenv ("bootdevice"); + break; + case 3: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + break; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (!boot_device) { + puts ("\n** No boot device **\n"); + return 1; + } + + dev = simple_strtoul(boot_device, &ep, 16); + printf("booting from dev %d\n",dev); + if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) { + printf ("\n** Device %d not available\n", dev); + return 1; + } + + if (*ep) { + if (*ep != ':') { + puts ("\n** Invalid boot device, use `dev[:part]' **\n"); + return 1; + } + part = simple_strtoul(++ep, NULL, 16); + } + if (get_partition_info (&scsi_dev_desc[dev], part, &info)) { + printf("error reading partinfo\n"); + return 1; + } + if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) { + printf ("\n** Invalid partition type \"%.32s\"" + " (expect \"" BOOT_PART_TYPE "\")\n", + info.type); + return 1; + } + + printf ("\nLoading from SCSI device %d, partition %d: " + "Name: %.32s Type: %.32s\n", + dev, part, info.name, info.type); + + PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n", + info.start, info.size, info.blksz); + + if (scsi_read (dev, info.start, 1, (ulong *)addr) != 1) { + printf ("** Read error on %d:%d\n", dev, part); + return 1; + } + + hdr = (image_header_t *)addr; + + if (hdr->ih_magic == IH_MAGIC) { + + print_image_hdr (hdr); + cnt = (hdr->ih_size + sizeof(image_header_t)); + cnt += info.blksz - 1; + cnt /= info.blksz; + cnt -= 1; + } else { + printf("\n** Bad Magic Number **\n"); + return 1; + } + + if (scsi_read (dev, info.start+1, cnt, + (ulong *)(addr+info.blksz)) != cnt) { + printf ("** Read error on %d:%d\n", dev, part); + return 1; + } + /* Loading ok, update default load address */ + load_addr = addr; + + flush_cache (addr, (cnt+1)*info.blksz); + + /* Check if we should attempt an auto-start */ + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { + char *local_args[2]; + extern int do_bootm (cmd_tbl_t *, int, int, char *[]); + local_args[0] = argv[0]; + local_args[1] = NULL; + printf ("Automatic boot of image at addr 0x%08lX ...\n", addr); + rcode = do_bootm (cmdtp, 0, 1, local_args); + } + return rcode; +} + +/********************************************************************************* + * scsi command intepreter + */ +int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + switch (argc) { + case 0: + case 1: printf ("Usage:\n%s\n", cmdtp->usage); return 1; + case 2: + if (strncmp(argv[1],"res",3) == 0) { + printf("\nReset SCSI\n"); + scsi_bus_reset(); + scsi_scan(1); + return 0; + } + if (strncmp(argv[1],"inf",3) == 0) { + int i; + for (i=0; i= CFG_SCSI_MAX_DEVICE)) { + printf("\nno SCSI devices available\n"); + return 1; + } + printf ("\n Device %d: ", scsi_curr_dev); + dev_print(&scsi_dev_desc[scsi_curr_dev]); + return 0; + } + if (strncmp(argv[1],"scan",4) == 0) { + scsi_scan(1); + return 0; + } + if (strncmp(argv[1],"part",4) == 0) { + int dev, ok; + for (ok=0, dev=0; devusage); + return 1; + case 3: + if (strncmp(argv[1],"dev",3) == 0) { + int dev = (int)simple_strtoul(argv[2], NULL, 10); + printf ("\nSCSI device %d: ", dev); + if (dev >= CFG_SCSI_MAX_DEVICE) { + printf("unknown device\n"); + return 1; + } + printf ("\n Device %d: ", dev); + dev_print(&scsi_dev_desc[dev]); + if(scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) { + return 1; + } + scsi_curr_dev = dev; + printf("... is now current device\n"); + return 0; + } + if (strncmp(argv[1],"part",4) == 0) { + int dev = (int)simple_strtoul(argv[2], NULL, 10); + if(scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) { + print_part(&scsi_dev_desc[dev]); + } + else { + printf ("\nSCSI device %d not available\n", dev); + } + return 1; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + default: + /* at least 4 args */ + if (strcmp(argv[1],"read") == 0) { + ulong addr = simple_strtoul(argv[2], NULL, 16); + ulong blk = simple_strtoul(argv[3], NULL, 16); + ulong cnt = simple_strtoul(argv[4], NULL, 16); + ulong n; + printf ("\nSCSI read: device %d block # %ld, count %ld ... ", + scsi_curr_dev, blk, cnt); + n = scsi_read(scsi_curr_dev, blk, cnt, (ulong *)addr); + printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR"); + return 0; + } + } /* switch */ + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +/**************************************************************************************** + * scsi_read + */ + +#define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */ + +ulong scsi_read(int device, ulong blknr, ulong blkcnt, ulong *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + ccb* pccb=(ccb *)&tempccb; + device&=0xff; + /* Setup device + */ + pccb->target=scsi_dev_desc[device].target; + pccb->lun=scsi_dev_desc[device].lun; + buf_addr=(unsigned long)buffer; + start=blknr; + blks=blkcnt; + PRINTF("\nscsi_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks,(unsigned long)buffer); + do { + pccb->pdata=(unsigned char *)buf_addr; + if(blks>SCSI_MAX_READ_BLK) { + pccb->datalen=scsi_dev_desc[device].blksz * SCSI_MAX_READ_BLK; + smallblks=SCSI_MAX_READ_BLK; + scsi_setup_read_ext(pccb,start,smallblks); + start+=SCSI_MAX_READ_BLK; + blks-=SCSI_MAX_READ_BLK; + } + else { + pccb->datalen=scsi_dev_desc[device].blksz * blks; + smallblks=(unsigned short) blks; + scsi_setup_read_ext(pccb,start,smallblks); + start+=blks; + blks=0; + } + PRINTF("scsi_read_ext: startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr); + if(scsi_exec(pccb)!=TRUE) { + scsi_print_error(pccb); + blkcnt-=blks; + break; + } + buf_addr+=pccb->datalen; + } while(blks!=0); + PRINTF("scsi_read_ext: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr); + return(blkcnt); +} + +/* copy src to dest, skipping leading and trailing blanks + * and null terminate the string + */ +void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len) +{ + int start,end; + + start=0; + while(startstart) { + if(src[end]!=' ') + break; + end--; + } + for( ; start<=end; start++) { + *dest++=src[start]; + } + *dest='\0'; +} + + + +/* Trim trailing blanks, and NUL-terminate string + */ +void scsi_trim_trail (unsigned char *str, unsigned int len) +{ + unsigned char *p = str + len - 1; + + while (len-- > 0) { + *p-- = '\0'; + if (*p != ' ') { + return; + } + } +} + + +/************************************************************************************ + * Some setup (fill-in) routines + */ +void scsi_setup_test_unit_ready(ccb * pccb) +{ + pccb->cmd[0]=SCSI_TST_U_RDY; + pccb->cmd[1]=pccb->lun<<5; + pccb->cmd[2]=0; + pccb->cmd[3]=0; + pccb->cmd[4]=0; + pccb->cmd[5]=0; + pccb->cmdlen=6; + pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ +} + +void scsi_setup_read_capacity(ccb * pccb) +{ + pccb->cmd[0]=SCSI_RD_CAPAC; + pccb->cmd[1]=pccb->lun<<5; + pccb->cmd[2]=0; + pccb->cmd[3]=0; + pccb->cmd[4]=0; + pccb->cmd[5]=0; + pccb->cmd[6]=0; + pccb->cmd[7]=0; + pccb->cmd[8]=0; + pccb->cmd[9]=0; + pccb->cmdlen=10; + pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ + +} + +void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks) +{ + pccb->cmd[0]=SCSI_READ10; + pccb->cmd[1]=pccb->lun<<5; + pccb->cmd[2]=((unsigned char) (start>>24))&0xff; + pccb->cmd[3]=((unsigned char) (start>>16))&0xff; + pccb->cmd[4]=((unsigned char) (start>>8))&0xff; + pccb->cmd[5]=((unsigned char) (start))&0xff; + pccb->cmd[6]=0; + pccb->cmd[7]=((unsigned char) (blocks>>8))&0xff; + pccb->cmd[8]=(unsigned char) blocks & 0xff; + pccb->cmd[6]=0; + pccb->cmdlen=10; + pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ + PRINTF("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", + pccb->cmd[0],pccb->cmd[1], + pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5], + pccb->cmd[7],pccb->cmd[8]); +} + +void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks) +{ + pccb->cmd[0]=SCSI_READ6; + pccb->cmd[1]=pccb->lun<<5 | (((unsigned char)(start>>16))&0x1f); + pccb->cmd[2]=((unsigned char) (start>>8))&0xff; + pccb->cmd[3]=((unsigned char) (start))&0xff; + pccb->cmd[4]=(unsigned char) blocks & 0xff; + pccb->cmd[5]=0; + pccb->cmdlen=6; + pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ + PRINTF("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n", + pccb->cmd[0],pccb->cmd[1], + pccb->cmd[2],pccb->cmd[3],pccb->cmd[4]); +} + + +void scsi_setup_inquiry(ccb * pccb) +{ + pccb->cmd[0]=SCSI_INQUIRY; + pccb->cmd[1]=pccb->lun<<5; + pccb->cmd[2]=0; + pccb->cmd[3]=0; + if(pccb->datalen>255) + pccb->cmd[4]=255; + else + pccb->cmd[4]=(unsigned char)pccb->datalen; + pccb->cmd[5]=0; + pccb->cmdlen=6; + pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ +} + +#endif /* #if (CONFIG_COMMANDS & CFG_CMD_SCSI) */ + + diff --git a/common/cmd_usb.c b/common/cmd_usb.c new file mode 100644 index 0000000000..389f0fc013 --- /dev/null +++ b/common/cmd_usb.c @@ -0,0 +1,595 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * Most of this source has been derived from the Linux USB + * project. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_USB) + +#include +#include + +#undef CMD_USB_DEBUG + +#ifdef CMD_USB_DEBUG +#define CMD_USB_PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define CMD_USB_PRINTF(fmt,args...) +#endif +static int usb_stor_curr_dev=-1; /* current device */ + +/* somme display routines (info command) */ +char * usb_get_class_desc(unsigned char dclass) +{ + switch(dclass) { + case USB_CLASS_PER_INTERFACE: + return("See Interface"); + case USB_CLASS_AUDIO: + return("Audio"); + case USB_CLASS_COMM: + return("Communication"); + case USB_CLASS_HID: + return("Human Interface"); + case USB_CLASS_PRINTER: + return("Printer"); + case USB_CLASS_MASS_STORAGE: + return("Mass Storage"); + case USB_CLASS_HUB: + return("Hub"); + case USB_CLASS_DATA: + return("CDC Data"); + case USB_CLASS_VENDOR_SPEC: + return("Vendor specific"); + default : + return(""); + } +} + +void usb_display_class_sub(unsigned char dclass,unsigned char subclass,unsigned char proto) +{ + switch(dclass) { + case USB_CLASS_PER_INTERFACE: + printf("See Interface"); + break; + case USB_CLASS_HID: + printf("Human Interface, Subclass: "); + switch(subclass) { + case USB_SUB_HID_NONE: + printf("None"); + break; + case USB_SUB_HID_BOOT: + printf("Boot "); + switch(proto) { + case USB_PROT_HID_NONE: + printf("None"); + break; + case USB_PROT_HID_KEYBOARD: + printf("Keyboard"); + break; + case USB_PROT_HID_MOUSE: + printf("Mouse"); + break; + default: + printf("reserved"); + } + break; + default: + printf("reserved"); + } + break; + case USB_CLASS_MASS_STORAGE: + printf("Mass Storage, "); + switch(subclass) { + case US_SC_RBC: + printf("RBC "); + break; + case US_SC_8020: + printf("SFF-8020i (ATAPI)"); + break; + case US_SC_QIC: + printf("QIC-157 (Tape)"); + break; + case US_SC_UFI: + printf("UFI"); + break; + case US_SC_8070: + printf("SFF-8070"); + break; + case US_SC_SCSI: + printf("Transp. SCSI"); + break; + default: + printf("reserved"); + break; + } + printf(", "); + switch(proto) { + case US_PR_CB: + printf("Command/Bulk"); + break; + case US_PR_CBI: + printf("Command/Bulk/Int"); + break; + case US_PR_BULK: + printf("Bulk only"); + break; + default: + printf("reserved"); + } + break; + default: + printf("%s",usb_get_class_desc(dclass)); + } +} + +void usb_display_string(struct usb_device *dev,int index) +{ + char buffer[256]; + if (index!=0) { + if (usb_string(dev,index,&buffer[0],256)>0); + printf("String: \"%s\"",buffer); + } +} + +void usb_display_desc(struct usb_device *dev) +{ + if (dev->descriptor.bDescriptorType==USB_DT_DEVICE) { + printf("%d: %s, USB Revision %x.%x\n",dev->devnum,usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass), + (dev->descriptor.bcdUSB>>8) & 0xff,dev->descriptor.bcdUSB & 0xff); + if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial)) + printf(" - %s %s %s\n",dev->mf,dev->prod,dev->serial); + if (dev->descriptor.bDeviceClass) { + printf(" - Class: "); + usb_display_class_sub(dev->descriptor.bDeviceClass,dev->descriptor.bDeviceSubClass,dev->descriptor.bDeviceProtocol); + printf("\n"); + } + else { + printf(" - Class: (from Interface) %s\n",usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass)); + } + printf(" - PacketSize: %d Configurations: %d\n",dev->descriptor.bMaxPacketSize0,dev->descriptor.bNumConfigurations); + printf(" - Vendor: 0x%04x Product 0x%04x Version %d.%d\n",dev->descriptor.idVendor,dev->descriptor.idProduct,(dev->descriptor.bcdDevice>>8) & 0xff,dev->descriptor.bcdDevice & 0xff); + } + +} + +void usb_display_conf_desc(struct usb_config_descriptor *config,struct usb_device *dev) +{ + printf(" Configuration: %d\n",config->bConfigurationValue); + printf(" - Interfaces: %d %s%s%dmA\n",config->bNumInterfaces,(config->bmAttributes & 0x40) ? "Self Powered " : "Bus Powered ", + (config->bmAttributes & 0x20) ? "Remote Wakeup " : "",config->MaxPower*2); + if (config->iConfiguration) { + printf(" - "); + usb_display_string(dev,config->iConfiguration); + printf("\n"); + } +} + +void usb_display_if_desc(struct usb_interface_descriptor *ifdesc,struct usb_device *dev) +{ + printf(" Interface: %d\n",ifdesc->bInterfaceNumber); + printf(" - Alternate Settings %d, Endpoints: %d\n",ifdesc->bAlternateSetting,ifdesc->bNumEndpoints); + printf(" - Class "); + usb_display_class_sub(ifdesc->bInterfaceClass,ifdesc->bInterfaceSubClass,ifdesc->bInterfaceProtocol); + printf("\n"); + if (ifdesc->iInterface) { + printf(" - "); + usb_display_string(dev,ifdesc->iInterface); + printf("\n"); + } +} + +void usb_display_ep_desc(struct usb_endpoint_descriptor *epdesc) +{ + printf(" - Endpoint %d %s ",epdesc->bEndpointAddress & 0xf,(epdesc->bEndpointAddress & 0x80) ? "In" : "Out"); + switch((epdesc->bmAttributes & 0x03)) + { + case 0: printf("Control"); break; + case 1: printf("Isochronous"); break; + case 2: printf("Bulk"); break; + case 3: printf("Interrupt"); break; + } + printf(" MaxPacket %d",epdesc->wMaxPacketSize); + if ((epdesc->bmAttributes & 0x03)==0x3) + printf(" Interval %dms",epdesc->bInterval); + printf("\n"); +} + +/* main routine to diasplay the configs, interfaces and endpoints */ +void usb_display_config(struct usb_device *dev) +{ + struct usb_config_descriptor *config; + struct usb_interface_descriptor *ifdesc; + struct usb_endpoint_descriptor *epdesc; + int i,ii; + + config= &dev->config; + usb_display_conf_desc(config,dev); + for(i=0;ino_of_if;i++) { + ifdesc= &config->if_desc[i]; + usb_display_if_desc(ifdesc,dev); + for(ii=0;iino_of_ep;ii++) { + epdesc= &ifdesc->ep_desc[ii]; + usb_display_ep_desc(epdesc); + } + } + printf("\n"); +} + +/* shows the device tree recursively */ +void usb_show_tree_graph(struct usb_device *dev,char *pre) +{ + int i,index; + int has_child,last_child,port; + + index=strlen(pre); + printf(" %s",pre); + /* check if the device has connected children */ + has_child=0; + for(i=0;imaxchild;i++) { + if (dev->children[i]!=NULL) + has_child=1; + } + /* check if we are the last one */ + last_child=1; + if (dev->parent!=NULL) { + for(i=0;iparent->maxchild;i++) { + /* search for children */ + if (dev->parent->children[i]==dev) { + /* found our pointer, see if we have a little sister */ + port=i; + while(i++parent->maxchild) { + if (dev->parent->children[i]!=NULL) { + /* found a sister */ + last_child=0; + break; + } /* if */ + } /* while */ + } /* device found */ + } /* for all children of the parent */ + printf("\b+-"); + /* correct last child */ + if (last_child) { + pre[index-1]=' '; + } + } /* if not root hub */ + else + printf(" "); + printf("%d ",dev->devnum); + pre[index++]=' '; + pre[index++]= has_child ? '|' : ' '; + pre[index]=0; + printf(" %s (%s, %dmA)\n",usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass), + dev->slow ? "1.5MBit/s" : "12MBit/s",dev->config.MaxPower * 2); + if (strlen(dev->mf) || + strlen(dev->prod) || + strlen(dev->serial)) + printf(" %s %s %s %s\n",pre,dev->mf,dev->prod,dev->serial); + printf(" %s\n",pre); + if (dev->maxchild>0) { + for(i=0;imaxchild;i++) { + if (dev->children[i]!=NULL) { + usb_show_tree_graph(dev->children[i],pre); + pre[index]=0; + } + } + } +} + +/* main routine for the tree command */ +void usb_show_tree(struct usb_device *dev) +{ + char preamble[32]; + + memset(preamble,0,32); + usb_show_tree_graph(dev,&preamble[0]); +} + + + +/****************************************************************************** + * usb boot command intepreter. Derived from diskboot + */ +#ifdef CONFIG_USB_STORAGE +int do_usbboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *boot_device = NULL; + char *ep; + int dev, part=0, rcode; + ulong cnt; + ulong addr; + disk_partition_t info; + image_header_t *hdr; + block_dev_desc_t *stor_dev; + + + switch (argc) { + case 1: + addr = CFG_LOAD_ADDR; + boot_device = getenv ("bootdevice"); + break; + case 2: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = getenv ("bootdevice"); + break; + case 3: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + break; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (!boot_device) { + puts ("\n** No boot device **\n"); + return 1; + } + + dev = simple_strtoul(boot_device, &ep, 16); + stor_dev=usb_stor_get_dev(dev); + if (stor_dev->type == DEV_TYPE_UNKNOWN) { + printf ("\n** Device %d not available\n", dev); + return 1; + } + if (stor_dev->block_read==NULL) { + printf("storage device not initialized. Use usb scan\n"); + return 1; + } + if (*ep) { + if (*ep != ':') { + puts ("\n** Invalid boot device, use `dev[:part]' **\n"); + return 1; + } + part = simple_strtoul(++ep, NULL, 16); + } + + if (get_partition_info (stor_dev, part, &info)) { + /* try to boot raw .... */ + strncpy(&info.type[0], BOOT_PART_TYPE, sizeof(BOOT_PART_TYPE)); + strncpy(&info.name[0], "Raw", 4); + info.start=0; + info.blksz=0x200; + info.size=2880; + printf("error reading partinfo...try to boot raw\n"); + } + if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) { + printf ("\n** Invalid partition type \"%.32s\"" + " (expect \"" BOOT_PART_TYPE "\")\n", + info.type); + return 1; + } + printf ("\nLoading from USB device %d, partition %d: " + "Name: %.32s Type: %.32s\n", + dev, part, info.name, info.type); + + printf ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n", + info.start, info.size, info.blksz); + + if (stor_dev->block_read(dev, info.start, 1, (ulong *)addr) != 1) { + printf ("** Read error on %d:%d\n", dev, part); + return 1; + } + + hdr = (image_header_t *)addr; + + if (hdr->ih_magic == IH_MAGIC) { + print_image_hdr (hdr); + cnt = (hdr->ih_size + sizeof(image_header_t)); + cnt += info.blksz - 1; + cnt /= info.blksz; + cnt -= 1; + } else { + printf("\n** Bad Magic Number **\n"); + return 1; + } + + if (stor_dev->block_read (dev, info.start+1, cnt, + (ulong *)(addr+info.blksz)) != cnt) { + printf ("\n** Read error on %d:%d\n", dev, part); + return 1; + } + /* Loading ok, update default load address */ + load_addr = addr; + + flush_cache (addr, (cnt+1)*info.blksz); + + /* Check if we should attempt an auto-start */ + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { + char *local_args[2]; + extern int do_bootm (cmd_tbl_t *, int, int, char *[]); + local_args[0] = argv[0]; + local_args[1] = NULL; + printf ("Automatic boot of image at addr 0x%08lX ...\n", addr); + rcode=do_bootm (cmdtp, 0, 1, local_args); + return rcode; + } + return 0; +} +#endif /* CONFIG_USB_STORAGE */ + + + +/********************************************************************************* + * usb command intepreter + */ +int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + + int i; + struct usb_device *dev = NULL; + block_dev_desc_t *stor_dev; + + if ((strncmp(argv[1],"reset",5) == 0) || + (strncmp(argv[1],"start",5) == 0)){ + usb_stop(); + printf("(Re)start USB...\n"); + usb_init(); + return 0; + } + if (strncmp(argv[1],"stop",4) == 0) { +#ifdef CONFIG_USB_KEYBOARD + if (argc==2) { + if (usb_kbd_deregister()!=0) { + printf("USB not stopped: usbkbd still using USB\n"); + return 1; + } + } + else { /* forced stop, switch console in to serial */ + console_assign(stdin,"serial"); + usb_kbd_deregister(); + } +#endif + printf("stopping USB..\n"); + usb_stop(); + return 0; + } + if (strncmp(argv[1],"tree",4) == 0) { + printf("\nDevice Tree:\n"); + usb_show_tree(usb_get_dev_index(0)); + return 0; + } + if (strncmp(argv[1],"inf",3) == 0) { + int d; + if (argc==2) { + for(d=0;ddevnum==i) + break; + } + if (dev==NULL) { + printf("*** NO Device avaiable ***\n"); + return 0; + } + else { + usb_display_desc(dev); + usb_display_config(dev); + } + } + return 0; + } +#ifdef CONFIG_USB_STORAGE + if (strncmp(argv[1],"scan",4) == 0) { + printf("Scan for storage device:\n"); + usb_stor_curr_dev=usb_stor_scan(1); + if (usb_stor_curr_dev==-1) { + printf("No device found. Not initialized?\n"); + return 1; + } + return 0; + } + if (strncmp(argv[1],"part",4) == 0) { + int devno, ok; + for (ok=0, devno=0; devnotype!=DEV_TYPE_UNKNOWN) { + ok++; + if (devno) + printf("\n"); + printf("print_part of %x\n",devno); + print_part(stor_dev); + } + } + if (!ok) { + printf("\nno USB devices available\n"); + return 1; + } + return 0; + } + if (strcmp(argv[1],"read") == 0) { + if (usb_stor_curr_dev<0) { + printf("no current device selected\n"); + return 1; + } + if (argc==5) { + unsigned long addr = simple_strtoul(argv[2], NULL, 16); + unsigned long blk = simple_strtoul(argv[3], NULL, 16); + unsigned long cnt = simple_strtoul(argv[4], NULL, 16); + unsigned long n; + printf ("\nUSB read: device %d block # %ld, count %ld ... ", + usb_stor_curr_dev, blk, cnt); + stor_dev=usb_stor_get_dev(usb_stor_curr_dev); + n = stor_dev->block_read(usb_stor_curr_dev, blk, cnt, (ulong *)addr); + printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR"); + if (n==cnt) + return 0; + return 1; + } + } + if (strcmp(argv[1],"dev") == 0) { + if (argc==3) { + int dev = (int)simple_strtoul(argv[2], NULL, 10); + printf ("\nUSB device %d: ", dev); + if (dev >= USB_MAX_STOR_DEV) { + printf("unknown device\n"); + return 1; + } + printf ("\n Device %d: ", dev); + stor_dev=usb_stor_get_dev(dev); + dev_print(stor_dev); + if (stor_dev->type == DEV_TYPE_UNKNOWN) { + return 1; + } + usb_stor_curr_dev = dev; + printf("... is now current device\n"); + return 0; + } + else { + printf ("\nUSB device %d: ", usb_stor_curr_dev); + stor_dev=usb_stor_get_dev(usb_stor_curr_dev); + dev_print(stor_dev); + if (stor_dev->type == DEV_TYPE_UNKNOWN) { + return 1; + } + return 0; + } + return 0; + } +#endif /* CONFIG_USB_STORAGE */ + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} + + +#endif /* (CONFIG_COMMANDS & CFG_CMD_USB) */ + + -- 2.39.5