1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Mass-Storage driver File: usbmass.c 5 * 6 * This driver deals with mass-storage devices that support 7 * the SCSI Transparent command set and USB Bulk-Only protocol 8 * 9 * Author: Mitch Lichtenberg (mpl@broadcom.com) 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48 49#ifndef _CFE_ 50#include <stdio.h> 51#include <time.h> 52#include <memory.h> 53#include <stdint.h> 54#include "usbhack.h" 55#else 56#include "lib_types.h" 57#include "lib_string.h" 58#include "lib_printf.h" 59#include "cfe_timer.h" 60#include "cfe_iocb.h" 61#include "cfe_device.h" 62#include "cfe_ioctl.h" 63#include "cfe_error.h" 64#include "cfe_console.h" 65#endif 66 67#include "lib_malloc.h" 68#include "lib_queue.h" 69#include "usbchap9.h" 70#include "usbd.h" 71 72/* ********************************************************************* 73 * USB Mass-Storage class Constants 74 ********************************************************************* */ 75 76#define USBMASS_CBI_PROTOCOL 0 77#define USBMASS_CBI_NOCOMPLETE_PROTOCOL 1 78#define USBMASS_BULKONLY_PROTOCOL 0x50 79 80#define USBMASS_SUBCLASS_RBC 0x01 81#define USBMASS_SUBCLASS_SFF8020 0x02 82#define USBMASS_SUBCLASS_QIC157 0x03 83#define USBMASS_SUBCLASS_UFI 0x04 84#define USBMASS_SUBCLASS_SFF8070 0x05 85#define USBMASS_SUBCLASS_SCSI 0x06 86 87#define USBMASS_CSW_PASS 0x00 88#define USBMASS_CSW_FAILED 0x01 89#define USBMASS_CSW_PHASEERR 0x02 90 91#define USBMASS_CBW_SIGNATURE 0x43425355 92#define USBMASS_CSW_SIGNATURE 0x53425355 93 94/* ********************************************************************* 95 * USB Mass-Storage class Structures 96 ********************************************************************* */ 97 98typedef struct usbmass_cbw_s { 99 uint8_t dCBWSignature0,dCBWSignature1,dCBWSignature2,dCBWSignature3; 100 uint8_t dCBWTag0,dCBWTag1,dCBWTag2,dCBWTag3; 101 uint8_t dCBWDataTransferLength0,dCBWDataTransferLength1, 102 dCBWDataTransferLength2,dCBWDataTransferLength3; 103 uint8_t bmCBWFlags; 104 uint8_t bCBWLUN; 105 uint8_t bCBWCBLength; 106 uint8_t CBWCB[16]; 107} usbmass_cbw_t; 108 109typedef struct usbmass_csw_s { 110 uint8_t dCSWSignature0,dCSWSignature1,dCSWSignature2,dCSWSignature3; 111 uint8_t dCSWTag0,dCSWTag1,dCSWTag2,dCSWTag3; 112 uint8_t dCSWDataResidue0,dCSWDataResidue1,dCSWDataResidue2,dCSWDataResidue3; 113 uint8_t bCSWStatus; 114} usbmass_csw_t; 115 116#define GETCBWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \ 117 ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24)) 118#define PUTCBWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \ 119 (s)->f##1 = ((v)>>8 & 0xFF); \ 120 (s)->f##2 = ((v)>>16 & 0xFF); \ 121 (s)->f##3 = ((v)>>24 & 0xFF); 122 123 124int usbmass_request_sense(usbdev_t *dev); 125 126/* ********************************************************************* 127 * Linkage to CFE 128 ********************************************************************* */ 129 130#ifdef _CFE_ 131 132/* 133 * Softc for the CFE side of the disk driver. 134 */ 135#define MAX_SECTORSIZE 2048 136typedef struct usbdisk_s { 137 uint32_t usbdisk_sectorsize; 138 uint32_t usbdisk_ttlsect; 139 uint32_t usbdisk_devtype; 140 int usbdisk_unit; 141} usbdisk_t; 142 143/* 144 * This table points at the currently configured USB disk 145 * devices. This lets us leave the CFE half of the driver lying 146 * around while the USB devices come and go. We use the unit number 147 * from the original CFE attach to index this table, and devices 148 * that are not present are "not ready." 149 */ 150 151#define USBDISK_MAXUNITS 4 152static usbdev_t *usbdisk_units[USBDISK_MAXUNITS]; 153 154/* 155 * CFE device driver routine forwards 156 */ 157 158static void usbdisk_probe(cfe_driver_t *drv, 159 unsigned long probe_a, unsigned long probe_b, 160 void *probe_ptr); 161 162static int usbdisk_open(cfe_devctx_t *ctx); 163static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 164static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 165static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 166static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 167static int usbdisk_close(cfe_devctx_t *ctx); 168 169/* 170 * CFE device driver descriptor 171 */ 172 173const static cfe_devdisp_t usbdisk_dispatch = { 174 usbdisk_open, 175 usbdisk_read, 176 usbdisk_inpstat, 177 usbdisk_write, 178 usbdisk_ioctl, 179 usbdisk_close, 180 NULL, 181 NULL 182}; 183 184const cfe_driver_t usb_disk = { 185 "USB Disk", 186 "usbdisk", 187 CFE_DEV_DISK, 188 &usbdisk_dispatch, 189 usbdisk_probe 190}; 191 192 193#endif 194 195 196 197/* ********************************************************************* 198 * Forward Definitions 199 ********************************************************************* */ 200 201static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv); 202static int usbmass_detach(usbdev_t *dev); 203 204/* ********************************************************************* 205 * Structures 206 ********************************************************************* */ 207 208typedef struct usbmass_softc_s { 209 int umass_inpipe; 210 int umass_outpipe; 211 int umass_devtype; 212 uint32_t umass_curtag; 213 int umass_unit; 214} usbmass_softc_t; 215 216usb_driver_t usbmass_driver = { 217 "Mass-Storage Device", 218 usbmass_attach, 219 usbmass_detach 220}; 221 222usbdev_t *usbmass_dev = NULL; /* XX hack for testing only */ 223 224/* ********************************************************************* 225 * usbmass_mass_storage_reset(dev,ifc) 226 * 227 * Do a bulk-only mass-storage reset. 228 * 229 * Input parameters: 230 * dev - device to reset 231 * ifc - interface number to reset (bInterfaceNum) 232 * 233 * Return value: 234 * status 235 ********************************************************************* */ 236 237#define usbmass_mass_storage_reset(dev,ifc) \ 238 usb_simple_request(dev,0x21,0xFF,ifc,0) 239 240 241 242/* ********************************************************************* 243 * usbmass_stall_recovery(dev) 244 * 245 * Do whatever it takes to unstick a stalled mass-storage device. 246 * 247 * Input parameters: 248 * dev - usb device 249 * 250 * Return value: 251 * nothing 252 ********************************************************************* */ 253 254static void usbmass_stall_recovery(usbdev_t *dev) 255{ 256 usbmass_softc_t *softc; 257 258 softc = (usbmass_softc_t *) dev->ud_private; 259 260 usb_clear_stall(dev,softc->umass_inpipe); 261 262 usbmass_request_sense(dev); 263} 264 265 266/* ********************************************************************* 267 * usbmass_read_capacity(dev,sectornum,buffer) 268 * 269 * Reads a sector from the device. 270 * 271 * Input parameters: 272 * dev - usb device 273 * sectornum - sector number to read 274 * buffer - place to put sector we read 275 * 276 * Return value: 277 * status 278 ********************************************************************* */ 279 280int usbmass_request_sense(usbdev_t *dev) 281{ 282 uint8_t *cbwcsw; 283 uint8_t *sector; 284 usbmass_cbw_t *cbw; 285 usbmass_csw_t *csw; 286 usbreq_t *ur; 287 usbmass_softc_t *softc; 288 int res; 289 290 softc = (usbmass_softc_t *) dev->ud_private; 291 292 cbwcsw = KMALLOC(64,32); 293 sector = KMALLOC(64,32); 294 295 memset(sector,0,64); 296 297 cbw = (usbmass_cbw_t *) cbwcsw; 298 csw = (usbmass_csw_t *) cbwcsw; 299 300 /* 301 * Fill in the fields of the CBW 302 */ 303 304 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 305 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 306 PUTCBWFIELD(cbw,dCBWDataTransferLength,18); 307 cbw->bmCBWFlags = 0x80; /* IN */ 308 cbw->bCBWLUN = 0; 309 cbw->bCBWCBLength = 12; 310 cbw->CBWCB[0] = 0x3; /* REQUEST SENSE */ 311 cbw->CBWCB[1] = 0; 312 cbw->CBWCB[2] = 0; 313 cbw->CBWCB[3] = 0; 314 cbw->CBWCB[4] = 18; /* allocation length */ 315 cbw->CBWCB[5] = 0; 316 cbw->CBWCB[6] = 0; 317 cbw->CBWCB[7] = 0; 318 cbw->CBWCB[8] = 0; 319 cbw->CBWCB[9] = 0; 320 321 softc->umass_curtag++; 322 323 /* 324 * Send the CBW 325 */ 326 327 ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 328 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 329 res = usb_sync_request(ur); 330 usb_free_request(ur); 331 332 /* 333 * Get the data 334 */ 335 336 memset(sector,0,18); 337 ur = usb_make_request(dev,softc->umass_inpipe,sector, 338 18,UR_FLAG_IN | UR_FLAG_SHORTOK); 339 res = usb_sync_request(ur); 340 usb_free_request(ur); 341 342 /* 343 * Get the Status 344 */ 345 346 memset(csw,0,sizeof(usbmass_csw_t)); 347 ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, 348 sizeof(usbmass_csw_t),UR_FLAG_IN); 349 res = usb_sync_request(ur); 350 usb_free_request(ur); 351 352 KFREE(cbwcsw); 353 354 KFREE(sector); 355 356 return 0; 357 358} 359 360/* ********************************************************************* 361 * usbmass_read_sector(dev,sectornum,seccnt,buffer) 362 * 363 * Reads a sector from the device. 364 * 365 * Input parameters: 366 * dev - usb device 367 * sectornum - sector number to read 368 * seccnt - count of sectors to read 369 * buffer - place to put sector we read 370 * 371 * Return value: 372 * status 373 ********************************************************************* */ 374 375int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 376 uint8_t *buffer); 377int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 378 uint8_t *buffer) 379{ 380 uint8_t *cbwcsw; 381 uint8_t *sector; 382 usbmass_cbw_t *cbw; 383 usbmass_csw_t *csw; 384 usbreq_t *ur; 385 usbmass_softc_t *softc; 386 int res; 387 388 softc = (usbmass_softc_t *) dev->ud_private; 389 390 cbwcsw = KMALLOC(64,32); 391 sector = buffer; 392 393 cbw = (usbmass_cbw_t *) cbwcsw; 394 csw = (usbmass_csw_t *) cbwcsw; 395 396 /* 397 * Fill in the fields of the CBW 398 */ 399 400 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 401 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 402 PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); 403 cbw->bmCBWFlags = 0x80; /* IN */ 404 cbw->bCBWLUN = 0; 405 cbw->bCBWCBLength = 10; 406 cbw->CBWCB[0] = 0x28; /* READ */ 407 cbw->CBWCB[1] = 0; 408 cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ 409 cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; 410 cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; 411 cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; 412 cbw->CBWCB[6] = 0; 413 cbw->CBWCB[7] = 0; 414 cbw->CBWCB[8] = seccnt; 415 cbw->CBWCB[9] = 0; 416 417 softc->umass_curtag++; 418 419 /* 420 * Send the CBW 421 */ 422 423 ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 424 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 425 res = usb_sync_request(ur); 426 usb_free_request(ur); 427 if (res == 4) { 428 usbmass_stall_recovery(dev); 429 KFREE(cbwcsw); 430 return -1; 431 } 432 433 434 /* 435 * Get the data 436 */ 437 438 ur = usb_make_request(dev,softc->umass_inpipe,sector, 439 512*seccnt,UR_FLAG_IN | UR_FLAG_SHORTOK); 440 res = usb_sync_request(ur); 441 usb_free_request(ur); 442 if (res == 4) { 443 usbmass_stall_recovery(dev); 444 KFREE(cbwcsw); 445 return -1; 446 } 447 448 449 /* 450 * Get the Status 451 */ 452 453 memset(csw,0,sizeof(usbmass_csw_t)); 454 ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, 455 sizeof(usbmass_csw_t),UR_FLAG_IN); 456 res = usb_sync_request(ur); 457 usb_free_request(ur); 458 if (res == 4) { 459 usbmass_stall_recovery(dev); 460 KFREE(cbwcsw); 461 return -1; 462 } 463 464 465 466 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; 467 468 KFREE(cbwcsw); 469 470 return res; 471 472} 473 474/* ********************************************************************* 475 * usbmass_write_sector(dev,sectornum,seccnt,buffer) 476 * 477 * Writes a sector to the device 478 * 479 * Input parameters: 480 * dev - usb device 481 * sectornum - sector number to write 482 * seccnt - count of sectors to write 483 * buffer - place to get sector to write 484 * 485 * Return value: 486 * status 487 ********************************************************************* */ 488 489static int usbmass_write_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 490 uint8_t *buffer) 491{ 492 uint8_t *cbwcsw; 493 uint8_t *sector; 494 usbmass_cbw_t *cbw; 495 usbmass_csw_t *csw; 496 usbreq_t *ur; 497 usbmass_softc_t *softc; 498 int res; 499 500 softc = (usbmass_softc_t *) dev->ud_private; 501 502 cbwcsw = KMALLOC(64,32); 503 sector = buffer; 504 505 cbw = (usbmass_cbw_t *) cbwcsw; 506 csw = (usbmass_csw_t *) cbwcsw; 507 508 /* 509 * Fill in the fields of the CBW 510 */ 511 512 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 513 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 514 PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); 515 cbw->bmCBWFlags = 0x00; /* OUT */ 516 cbw->bCBWLUN = 0; 517 cbw->bCBWCBLength = 10; 518 cbw->CBWCB[0] = 0x2A; /* WRITE */ 519 cbw->CBWCB[1] = 0; 520 cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ 521 cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; 522 cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; 523 cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; 524 cbw->CBWCB[6] = 0; 525 cbw->CBWCB[7] = 0; 526 cbw->CBWCB[8] = seccnt; 527 cbw->CBWCB[9] = 0; 528 529 softc->umass_curtag++; 530 531 /* 532 * Send the CBW 533 */ 534 535 ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 536 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 537 res = usb_sync_request(ur); 538 usb_free_request(ur); 539 540 /* 541 * Send the data 542 */ 543 544 ur = usb_make_request(dev,softc->umass_outpipe,sector, 545 512*seccnt,UR_FLAG_OUT); 546 res = usb_sync_request(ur); 547 usb_free_request(ur); 548 549 /* 550 * Get the Status 551 */ 552 553 memset(csw,0,sizeof(usbmass_csw_t)); 554 ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, 555 sizeof(usbmass_csw_t),UR_FLAG_IN); 556 res = usb_sync_request(ur); 557 usb_free_request(ur); 558 559 560 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; 561 562 KFREE(cbwcsw); 563 564 return res; 565} 566 567/* ********************************************************************* 568 * usbmass_read_capacity(dev,sectornum,buffer) 569 * 570 * Reads a sector from the device. 571 * 572 * Input parameters: 573 * dev - usb device 574 * sectornum - sector number to read 575 * buffer - place to put sector we read 576 * 577 * Return value: 578 * status 579 ********************************************************************* */ 580 581int usbmass_read_capacity(usbdev_t *dev,uint32_t *size); 582int usbmass_read_capacity(usbdev_t *dev,uint32_t *size) 583{ 584 uint8_t *cbwcsw; 585 uint8_t *sector; 586 usbmass_cbw_t *cbw; 587 usbmass_csw_t *csw; 588 usbreq_t *ur; 589 usbmass_softc_t *softc; 590 int res; 591 592 softc = (usbmass_softc_t *) dev->ud_private; 593 594 cbwcsw = KMALLOC(64,32); 595 sector = KMALLOC(64,32); 596 597 memset(sector,0,64); 598 599 cbw = (usbmass_cbw_t *) cbwcsw; 600 csw = (usbmass_csw_t *) cbwcsw; 601 602 *size = 0; 603 604 /* 605 * Fill in the fields of the CBW 606 */ 607 608 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 609 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 610 PUTCBWFIELD(cbw,dCBWDataTransferLength,8); 611 cbw->bmCBWFlags = 0x80; /* IN */ 612 cbw->bCBWLUN = 0; 613 cbw->bCBWCBLength = 10; 614 cbw->CBWCB[0] = 0x25; /* READ CAPACITY */ 615 cbw->CBWCB[1] = 0; 616 cbw->CBWCB[2] = 0; 617 cbw->CBWCB[3] = 0; 618 cbw->CBWCB[4] = 0; 619 cbw->CBWCB[5] = 0; 620 cbw->CBWCB[6] = 0; 621 cbw->CBWCB[7] = 0; 622 cbw->CBWCB[8] = 0; 623 cbw->CBWCB[9] = 0; 624 625 softc->umass_curtag++; 626 627 /* 628 * Send the CBW 629 */ 630 631 ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 632 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 633 res = usb_sync_request(ur); 634 usb_free_request(ur); 635 636 if (res == 4) { 637 usbmass_stall_recovery(dev); 638 KFREE(cbwcsw); 639 KFREE(sector); 640 return -1; 641 } 642 643 /* 644 * Get the data 645 */ 646 647 ur = usb_make_request(dev,softc->umass_inpipe,sector, 648 8,UR_FLAG_IN | UR_FLAG_SHORTOK); 649 res = usb_sync_request(ur); 650 usb_free_request(ur); 651 652 if (res == 4) { 653 usbmass_stall_recovery(dev); 654 KFREE(cbwcsw); 655 KFREE(sector); 656 return -1; 657 } 658 659 /* 660 * Get the Status 661 */ 662 663 memset(csw,0,sizeof(usbmass_csw_t)); 664 ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, 665 sizeof(usbmass_csw_t),UR_FLAG_IN); 666 res = usb_sync_request(ur); 667 usb_free_request(ur); 668 669 KFREE(cbwcsw); 670 671 *size = (((uint32_t) sector[0]) << 24) | 672 (((uint32_t) sector[1]) << 16) | 673 (((uint32_t) sector[2]) << 8) | 674 (((uint32_t) sector[3]) << 0); 675 676 KFREE(sector); 677 678 return 0; 679 680} 681 682 683 684/* ********************************************************************* 685 * usbmass_attach(dev,drv) 686 * 687 * This routine is called when the bus scan stuff finds a mass-storage 688 * device. We finish up the initialization by configuring the 689 * device and allocating our softc here. 690 * 691 * Input parameters: 692 * dev - usb device, in the "addressed" state. 693 * drv - the driver table entry that matched 694 * 695 * Return value: 696 * 0 697 ********************************************************************* */ 698 699static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv) 700{ 701 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; 702 usb_endpoint_descr_t *epdscr; 703 usb_endpoint_descr_t *indscr = NULL; 704 usb_endpoint_descr_t *outdscr = NULL; 705 usb_interface_descr_t *ifdscr; 706 usbmass_softc_t *softc; 707 int idx; 708 709 dev->ud_drv = drv; 710 711 softc = KMALLOC(sizeof(usbmass_softc_t),0); 712 memset(softc,0,sizeof(usbmass_softc_t)); 713 dev->ud_private = softc; 714 715 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 716 if (ifdscr == NULL) { 717 return -1; 718 } 719 720 if ((ifdscr->bInterfaceSubClass != USBMASS_SUBCLASS_SCSI) || 721 (ifdscr->bInterfaceProtocol != USBMASS_BULKONLY_PROTOCOL)) { 722 console_log("USBMASS: Do not understand devices with SubClass 0x%02X, Protocol 0x%02X", 723 ifdscr->bInterfaceSubClass, 724 ifdscr->bInterfaceProtocol); 725 return -1; 726 } 727 728 for (idx = 0; idx < 2; idx++) { 729 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); 730 731 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) { 732 outdscr = epdscr; 733 } 734 else { 735 indscr = epdscr; 736 } 737 } 738 739 740 if (!indscr || !outdscr) { 741 /* 742 * Could not get descriptors, something is very wrong. 743 * Leave device addressed but not configured. 744 */ 745 return -1; 746 } 747 748 /* 749 * Choose the standard configuration. 750 */ 751 752 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 753 754 /* 755 * Open the pipes. 756 */ 757 758 softc->umass_inpipe = usb_open_pipe(dev,indscr); 759 softc->umass_outpipe = usb_open_pipe(dev,outdscr); 760 softc->umass_curtag = 0x12345678; 761 762 /* 763 * Save pointer in global unit table so we can 764 * match CFE devices up with USB ones 765 */ 766 767 768#ifdef _CFE_ 769 softc->umass_unit = -1; 770 for (idx = 0; idx < USBDISK_MAXUNITS; idx++) { 771 if (usbdisk_units[idx] == NULL) { 772 softc->umass_unit = idx; 773 usbdisk_units[idx] = dev; 774 break; 775 } 776 } 777 778 console_log("USBMASS: Unit %d connected",softc->umass_unit); 779#endif 780 781 usbmass_dev = dev; 782 783 return 0; 784} 785 786/* ********************************************************************* 787 * usbmass_detach(dev) 788 * 789 * This routine is called when the bus scanner notices that 790 * this device has been removed from the system. We should 791 * do any cleanup that is required. The pending requests 792 * will be cancelled automagically. 793 * 794 * Input parameters: 795 * dev - usb device 796 * 797 * Return value: 798 * 0 799 ********************************************************************* */ 800 801static int usbmass_detach(usbdev_t *dev) 802{ 803 usbmass_softc_t *softc; 804 softc = (usbmass_softc_t *) dev->ud_private; 805 806#ifdef _CFE_ 807 console_log("USBMASS: USB unit %d disconnected",softc->umass_unit); 808 if (softc->umass_unit >= 0) usbdisk_units[softc->umass_unit] = NULL; 809#endif 810 811 KFREE(softc); 812 return 0; 813} 814 815 816 817#ifdef _CFE_ 818 819 820/* ********************************************************************* 821 * usbdisk_sectorshift(size) 822 * 823 * Given a sector size, return log2(size). We cheat; this is 824 * only needed for 2048 and 512-byte sectors. 825 * Explicitly using shifts and masks in sector number calculations 826 * helps on 32-bit-only platforms, since we probably won't need 827 * a helper library. 828 * 829 * Input parameters: 830 * size - sector size 831 * 832 * Return value: 833 * # of bits to shift 834 ********************************************************************* */ 835 836#define usbdisk_sectorshift(size) (((size)==2048)?11:9) 837 838 839/* ********************************************************************* 840 * usbdisk_probe(drv,probe_a,probe_b,probe_ptr) 841 * 842 * Our probe routine. Attach an empty USB disk device to the firmware. 843 * 844 * Input parameters: 845 * drv - driver structure 846 * probe_a - not used 847 * probe_b - not used 848 * probe_ptr - not used 849 * 850 * Return value: 851 * nothing 852 ********************************************************************* */ 853 854static void usbdisk_probe(cfe_driver_t *drv, 855 unsigned long probe_a, unsigned long probe_b, 856 void *probe_ptr) 857{ 858 usbdisk_t *softc; 859 char descr[128]; 860 861 softc = (usbdisk_t *) KMALLOC(sizeof(usbdisk_t),0); 862 863 memset(softc,0,sizeof(usbdisk_t)); 864 865 softc->usbdisk_sectorsize = 512; 866 softc->usbdisk_devtype = BLOCK_DEVTYPE_DISK; 867 softc->usbdisk_ttlsect = 0; /* not calculated yet */ 868 softc->usbdisk_unit = (int)probe_a; 869 870 xsprintf(descr,"USB Disk unit %d",(int)probe_a); 871 872 cfe_attach(drv,softc,NULL,descr); 873} 874 875 876/* ********************************************************************* 877 * usbdisk_open(ctx) 878 * 879 * Process the CFE OPEN call for this device. For IDE disks, 880 * the device is reset and identified, and the geometry is 881 * determined. 882 * 883 * Input parameters: 884 * ctx - device context 885 * 886 * Return value: 887 * 0 if ok, else error code 888 ********************************************************************* */ 889 890 891static int usbdisk_open(cfe_devctx_t *ctx) 892{ 893 usbdisk_t *softc = ctx->dev_softc; 894 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 895 uint32_t size; 896 int res; 897 898 if (!dev) return CFE_ERR_NOTREADY; 899 900 usbmass_request_sense(dev); 901 902 res = usbmass_read_capacity(dev,&size); 903 if (res < 0) return res; 904 905 softc->usbdisk_ttlsect = size; 906 907 return 0; 908} 909 910/* ********************************************************************* 911 * usbdisk_read(ctx,buffer) 912 * 913 * Process a CFE READ command for the IDE device. This is 914 * more complex than it looks, since CFE offsets are byte offsets 915 * and we may need to read partial sectors. 916 * 917 * Input parameters: 918 * ctx - device context 919 * buffer - buffer descriptor 920 * 921 * Return value: 922 * number of bytes read, or <0 if an error occured 923 ********************************************************************* */ 924 925static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 926{ 927 usbdisk_t *softc = ctx->dev_softc; 928 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 929 unsigned char *bptr; 930 int blen; 931 int numsec; 932 int res = 0; 933 int amtcopy; 934 uint64_t lba; 935 uint64_t offset; 936 unsigned char sector[MAX_SECTORSIZE]; 937 int sectorshift; 938 939 if (!dev) return CFE_ERR_NOTREADY; 940 941 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); 942 943 bptr = buffer->buf_ptr; 944 blen = buffer->buf_length; 945 offset = buffer->buf_offset; 946 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; 947 948 if (offset & (softc->usbdisk_sectorsize-1)) { 949 lba = (offset >> sectorshift); 950 res = usbmass_read_sector(dev,lba,1,sector); 951 if (res < 0) goto out; 952 amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); 953 if (amtcopy > blen) amtcopy = blen; 954 memcpy(bptr,§or[offset & (softc->usbdisk_sectorsize-1)],amtcopy); 955 bptr += amtcopy; 956 offset += amtcopy; 957 blen -= amtcopy; 958 } 959 960 if (blen >= softc->usbdisk_sectorsize) { 961 int seccnt; 962 963 lba = (offset >> sectorshift); 964 seccnt = (blen >> sectorshift); 965 966 res = usbmass_read_sector(dev,lba,seccnt,bptr); 967 if (res < 0) goto out; 968 969 amtcopy = seccnt << sectorshift; 970 bptr += amtcopy; 971 offset += amtcopy; 972 blen -= amtcopy; 973 } 974 975 if (blen) { 976 lba = (offset >> sectorshift); 977 res = usbmass_read_sector(dev,lba,1,sector); 978 if (res < 0) goto out; 979 amtcopy = blen; 980 memcpy(bptr,sector,amtcopy); 981 bptr += amtcopy; 982 offset += amtcopy; 983 blen -= amtcopy; 984 } 985 986out: 987 buffer->buf_retlen = bptr - buffer->buf_ptr; 988 989 return res; 990} 991 992/* ********************************************************************* 993 * usbdisk_inpstat(ctx,inpstat) 994 * 995 * Test input status for the IDE disk. Disks are always ready 996 * to read. 997 * 998 * Input parameters: 999 * ctx - device context 1000 * inpstat - input status structure 1001 * 1002 * Return value: 1003 * 0 1004 ********************************************************************* */ 1005 1006static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 1007{ 1008 /* usbdisk_t *softc = ctx->dev_softc; */ 1009 1010 inpstat->inp_status = 1; 1011 return 0; 1012} 1013 1014/* ********************************************************************* 1015 * usbdisk_write(ctx,buffer) 1016 * 1017 * Process a CFE WRITE command for the IDE device. If the write 1018 * involves partial sectors, the affected sectors are read first 1019 * and the changes are merged in. 1020 * 1021 * Input parameters: 1022 * ctx - device context 1023 * buffer - buffer descriptor 1024 * 1025 * Return value: 1026 * number of bytes write, or <0 if an error occured 1027 ********************************************************************* */ 1028 1029static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1030{ 1031 usbdisk_t *softc = ctx->dev_softc; 1032 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 1033 unsigned char *bptr; 1034 int blen; 1035 int numsec; 1036 int res = 0; 1037 int amtcopy; 1038 uint64_t offset; 1039 uint64_t lba; 1040 unsigned char sector[MAX_SECTORSIZE]; 1041 int sectorshift; 1042 1043 if (!dev) return CFE_ERR_NOTREADY; 1044 1045 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); 1046 1047 bptr = buffer->buf_ptr; 1048 blen = buffer->buf_length; 1049 offset = buffer->buf_offset; 1050 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; 1051 1052 if (offset & (softc->usbdisk_sectorsize-1)) { 1053 lba = (offset >> sectorshift); 1054 res = usbmass_read_sector(dev,lba,1,sector); 1055 if (res < 0) goto out; 1056 amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); 1057 if (amtcopy > blen) amtcopy = blen; 1058 memcpy(§or[offset & (softc->usbdisk_sectorsize-1)],bptr,amtcopy); 1059 res = usbmass_write_sector(dev,lba,1,sector); 1060 if (res < 0) goto out; 1061 bptr += amtcopy; 1062 offset += amtcopy; 1063 blen -= amtcopy; 1064 } 1065 1066 while (blen >= softc->usbdisk_sectorsize) { 1067 amtcopy = softc->usbdisk_sectorsize; 1068 lba = (offset >> sectorshift); 1069 res = usbmass_write_sector(dev,lba,1,bptr); 1070 if (res < 0) goto out; 1071 bptr += amtcopy; 1072 offset += amtcopy; 1073 blen -= amtcopy; 1074 } 1075 1076 if (blen) { 1077 lba = (offset >> sectorshift); 1078 res = usbmass_read_sector(dev,lba,1,sector); 1079 if (res < 0) goto out; 1080 amtcopy = blen; 1081 memcpy(sector,bptr,amtcopy); 1082 res = usbmass_write_sector(dev,lba,1,sector); 1083 if (res < 0) goto out; 1084 bptr += amtcopy; 1085 offset += amtcopy; 1086 blen -= amtcopy; 1087 } 1088 1089out: 1090 buffer->buf_retlen = bptr - buffer->buf_ptr; 1091 1092 return res; 1093} 1094 1095 1096/* ********************************************************************* 1097 * usbdisk_ioctl(ctx,buffer) 1098 * 1099 * Process device I/O control requests for the IDE device. 1100 * 1101 * Input parameters: 1102 * ctx - device context 1103 * buffer - buffer descriptor 1104 * 1105 * Return value: 1106 * 0 if ok 1107 * else error code 1108 ********************************************************************* */ 1109 1110static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1111{ 1112 usbdisk_t *softc = ctx->dev_softc; 1113 unsigned int *info = (unsigned int *) buffer->buf_ptr; 1114 unsigned long long *linfo = (unsigned long long *) buffer->buf_ptr; 1115 blockdev_info_t *devinfo; 1116 1117 switch ((int)buffer->buf_ioctlcmd) { 1118 case IOCTL_BLOCK_GETBLOCKSIZE: 1119 *info = softc->usbdisk_sectorsize; 1120 break; 1121 case IOCTL_BLOCK_GETTOTALBLOCKS: 1122 *linfo = softc->usbdisk_ttlsect; 1123 break; 1124 case IOCTL_BLOCK_GETDEVTYPE: 1125 devinfo = (blockdev_info_t *) buffer->buf_ptr; 1126 devinfo->blkdev_totalblocks = softc->usbdisk_ttlsect; 1127 devinfo->blkdev_blocksize = softc->usbdisk_sectorsize; 1128 devinfo->blkdev_devtype = softc->usbdisk_devtype; 1129 break; 1130 default: 1131 return -1; 1132 } 1133 1134 return 0; 1135} 1136 1137/* ********************************************************************* 1138 * usbdisk_close(ctx) 1139 * 1140 * Close the I/O device. 1141 * 1142 * Input parameters: 1143 * ctx - device context 1144 * 1145 * Return value: 1146 * 0 if ok, else error code 1147 ********************************************************************* */ 1148 1149static int usbdisk_close(cfe_devctx_t *ctx) 1150{ 1151 /* usbdisk_t *softc = ctx->dev_softc; */ 1152 1153 return 0; 1154} 1155 1156 1157#endif 1158