RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / cfe / cfe / usb / usbmass.c
blob7f7d90b2ace84246c0495f2fc397cef354453ba2
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)
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
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.
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.
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.
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 ********************************************************************* */
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
67 #include "lib_malloc.h"
68 #include "lib_queue.h"
69 #include "usbchap9.h"
70 #include "usbd.h"
72 /* *********************************************************************
73 * USB Mass-Storage class Constants
74 ********************************************************************* */
76 #define USBMASS_CBI_PROTOCOL 0
77 #define USBMASS_CBI_NOCOMPLETE_PROTOCOL 1
78 #define USBMASS_BULKONLY_PROTOCOL 0x50
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
87 #define USBMASS_CSW_PASS 0x00
88 #define USBMASS_CSW_FAILED 0x01
89 #define USBMASS_CSW_PHASEERR 0x02
91 #define USBMASS_CBW_SIGNATURE 0x43425355
92 #define USBMASS_CSW_SIGNATURE 0x53425355
94 /* *********************************************************************
95 * USB Mass-Storage class Structures
96 ********************************************************************* */
98 typedef 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;
109 typedef 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;
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);
124 int usbmass_request_sense(usbdev_t *dev);
126 /* *********************************************************************
127 * Linkage to CFE
128 ********************************************************************* */
130 #ifdef _CFE_
133 * Softc for the CFE side of the disk driver.
135 #define MAX_SECTORSIZE 2048
136 typedef 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;
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."
151 #define USBDISK_MAXUNITS 4
152 static usbdev_t *usbdisk_units[USBDISK_MAXUNITS];
155 * CFE device driver routine forwards
158 static void usbdisk_probe(cfe_driver_t *drv,
159 unsigned long probe_a, unsigned long probe_b,
160 void *probe_ptr);
162 static int usbdisk_open(cfe_devctx_t *ctx);
163 static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
164 static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
165 static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
166 static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
167 static int usbdisk_close(cfe_devctx_t *ctx);
170 * CFE device driver descriptor
173 const 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
184 const cfe_driver_t usb_disk = {
185 "USB Disk",
186 "usbdisk",
187 CFE_DEV_DISK,
188 &usbdisk_dispatch,
189 usbdisk_probe
193 #endif
197 /* *********************************************************************
198 * Forward Definitions
199 ********************************************************************* */
201 static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv);
202 static int usbmass_detach(usbdev_t *dev);
204 /* *********************************************************************
205 * Structures
206 ********************************************************************* */
208 typedef 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;
216 usb_driver_t usbmass_driver = {
217 "Mass-Storage Device",
218 usbmass_attach,
219 usbmass_detach
222 usbdev_t *usbmass_dev = NULL; /* XX hack for testing only */
224 /* *********************************************************************
225 * usbmass_mass_storage_reset(dev,ifc)
227 * Do a bulk-only mass-storage reset.
229 * Input parameters:
230 * dev - device to reset
231 * ifc - interface number to reset (bInterfaceNum)
233 * Return value:
234 * status
235 ********************************************************************* */
237 #define usbmass_mass_storage_reset(dev,ifc) \
238 usb_simple_request(dev,0x21,0xFF,ifc,0)
242 /* *********************************************************************
243 * usbmass_stall_recovery(dev)
245 * Do whatever it takes to unstick a stalled mass-storage device.
247 * Input parameters:
248 * dev - usb device
250 * Return value:
251 * nothing
252 ********************************************************************* */
254 static void usbmass_stall_recovery(usbdev_t *dev)
256 usbmass_softc_t *softc;
258 softc = (usbmass_softc_t *) dev->ud_private;
260 usb_clear_stall(dev,softc->umass_inpipe);
262 usbmass_request_sense(dev);
266 /* *********************************************************************
267 * usbmass_read_capacity(dev,sectornum,buffer)
269 * Reads a sector from the device.
271 * Input parameters:
272 * dev - usb device
273 * sectornum - sector number to read
274 * buffer - place to put sector we read
276 * Return value:
277 * status
278 ********************************************************************* */
280 int usbmass_request_sense(usbdev_t *dev)
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;
290 softc = (usbmass_softc_t *) dev->ud_private;
292 cbwcsw = KMALLOC(64,32);
293 sector = KMALLOC(64,32);
295 memset(sector,0,64);
297 cbw = (usbmass_cbw_t *) cbwcsw;
298 csw = (usbmass_csw_t *) cbwcsw;
301 * Fill in the fields of the CBW
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;
321 softc->umass_curtag++;
324 * Send the CBW
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);
333 * Get the data
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);
343 * Get the Status
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);
352 KFREE(cbwcsw);
354 KFREE(sector);
356 return 0;
360 /* *********************************************************************
361 * usbmass_read_sector(dev,sectornum,seccnt,buffer)
363 * Reads a sector from the device.
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
371 * Return value:
372 * status
373 ********************************************************************* */
375 int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
376 uint8_t *buffer);
377 int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
378 uint8_t *buffer)
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;
388 softc = (usbmass_softc_t *) dev->ud_private;
390 cbwcsw = KMALLOC(64,32);
391 sector = buffer;
393 cbw = (usbmass_cbw_t *) cbwcsw;
394 csw = (usbmass_csw_t *) cbwcsw;
397 * Fill in the fields of the CBW
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;
417 softc->umass_curtag++;
420 * Send the CBW
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;
435 * Get the data
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;
450 * Get the Status
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;
466 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1;
468 KFREE(cbwcsw);
470 return res;
474 /* *********************************************************************
475 * usbmass_write_sector(dev,sectornum,seccnt,buffer)
477 * Writes a sector to the device
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
485 * Return value:
486 * status
487 ********************************************************************* */
489 static int usbmass_write_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
490 uint8_t *buffer)
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;
500 softc = (usbmass_softc_t *) dev->ud_private;
502 cbwcsw = KMALLOC(64,32);
503 sector = buffer;
505 cbw = (usbmass_cbw_t *) cbwcsw;
506 csw = (usbmass_csw_t *) cbwcsw;
509 * Fill in the fields of the CBW
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;
529 softc->umass_curtag++;
532 * Send the CBW
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);
541 * Send the data
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);
550 * Get the Status
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);
560 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1;
562 KFREE(cbwcsw);
564 return res;
567 /* *********************************************************************
568 * usbmass_read_capacity(dev,sectornum,buffer)
570 * Reads a sector from the device.
572 * Input parameters:
573 * dev - usb device
574 * sectornum - sector number to read
575 * buffer - place to put sector we read
577 * Return value:
578 * status
579 ********************************************************************* */
581 int usbmass_read_capacity(usbdev_t *dev,uint32_t *size);
582 int usbmass_read_capacity(usbdev_t *dev,uint32_t *size)
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;
592 softc = (usbmass_softc_t *) dev->ud_private;
594 cbwcsw = KMALLOC(64,32);
595 sector = KMALLOC(64,32);
597 memset(sector,0,64);
599 cbw = (usbmass_cbw_t *) cbwcsw;
600 csw = (usbmass_csw_t *) cbwcsw;
602 *size = 0;
605 * Fill in the fields of the CBW
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;
625 softc->umass_curtag++;
628 * Send the CBW
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);
636 if (res == 4) {
637 usbmass_stall_recovery(dev);
638 KFREE(cbwcsw);
639 KFREE(sector);
640 return -1;
644 * Get the data
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);
652 if (res == 4) {
653 usbmass_stall_recovery(dev);
654 KFREE(cbwcsw);
655 KFREE(sector);
656 return -1;
660 * Get the Status
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);
669 KFREE(cbwcsw);
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);
676 KFREE(sector);
678 return 0;
684 /* *********************************************************************
685 * usbmass_attach(dev,drv)
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.
691 * Input parameters:
692 * dev - usb device, in the "addressed" state.
693 * drv - the driver table entry that matched
695 * Return value:
697 ********************************************************************* */
699 static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv)
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;
709 dev->ud_drv = drv;
711 softc = KMALLOC(sizeof(usbmass_softc_t),0);
712 memset(softc,0,sizeof(usbmass_softc_t));
713 dev->ud_private = softc;
715 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
716 if (ifdscr == NULL) {
717 return -1;
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;
728 for (idx = 0; idx < 2; idx++) {
729 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx);
731 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) {
732 outdscr = epdscr;
734 else {
735 indscr = epdscr;
740 if (!indscr || !outdscr) {
742 * Could not get descriptors, something is very wrong.
743 * Leave device addressed but not configured.
745 return -1;
749 * Choose the standard configuration.
752 usb_set_configuration(dev,cfgdscr->bConfigurationValue);
755 * Open the pipes.
758 softc->umass_inpipe = usb_open_pipe(dev,indscr);
759 softc->umass_outpipe = usb_open_pipe(dev,outdscr);
760 softc->umass_curtag = 0x12345678;
763 * Save pointer in global unit table so we can
764 * match CFE devices up with USB ones
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;
778 console_log("USBMASS: Unit %d connected",softc->umass_unit);
779 #endif
781 usbmass_dev = dev;
783 return 0;
786 /* *********************************************************************
787 * usbmass_detach(dev)
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.
794 * Input parameters:
795 * dev - usb device
797 * Return value:
799 ********************************************************************* */
801 static int usbmass_detach(usbdev_t *dev)
803 usbmass_softc_t *softc;
804 softc = (usbmass_softc_t *) dev->ud_private;
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
811 KFREE(softc);
812 return 0;
817 #ifdef _CFE_
820 /* *********************************************************************
821 * usbdisk_sectorshift(size)
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.
829 * Input parameters:
830 * size - sector size
832 * Return value:
833 * # of bits to shift
834 ********************************************************************* */
836 #define usbdisk_sectorshift(size) (((size)==2048)?11:9)
839 /* *********************************************************************
840 * usbdisk_probe(drv,probe_a,probe_b,probe_ptr)
842 * Our probe routine. Attach an empty USB disk device to the firmware.
844 * Input parameters:
845 * drv - driver structure
846 * probe_a - not used
847 * probe_b - not used
848 * probe_ptr - not used
850 * Return value:
851 * nothing
852 ********************************************************************* */
854 static void usbdisk_probe(cfe_driver_t *drv,
855 unsigned long probe_a, unsigned long probe_b,
856 void *probe_ptr)
858 usbdisk_t *softc;
859 char descr[128];
861 softc = (usbdisk_t *) KMALLOC(sizeof(usbdisk_t),0);
863 memset(softc,0,sizeof(usbdisk_t));
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;
870 xsprintf(descr,"USB Disk unit %d",(int)probe_a);
872 cfe_attach(drv,softc,NULL,descr);
876 /* *********************************************************************
877 * usbdisk_open(ctx)
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.
883 * Input parameters:
884 * ctx - device context
886 * Return value:
887 * 0 if ok, else error code
888 ********************************************************************* */
891 static int usbdisk_open(cfe_devctx_t *ctx)
893 usbdisk_t *softc = ctx->dev_softc;
894 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit];
895 uint32_t size;
896 int res;
898 if (!dev) return CFE_ERR_NOTREADY;
900 usbmass_request_sense(dev);
902 res = usbmass_read_capacity(dev,&size);
903 if (res < 0) return res;
905 softc->usbdisk_ttlsect = size;
907 return 0;
910 /* *********************************************************************
911 * usbdisk_read(ctx,buffer)
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.
917 * Input parameters:
918 * ctx - device context
919 * buffer - buffer descriptor
921 * Return value:
922 * number of bytes read, or <0 if an error occured
923 ********************************************************************* */
925 static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
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;
939 if (!dev) return CFE_ERR_NOTREADY;
941 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize);
943 bptr = buffer->buf_ptr;
944 blen = buffer->buf_length;
945 offset = buffer->buf_offset;
946 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift;
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,&sector[offset & (softc->usbdisk_sectorsize-1)],amtcopy);
955 bptr += amtcopy;
956 offset += amtcopy;
957 blen -= amtcopy;
960 if (blen >= softc->usbdisk_sectorsize) {
961 int seccnt;
963 lba = (offset >> sectorshift);
964 seccnt = (blen >> sectorshift);
966 res = usbmass_read_sector(dev,lba,seccnt,bptr);
967 if (res < 0) goto out;
969 amtcopy = seccnt << sectorshift;
970 bptr += amtcopy;
971 offset += amtcopy;
972 blen -= amtcopy;
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;
986 out:
987 buffer->buf_retlen = bptr - buffer->buf_ptr;
989 return res;
992 /* *********************************************************************
993 * usbdisk_inpstat(ctx,inpstat)
995 * Test input status for the IDE disk. Disks are always ready
996 * to read.
998 * Input parameters:
999 * ctx - device context
1000 * inpstat - input status structure
1002 * Return value:
1004 ********************************************************************* */
1006 static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
1008 /* usbdisk_t *softc = ctx->dev_softc; */
1010 inpstat->inp_status = 1;
1011 return 0;
1014 /* *********************************************************************
1015 * usbdisk_write(ctx,buffer)
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.
1021 * Input parameters:
1022 * ctx - device context
1023 * buffer - buffer descriptor
1025 * Return value:
1026 * number of bytes write, or <0 if an error occured
1027 ********************************************************************* */
1029 static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
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;
1043 if (!dev) return CFE_ERR_NOTREADY;
1045 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize);
1047 bptr = buffer->buf_ptr;
1048 blen = buffer->buf_length;
1049 offset = buffer->buf_offset;
1050 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift;
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(&sector[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;
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;
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;
1089 out:
1090 buffer->buf_retlen = bptr - buffer->buf_ptr;
1092 return res;
1096 /* *********************************************************************
1097 * usbdisk_ioctl(ctx,buffer)
1099 * Process device I/O control requests for the IDE device.
1101 * Input parameters:
1102 * ctx - device context
1103 * buffer - buffer descriptor
1105 * Return value:
1106 * 0 if ok
1107 * else error code
1108 ********************************************************************* */
1110 static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
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;
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;
1134 return 0;
1137 /* *********************************************************************
1138 * usbdisk_close(ctx)
1140 * Close the I/O device.
1142 * Input parameters:
1143 * ctx - device context
1145 * Return value:
1146 * 0 if ok, else error code
1147 ********************************************************************* */
1149 static int usbdisk_close(cfe_devctx_t *ctx)
1151 /* usbdisk_t *softc = ctx->dev_softc; */
1153 return 0;
1157 #endif