From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1OGFKm-0002pN-8G for mharc-grub-devel@gnu.org; Sun, 23 May 2010 13:51:32 -0400 Received: from [140.186.70.92] (port=40789 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGFKf-0002oe-QF for grub-devel@gnu.org; Sun, 23 May 2010 13:51:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OGFKb-0007tk-25 for grub-devel@gnu.org; Sun, 23 May 2010 13:51:25 -0400 Received: from mail-bw0-f41.google.com ([209.85.214.41]:61305) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OGFKa-0007tZ-Eo for grub-devel@gnu.org; Sun, 23 May 2010 13:51:21 -0400 Received: by bwz2 with SMTP id 2so671987bwz.0 for ; Sun, 23 May 2010 10:51:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:subject:references:in-reply-to :x-enigmail-version:content-type; bh=M+aJ51s/jSYP6alG2mCAfbIpqzR+Yluyj3e0o3skIXg=; b=rlvt6xfXP2610/5dyqZwj0d2KxwiMRedUcdjzjOlABLkJLf8VVehX/5RKYI3hAjnLr ABBr12HXkpVv5+FkF+vnVjO5RWAK0fDpSuWxJcBQ6lPyJsEPtlRSizvjPHyg8Dq6o7ff m5GzzL+VKg5sDpdOaaeKqBvFRMHEevhvkxPgo= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:x-enigmail-version:content-type; b=hnAxw75Jng6zgUGn6NtfKGzr4cMKSh05Hzde77kYwlRlV7zMMzVehO4qXvN/qS/Rbz m64QpSdCPMxaEY3SxS9MuX1tI18T4iw+rVEgeVndVbhhIsdFZVCN5NGQRc7yTB7Vjyw1 dPIr1hmF8kLcdnuLHNV8tgjtGVne2+FCFFagU= Received: by 10.204.38.87 with SMTP id a23mr1817825bke.37.1274637079318; Sun, 23 May 2010 10:51:19 -0700 (PDT) Received: from debian.bg45.phnet (236-8.203-62.cust.bluewin.ch [62.203.8.236]) by mx.google.com with ESMTPS id d13sm15138314bkd.17.2010.05.23.10.51.16 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 23 May 2010 10:51:18 -0700 (PDT) Message-ID: <4BF96B0D.5070701@gmail.com> Date: Sun, 23 May 2010 19:51:09 +0200 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109) MIME-Version: 1.0 To: The development of GNU GRUB References: <1268605383.2839.26.camel@homenes1> <4BB657BB.60801@gmail.com> <1270669741.2732.129.camel@homenes1> <4BBCED68.3080900@gmail.com> <1270762038.2730.37.camel@homenes1> <4BC892C3.3090507@gmail.com> <1271794445.4221.93.camel@pracovna> <1274485618.18038.56.camel@pracovna> <4BF86523.4090509@gmail.com> <1274610426.5231.67.camel@pracovna> <4BF93E8F.3020605@gmail.com> In-Reply-To: <4BF93E8F.3020605@gmail.com> X-Enigmail-Version: 0.95.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="------------enig451A3162B1C0513E1C43E4BA" X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: Re: [Patch] [bug #26237] multiple problems with usb devices X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 May 2010 17:51:31 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig451A3162B1C0513E1C43E4BA Content-Type: multipart/mixed; boundary="------------010507070401040703060508" This is a multi-part message in MIME format. --------------010507070401040703060508 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Vladimir '=CF=86-coder/phcoder' Serbinenko wrote: >> I will look into yeeloongfw branch, I got Bazaar working yesterday >> evening only... I agree with You, first should be solved known problem= s >> on simple base. >> Unfortunately, I probably cannot help You as I don't have GEODE or >> Yeeloong... I can hope only that my corrections would help You or >> inspire You in some other ways. >> =20 >> =20 > I don't think it's something deeply specific to Geode. Other than havin= g > Geode MSR instead of PCI configuration space it's normal OHCI. Actually= > with your patch when you forgot to power device up it resulted in > similar symptoms on PCI OHCI controller. OHCI specification mentions > different ways to configure power settings. I guess geode defaults to > another mode than most controllers do. Or perhaps I need to somehow > enable ports. > =20 I was right this was the problem with grub_ohci_portstatus. RHUBPORT is of type R/WC and not of type R/W so you just write to it the bits you want to modify and not (previous OR modification). New grub_ohci_portstatus looks like (or patch attached): #define GRUB_OHCI_SET_PORT_ENABLE (1 << 1) #define GRUB_OHCI_CLEAR_PORT_ENABLE (1 << 0) #define GRUB_OHCI_SET_PORT_RESET (1 << 4) #define GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE (1 << 20) static grub_err_t grub_ohci_portstatus (grub_usb_controller_t dev, unsigned int port, unsigned int enable) { struct grub_ohci *o =3D (struct grub_ohci *) dev->data; grub_dprintf ("ohci", "begin of portstatus=3D0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));= grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_SET_PORT_RESET); grub_millisleep (50); /* For root hub should be nominaly 50ms */ /* End the reset signaling. */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); grub_millisleep (10); if (enable) grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_SET_PORT_ENABLE); else grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_CLEAR_PORT_ENABLE); grub_millisleep (10); grub_dprintf ("ohci", "end of portstatus=3D0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); return GRUB_ERR_NONE; } --=20 Regards Vladimir '=CF=86-coder/phcoder' Serbinenko --------------010507070401040703060508 Content-Type: text/x-diff; name="yeeloong_usb_i.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline; filename="yeeloong_usb_i.diff" =3D=3D=3D modified file 'bus/usb/ohci.c' --- bus/usb/ohci.c 2010-05-22 22:17:51 +0000 +++ bus/usb/ohci.c 2010-05-23 17:27:15 +0000 @@ -96,7 +96,11 @@ GRUB_OHCI_REG_FRAME_INTERVAL, GRUB_OHCI_REG_PERIODIC_START =3D 16, GRUB_OHCI_REG_RHUBA =3D 18, - GRUB_OHCI_REG_RHUBPORT =3D 21 + GRUB_OHCI_REG_RHUBPORT =3D 21, + GRUB_OHCI_REG_LEGACY_CONTROL =3D 0x100, + GRUB_OHCI_REG_LEGACY_INPUT =3D 0x104, + GRUB_OHCI_REG_LEGACY_OUTPUT =3D 0x108, + GRUB_OHCI_REG_LEGACY_STATUS =3D 0x10c } grub_ohci_reg_t; =20 #define GRUB_OHCI_RHUB_PORT_POWER_MASK 0x300 @@ -195,7 +199,7 @@ if (! o) return 1; =20 - o->iobase =3D grub_pci_device_map_range (dev, base, 0x100); + o->iobase =3D grub_pci_device_map_range (dev, base, 0x800); =20 grub_dprintf ("ohci", "base=3D%p\n", o->iobase); =20 @@ -212,10 +216,48 @@ if ((revision & 0xFF) !=3D 0x10) goto fail; =20 - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBA, - (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA) - & ~GRUB_OHCI_RHUB_PORT_POWER_MASK) - | GRUB_OHCI_RHUB_PORT_ALL_POWERED); + + { + grub_uint32_t control; + /* Check SMM/BIOS ownership of OHCI (SMM =3D USB Legacy Support driv= er for BIOS) */ + control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); + if ((control & 0x100) !=3D 0) + { + unsigned i; + grub_dprintf("ohci", "OHCI is owned by SMM\n"); + /* Do change of ownership */ + /* Ownership change request */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, (1<<3)); /* XXX: Magi= c. */ + /* Waiting for SMM deactivation */ + for (i=3D0; i < 10; i++) + { + if ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & 0x100) =3D=3D= 0) + { + grub_dprintf("ohci", "Ownership changed normally.\n"); + break; + } + grub_millisleep (100); + } + if (i >=3D 10) + { + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & ~0x100); + grub_dprintf("ohci", "Ownership changing timeout, change forced !\n= "); + } + } + else if (((control & 0x100) =3D=3D 0) &&=20 + ((control & 0xc0) !=3D 0)) /* Not owned by SMM nor reset */ + { + grub_dprintf("ohci", "OHCI is owned by BIOS\n"); + /* Do change of ownership - not implemented yet... */ + /* In fact we probably need to do nothing ...? */ + } + else + { + grub_dprintf("ohci", "OHCI is not owned by SMM nor BIOS\n"); + /* We can setup OHCI. */ + } =20 + } =20 /* Suspend the OHCI by issuing a reset. */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. = */ @@ -232,15 +274,58 @@ GRUB_OHCI_PERIODIC_START); =20 /* Setup the HCCA. */ + o->hcca->donehead =3D 0; grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, o->hcca_addr); grub_dprintf ("ohci", "OHCI HCCA\n"); =20 + /* Misc. pre-sets. */ + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears= WDH */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); + + /* Check OHCI Legacy Support */ + if ((revision & 0x100) !=3D 0) + { + grub_dprintf ("ohci", "Legacy Support registers detected\n"); + grub_dprintf ("ohci", "Current state of legacy control reg.: 0x%04= x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL)); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL, + (grub_ohci_readreg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL)) & ~1); + grub_dprintf ("ohci", "OHCI Legacy Support disabled.\n"); + } + /* Enable the OHCI. */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, (2 << 6)); grub_dprintf ("ohci", "OHCI enable: 0x%02x\n", (grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) >> 6) & 3); =20 + /* Power on all ports */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBA, + (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA) + & ~GRUB_OHCI_RHUB_PORT_POWER_MASK) + | GRUB_OHCI_RHUB_PORT_ALL_POWERED); + /* Wait for stable power (100ms) and stable attachment (100ms) */ + /* I.e. minimum wait time should be probably 200ms. */ + /* We assume that device is attached when ohci is loaded. */ + /* Some devices take long time to power-on or indicate attach. */ + /* Here is some experimental value which should probably mostly work. = */ + /* Cameras with manual USB mode selection and maybe some other similar= + * devices will not work in some cases - they are repowered during + * ownership change and then they are starting slowly and mostly they + * are wanting select proper mode again... + * The same situation can be on computers where BIOS not set-up OHCI + * to be at least powered USB bus (maybe it is Yeelong case...?) + * Possible workaround could be for example some prompt + * for user with confirmation of proper USB device connection. + * Another workaround - "rmmod usbms", "rmmod ohci", proper start + * and configuration of USB device and then "insmod ohci" + * and "insmod usbms". */ + grub_millisleep (500);=09 + /* Link to ohci now that initialisation is successful. */ o->next =3D ohci; ohci =3D o; @@ -317,13 +402,29 @@ token |=3D toggle << 24; token |=3D 1 << 25; =20 + /* Set "Not accessed" error code */ + token |=3D 15 << 28; + buffer =3D data; buffer_end =3D buffer + size - 1; =20 + /* Set correct buffer values in TD if zero transfer occurs */ + if (size) + { + buffer =3D (grub_uint32_t) data; + buffer_end =3D buffer + size - 1; + td->buffer =3D grub_cpu_to_le32 (buffer); + td->buffer_end =3D grub_cpu_to_le32 (buffer_end); + } + else=20 + { + td->buffer =3D 0; + td->buffer_end =3D 0; + } + + /* Set the rest of TD */ td->token =3D grub_cpu_to_le32 (token); - td->buffer =3D grub_cpu_to_le32 (buffer); td->next_td =3D 0; - td->buffer_end =3D grub_cpu_to_le32 (buffer_end); } =20 static grub_usb_err_t @@ -342,7 +443,9 @@ grub_uint32_t status; grub_uint32_t control; grub_usb_err_t err; - int i; + int i, j; + grub_uint64_t maxtime; + int err_timeout =3D 0; =20 /* Allocate an Endpoint Descriptor. */ ed_chunk =3D grub_memalign_dma32 (256, sizeof (*ed)); @@ -375,13 +478,25 @@ + (i + 1) * sizeof (td_list[0])); } =20 + /* The last-1 TD token we should change to enable interrupt when TD fi= nishes. + * As OHCI interrupts are disabled, it does only setting of WDH bit in= + * HcInterruptStatus register - and that is what we want to safely det= ect + * normal end of all transactions. */ + td_list[transfer->transcnt - 1].token &=3D ~(7 << 21); + + td_list[transfer->transcnt].token =3D 0; + td_list[transfer->transcnt].buffer =3D 0; + td_list[transfer->transcnt].buffer_end =3D 0; + td_list[transfer->transcnt].next_td =3D + (grub_uint32_t) &td_list[transfer->transcnt]; + =20 /* Setup the Endpoint Descriptor. */ =20 /* Set the device address. */ target =3D transfer->devaddr; =20 - /* Set the endpoint. */ - target |=3D transfer->endpoint << 7; + /* Set the endpoint. It should be masked, we need 4 bits only. */ + target |=3D (transfer->endpoint & 15) << 7; =20 /* Set the device speed. */ target |=3D (transfer->dev->speed =3D=3D GRUB_USB_SPEED_LOW) << 13; @@ -400,6 +515,30 @@ =20 grub_dprintf ("ohci", "program OHCI\n"); =20 + /* Disable the Control and Bulk lists. */ + control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); + control &=3D ~(3 << 4); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); + + /* Clear BulkListFilled and ControlListFilled. */ + status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); + status &=3D ~(3 << 1); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); + + /* Now we should wait for start of next frame. Because we are not usin= g + * interrupt, we reset SF bit and wait when it goes to 1. */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) =3D=3D= 0); + /* Now it should be safe to change CONTROL and BULK lists. */ + + /* This we do for safety's sake - it should be done in previous call + * of grub_ohci_transfer and nobody should change it in meantime... + * It should be done before start of control or bulk OHCI list. */ =20 + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears= WDH */ + /* Program the OHCI to actually transfer. */ switch (transfer->type) { @@ -407,24 +546,17 @@ { grub_dprintf ("ohci", "add to bulk list\n"); =20 - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - - /* Disable the Control and Bulk lists. */ - control &=3D ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - - /* Clear BulkListFilled. */ - status &=3D ~(1 << 2); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + /* Set BulkList Head and Current */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, ed_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); =20 /* Enable the Bulk list. */ + control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); control |=3D 1 << 5; grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); =20 /* Set BulkListFilled. */ + status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); status |=3D 1 << 2; grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); =20 @@ -433,21 +565,9 @@ =20 case GRUB_USB_TRANSACTION_TYPE_CONTROL: { - grub_dprintf ("ohci", "add to control list\n"); - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - - /* Disable the Control and Bulk lists. */ - control &=3D ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - - /* Clear ControlListFilled. */ - status &=3D ~(1 << 1); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + /* Set ControlList Head and Current */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, ed_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD+1, - ed_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); =20 /* Enable the Control list. */ control |=3D 1 << 4; @@ -465,36 +585,77 @@ grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL), grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS)); =20 + /* Safety measure to avoid a hang. */ + maxtime =3D grub_get_time_ms () + 1000; +=09 /* Wait until the transfer is completed or STALLs. */ - while ((ed->td_head & ~0xf) !=3D (ed->td_tail & ~0xf)) + do { grub_cpu_idle (); =20 - grub_dprintf ("ohci", "head=3D0x%02x tail=3D0x%02x\n", ed->td_head= , ed->td_tail); - - /* Detected a STALL. */ - if (ed->td_head & 1) + /* Detected a HALT. */ + if (grub_le_to_cpu32 (ed->td_head) & 1) + break; + =20 + if ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x2) !=3D = 0) + { + if ((grub_le_to_cpu32 (o->hcca->donehead) & ~0xf) + =3D=3D td_list_addr + (transfer->transcnt - 1) * sizeof (td_list[= 0])) + break; + + /* Done Head can be updated on some another place if ED is hal= ted. */ =20 + if (grub_le_to_cpu32 (ed->td_head) & 1) + break; + + /* If there is not HALT in ED, it is not correct, so debug it,= reset + * donehead and WDH and continue waiting. */ + grub_dprintf ("ohci", "Incorrect HccaDoneHead=3D0x%08x\n", + o->hcca->donehead); + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + continue; + } + /* Timeout ? */ + if (grub_get_time_ms () > maxtime) + { + /* Disable the Control and Bulk lists. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & ~(3 << 4)); + err_timeout =3D 1; + break; + } + + if ((ed->td_head & ~0xf) =3D=3D (ed->td_tail & ~0xf)) break; } - - grub_dprintf ("ohci", "complete\n"); - -/* if (ed->td_head & 1) */ -/* err =3D GRUB_USB_ERR_STALL; */ -/* else if (ed->td */ - - - if (ed->td_head & 1) - { + while (1); + + if (err_timeout) + { + err =3D GRUB_ERR_TIMEOUT; + grub_dprintf("ohci", "Timeout, target=3D%08x, head=3D%08x\n\t\ttai= l=3D%08x, next=3D%08x\n", + grub_le_to_cpu32(ed->target), + grub_le_to_cpu32(ed->td_head), + grub_le_to_cpu32(ed->td_tail), + grub_le_to_cpu32(ed->next_ed)); + } + else if (grub_le_to_cpu32 (ed->td_head) & 1) + { + grub_uint32_t td_err_addr; grub_uint8_t errcode; - grub_ohci_td_t tderr; - grub_uint32_t td_err_addr; + grub_ohci_td_t tderr =3D NULL; =20 - td_err_addr =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD); + td_err_addr =3D (grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD) &= ~0xf); + if (td_err_addr =3D=3D 0) + /* If DONEHEAD=3D=3D0 it means that correct address is in HCCA. + * It should be always now! */ + td_err_addr =3D (grub_le_to_cpu32 (o->hcca->donehead) & ~0xf); =20 tderr =3D (grub_ohci_td_t) ((char *) td_list + (td_err_addr - td_list_addr)); - errcode =3D tderr->token >> 28; +=20 + errcode =3D grub_le_to_cpu32 (tderr->token) >> 28; =20 + grub_dprintf ("ohci", "OHCI errcode=3D0x%02x\n", errcode); =20 switch (errcode) { @@ -540,11 +701,17 @@ case 8: /* XXX: Data overrun error. */ err =3D GRUB_USB_ERR_DATA; + j =3D ((grub_uint32_t)tderr - (grub_uint32_t)td_list) / sizeof (*td_l= ist); + grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", = tderr, j); break; =20 case 9: /* XXX: Data underrun error. */ err =3D GRUB_USB_ERR_DATA; + grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\= n", + 1 + grub_le_to_cpu32 (tderr->buffer_end) - grub_le_to_c= pu32 (tderr->buffer)); + j =3D ((grub_uint32_t)tderr - (grub_uint32_t)td_list) / sizeof (*td_l= ist); + grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",= tderr, j); break; =20 case 10: @@ -582,42 +749,74 @@ =20 /* Clear BulkListFilled and ControlListFilled. */ status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - status &=3D ~((1 << 2) | (1 << 3)); + status &=3D ~(3 << 1); grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + =20 + /* Set ED to be skipped - for safety */ + ed->target |=3D grub_cpu_to_le32 (1 << 14); + + /* Now we should wait for start of next frame. + * It is necessary because we will invalidate pointer to ED and it + * can be on OHCI active till SOF! + * Because we are not using interrupt, we reset SF bit and wait when + * it goes to 1. */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) =3D=3D= 0); + /* Now it should be safe to change CONTROL and BULK lists. */ + =20 + /* Important cleaning. */ + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears= WDH */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); + + grub_dprintf ("ohci", "OHCI finished, freeing, err=3D0x%02x\n", + err); + =20 /* XXX */ - grub_free (td_list); - grub_free (ed); + grub_dma_free (td_list_chunk); + grub_dma_free (ed_chunk); =20 return err; } =20 +#define GRUB_OHCI_SET_PORT_ENABLE (1 << 1) +#define GRUB_OHCI_CLEAR_PORT_ENABLE (1 << 0) +#define GRUB_OHCI_SET_PORT_RESET (1 << 4) +#define GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE (1 << 20) + static grub_err_t grub_ohci_portstatus (grub_usb_controller_t dev, unsigned int port, unsigned int enable) { struct grub_ohci *o =3D (struct grub_ohci *) dev->data; - grub_uint32_t status; - - /* Reset the port. */ - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); - status |=3D (1 << 4); /* XXX: Magic. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status); - grub_millisleep (100); + + grub_dprintf ("ohci", "begin of portstatus=3D0x%02x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port))= ; + + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET); + grub_millisleep (50); /* For root hub should be nominaly 50ms */ =20 /* End the reset signaling. */ - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); - status |=3D (1 << 20); /* XXX: Magic. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status); - grub_millisleep (10); - - /* Enable the port. */ - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); - status |=3D (enable << 1); /* XXX: Magic. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status); - - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); - grub_dprintf ("ohci", "portstatus=3D0x%02x\n", status); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); + grub_millisleep (10); + + if (enable) + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_ENABLE); + else + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_CLEAR_PORT_ENABLE); + grub_millisleep (10); + + grub_dprintf ("ohci", "end of portstatus=3D0x%02x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); =20 return GRUB_ERR_NONE; } =3D=3D=3D modified file 'bus/usb/uhci.c' --- bus/usb/uhci.c 2010-05-05 08:40:48 +0000 +++ bus/usb/uhci.c 2010-05-23 13:08:06 +0000 @@ -174,14 +174,15 @@ return 1; =20 u->iobase =3D base & GRUB_UHCI_IOMASK; - grub_dprintf ("uhci", "class=3D0x%02x 0x%02x interface 0x%02x base=3D0= x%x\n", - class, subclass, interf, u->iobase); =20 /* Reserve a page for the frame list. */ u->framelist =3D grub_memalign (4096, 4096); if (! u->framelist) goto fail; =20 + grub_dprintf ("uhci", "class=3D0x%02x 0x%02x interface 0x%02x base=3D0= x%x framelist=3D%p\n", + class, subclass, interf, u->iobase, u->framelist); + /* The framelist pointer of UHCI is only 32 bits, make sure this code works on on 64 bits architectures. */ #if GRUB_CPU_SIZEOF_VOID_P =3D=3D 8 @@ -221,6 +222,9 @@ } #endif =20 + grub_dprintf ("uhci", "QH=3D%p, TD=3D%p\n", + u->qh, u->td); + /* Link all Transfer Descriptors in a list of available Transfer Descriptors. */ for (i =3D 0; i < 256; i++) @@ -441,6 +445,8 @@ if (! qh) return grub_errno; =20 + grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase); + =20 for (i =3D 0; i < transfer->transcnt; i++) { grub_usb_transaction_t tr =3D &transfer->transactions[i]; @@ -548,7 +554,8 @@ =20 fail: =20 - grub_dprintf ("uhci", "transaction failed\n"); + if (err !=3D GRUB_USB_ERR_NONE) + grub_dprintf ("uhci", "transaction failed\n"); =20 /* Place the QH back in the free list and deallocate the associated TDs. */ @@ -583,6 +590,8 @@ unsigned int status; grub_uint64_t endtime; =20 + grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase); + =20 grub_dprintf ("uhci", "enable=3D%d port=3D%d\n", enable, port); =20 if (port =3D=3D 0) @@ -631,6 +640,8 @@ int reg; unsigned int status; =20 + grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase); + =20 if (port =3D=3D 0) reg =3D GRUB_UHCI_REG_PORTSC1; else if (port =3D=3D 1) =3D=3D=3D modified file 'bus/usb/usb.c' --- bus/usb/usb.c 2009-11-09 17:43:53 +0000 +++ bus/usb/usb.c 2010-05-23 13:08:06 +0000 @@ -107,7 +107,7 @@ { int i; =20 - for (i =3D 0; i < 16; i++) + for (i =3D 0; i < 256; i++) dev->toggle[i] =3D 0; =20 return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT @@ -163,6 +163,16 @@ grub_usb_err_t err; int i; =20 + /* First we have to read first 8 bytes only and determine + * max. size of packet */ + dev->descdev.maxsize0 =3D 0; /* invalidating, for safety only, can be = removed if it is sure it is zero here */ + err =3D grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE, + 0, 8, (char *) &dev->descdev); + if (err) + return err; + + /* Now we have valid value in dev->descdev.maxsize0, + * so we can read whole device descriptor */ err =3D grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE, 0, sizeof (struct grub_usb_desc_device), (char *) &dev->descdev); =3D=3D=3D modified file 'bus/usb/usbtrans.c' --- bus/usb/usbtrans.c 2010-05-22 22:13:37 +0000 +++ bus/usb/usbtrans.c 2010-05-23 13:10:07 +0000 @@ -138,7 +138,7 @@ /* End with an empty OUT transaction. */ transfer->transactions[datablocks + 1].size =3D 0; transfer->transactions[datablocks + 1].data =3D 0; - if (reqtype & 128) + if ((reqtype & 128) && datablocks) transfer->transactions[datablocks + 1].pid =3D GRUB_USB_TRANSFER_TYP= E_OUT; else transfer->transactions[datablocks + 1].pid =3D GRUB_USB_TRANSFER_TYP= E_IN; @@ -148,6 +148,7 @@ err =3D dev->controller.dev->transfer (&dev->controller, transfer); =20 grub_free (transfer->transactions); + =20 grub_free (transfer); grub_dma_free (data_chunk); grub_dma_free (setupdata_chunk); @@ -207,7 +208,7 @@ datablocks =3D ((size + max - 1) / max); transfer->transcnt =3D datablocks; transfer->size =3D size - 1; - transfer->endpoint =3D endpoint; + transfer->endpoint =3D endpoint & 15; transfer->devaddr =3D dev->addr; transfer->type =3D GRUB_USB_TRANSACTION_TYPE_BULK; transfer->max =3D max; =3D=3D=3D modified file 'commands/usbtest.c' --- commands/usbtest.c 2010-05-23 12:37:28 +0000 +++ commands/usbtest.c 2010-05-23 13:41:32 +0000 @@ -148,6 +148,8 @@ =20 grub_printf ("%s speed device\n", usb_devspeed[dev->speed]); =20 + return 0; + for (i =3D 0; i < descdev->configcnt; i++) { struct grub_usb_desc_config *config; =3D=3D=3D modified file 'disk/scsi.c' --- disk/scsi.c 2010-03-05 14:29:28 +0000 +++ disk/scsi.c 2010-05-23 13:08:06 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include =20 =0C static grub_scsi_dev_t grub_scsi_dev_list; @@ -50,7 +51,62 @@ } =20 =0C -/* Determine the the device is removable and the type of the device +/* Check result of previous operation. */ +static grub_err_t +grub_scsi_request_sense (grub_scsi_t scsi) +{ + struct grub_scsi_request_sense rs; + struct grub_scsi_request_sense_data rsd; + grub_err_t err; + + rs.opcode =3D grub_scsi_cmd_request_sense; + rs.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + rs.reserved1 =3D 0; + rs.reserved2 =3D 0; + rs.alloc_length =3D 0x12; /* XXX: Hardcoded for now */ + rs.control =3D 0; + grub_memset (rs.pad, 0, sizeof(rs.pad)); + + err =3D scsi->dev->read (scsi, sizeof (rs), (char *) &rs, + sizeof (rsd), (char *) &rsd); + if (err) + return err; + + return GRUB_ERR_NONE; +} +/* Self commenting... */ +static grub_err_t +grub_scsi_test_unit_ready (grub_scsi_t scsi) +{ + struct grub_scsi_test_unit_ready tur; + grub_err_t err; + grub_err_t err_sense; + =20 + tur.opcode =3D grub_scsi_cmd_test_unit_ready; + tur.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + tur.reserved1 =3D 0; + tur.reserved2 =3D 0; + tur.reserved3 =3D 0; + tur.control =3D 0; + grub_memset (tur.pad, 0, sizeof(tur.pad)); + + err =3D scsi->dev->read (scsi, sizeof (tur), (char *) &tur, + 0, NULL); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + =20 + if (err) + return err; + + return GRUB_ERR_NONE; +} + +/* Determine if the device is removable and the type of the device SCSI. */ static grub_err_t grub_scsi_inquiry (grub_scsi_t scsi) @@ -58,15 +114,26 @@ struct grub_scsi_inquiry iq; struct grub_scsi_inquiry_data iqd; grub_err_t err; + grub_err_t err_sense; =20 iq.opcode =3D grub_scsi_cmd_inquiry; iq.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + iq.page =3D 0; iq.reserved =3D 0; iq.alloc_length =3D 0x24; /* XXX: Hardcoded for now */ - iq.reserved2 =3D 0; + iq.control =3D 0; + grub_memset (iq.pad, 0, sizeof(iq.pad)); =20 err =3D scsi->dev->read (scsi, sizeof (iq), (char *) &iq, sizeof (iqd), (char *) &iqd); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + if (err) return err; =20 @@ -83,13 +150,27 @@ struct grub_scsi_read_capacity rc; struct grub_scsi_read_capacity_data rcd; grub_err_t err; + grub_err_t err_sense; =20 rc.opcode =3D grub_scsi_cmd_read_capacity; rc.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; - grub_memset (rc.reserved, 0, sizeof (rc.reserved)); - + rc.logical_block_addr =3D 0; + rc.reserved1 =3D 0; + rc.reserved2 =3D 0; + rc.PMI =3D 0; + rc.control =3D 0; + rc.pad =3D 0; +=09 err =3D scsi->dev->read (scsi, sizeof (rc), (char *) &rc, sizeof (rcd), (char *) &rcd); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; +/* err_sense is ignored for now and Request Sense Data also... */ + if (err) return err; =20 @@ -107,6 +188,8 @@ { grub_scsi_t scsi; struct grub_scsi_read10 rd; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -118,7 +201,16 @@ rd.reserved2 =3D 0; rd.pad =3D 0; =20 - return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->= blocksize, buf); + err =3D scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi-= >blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 /* Send a SCSI request for DISK: read SIZE sectors starting with @@ -129,6 +221,8 @@ { grub_scsi_t scsi; struct grub_scsi_read12 rd; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -139,7 +233,16 @@ rd.reserved =3D 0; rd.control =3D 0; =20 - return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->= blocksize, buf); + err =3D scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi-= >blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 #if 0 @@ -151,6 +254,8 @@ { grub_scsi_t scsi; struct grub_scsi_write10 wr; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -162,7 +267,16 @@ wr.reserved2 =3D 0; wr.pad =3D 0; =20 - return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi-= >blocksize, buf); + err =3D scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi= ->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 /* Send a SCSI request for DISK: write the data stored in BUF to SIZE @@ -172,7 +286,9 @@ grub_size_t size, char *buf) { grub_scsi_t scsi; - struct grub_scsi_write10 wr; + struct grub_scsi_write12 wr; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -181,9 +297,18 @@ wr.lba =3D grub_cpu_to_be32 (sector); wr.size =3D grub_cpu_to_be32 (size); wr.reserved =3D 0; - wr.pad =3D 0; - - return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi-= >blocksize, buf); + wr.control =3D 0; + + err =3D scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi= ->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + if (err_sense !=3D GRUB_ERR_NONE) + grub_errno =3D err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } #endif =20 @@ -235,6 +360,7 @@ grub_err_t err; int len; int lun; + grub_uint64_t maxtime; =20 scsi =3D grub_malloc (sizeof (*scsi)); if (! scsi) @@ -292,6 +418,31 @@ else disk->has_partitions =3D 1; =20 + + /* According to USB MS tests specification, issue Test Unit Ready + * until OK */ + maxtime =3D grub_get_time_ms () + 1000; + do + { + /* Timeout is necessary - for example in case when we have + * universal card reader with more LUNs and we have only + * one card inserted (or none), so only one LUN (or none) + * will be ready - and we want not to hang... */ + if (grub_get_time_ms () > maxtime) + { + err =3D GRUB_ERR_READ_ERROR; + grub_free (scsi); + grub_dprintf ("scsi", "LUN is not ready - timeout\n"); + return err; + } + err =3D grub_scsi_test_unit_ready (scsi); + } + while (err =3D=3D GRUB_ERR_READ_ERROR); + /* Reset grub_errno ! + * It is set to some error code in loop before... */ + grub_errno =3D GRUB_ERR_NONE; + + /* Read capacity of media */ err =3D grub_scsi_read_capacity (scsi); if (err) { @@ -302,12 +453,14 @@ =20 /* SCSI blocks can be something else than 512, although GRUB wants 512 byte blocks. */ - disk->total_sectors =3D ((scsi->size * scsi->blocksize) - << GRUB_DISK_SECTOR_BITS); + disk->total_sectors =3D ((grub_uint64_t)scsi->size + * (grub_uint64_t)scsi->blocksize) + >> GRUB_DISK_SECTOR_BITS; =20 - grub_dprintf ("scsi", "capacity=3D%llu, blksize=3D%d\n", - (unsigned long long) disk->total_sectors, - scsi->blocksize); + grub_dprintf ("scsi", "blocks=3D%u, blocksize=3D%u\n", + scsi->size, scsi->blocksize); + grub_dprintf ("scsi", "Disk total 512 sectors =3D %llu\n", + disk->total_sectors); =20 return GRUB_ERR_NONE; } =3D=3D=3D modified file 'disk/usbms.c' --- disk/usbms.c 2010-01-20 08:12:47 +0000 +++ disk/usbms.c 2010-05-23 14:08:52 +0000 @@ -84,7 +84,8 @@ struct grub_usb_desc_device *descdev =3D &usbdev->descdev; int i; =20 - if (descdev->class !=3D 0 || descdev->subclass || descdev->protoco= l !=3D 0) + if (descdev->class !=3D 0 || descdev->subclass || descdev->protoco= l !=3D 0 + || descdev->configcnt =3D=3D 0) return 0; =20 /* XXX: Just check configuration 0 for now. */ @@ -93,19 +94,31 @@ struct grub_usbms_dev *usbms; struct grub_usb_desc_if *interf; int j; - grub_uint8_t luns; + grub_uint8_t luns =3D 0; + + grub_dprintf ("usbms", "alive\n"); =20 interf =3D usbdev->config[0].interf[i].descif; =20 /* If this is not a USB Mass Storage device with a supported protocol, just skip it. */ + grub_dprintf ("usbms", "iterate: interf=3D%d, class=3D%d, subclass=3D= %d, protocol=3D%d\n", + i, interf->class, interf->subclass, interf->protocol); + if (interf->class !=3D GRUB_USB_CLASS_MASS_STORAGE - || interf->subclass !=3D GRUB_USBMS_SUBCLASS_BULK + || ( interf->subclass !=3D GRUB_USBMS_SUBCLASS_BULK && + /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */ + interf->subclass !=3D GRUB_USBMS_SUBCLASS_RBC && + interf->subclass !=3D GRUB_USBMS_SUBCLASS_MMC2 && + interf->subclass !=3D GRUB_USBMS_SUBCLASS_UFI && + interf->subclass !=3D GRUB_USBMS_SUBCLASS_SFF8070 ) || interf->protocol !=3D GRUB_USBMS_PROTOCOL_BULK) { continue; } =20 + grub_dprintf ("usbms", "alive\n"); + devcnt++; usbms =3D grub_zalloc (sizeof (struct grub_usbms_dev)); if (! usbms) @@ -114,6 +127,8 @@ usbms->dev =3D usbdev; usbms->interface =3D i; =20 + grub_dprintf ("usbms", "alive\n"); + /* Iterate over all endpoints of this interface, at least a IN and OUT bulk endpoint are required. */ for (j =3D 0; j < interf->endpointcnt; j++) @@ -125,14 +140,16 @@ { /* Bulk IN endpoint. */ usbms->in =3D endp; - grub_usb_clear_halt (usbdev, endp->endp_addr & 128); + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ usbms->in_maxsz =3D endp->maxpacket; } else if (!(endp->endp_addr & 128) && (endp->attrib & 3) =3D=3D 2)= { /* Bulk OUT endpoint. */ usbms->out =3D endp; - grub_usb_clear_halt (usbdev, endp->endp_addr & 128); + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ usbms->out_maxsz =3D endp->maxpacket; } } @@ -143,51 +160,63 @@ return 0; } =20 + grub_dprintf ("usbms", "alive\n"); + + /* XXX: Activate the first configuration. */ + grub_usb_set_configuration (usbdev, 1); + /* Query the amount of LUNs. */ err =3D grub_usb_control_msg (usbdev, 0xA1, 254, 0, i, 1, (char *) &luns); + =09 if (err) { /* In case of a stall, clear the stall. */ if (err =3D=3D GRUB_USB_ERR_STALL) { - grub_usb_clear_halt (usbdev, usbms->in->endp_addr & 3); - grub_usb_clear_halt (usbdev, usbms->out->endp_addr & 3); + grub_usb_clear_halt (usbdev, usbms->in->endp_addr); + grub_usb_clear_halt (usbdev, usbms->out->endp_addr); } - /* Just set the amount of LUNs to one. */ grub_errno =3D GRUB_ERR_NONE; usbms->luns =3D 1; } else - usbms->luns =3D luns; - - /* XXX: Check the magic values, does this really make - sense? */ - grub_usb_control_msg (usbdev, (1 << 6) | 1, 255, - 0, i, 0, 0); - - /* XXX: To make Qemu work? */ - if (usbms->luns =3D=3D 0) - usbms->luns =3D 1; + /* luns =3D 0 means one LUN with ID 0 present ! */ + /* We get from device not number of LUNs but highest + * LUN number. LUNs are numbered from 0,=20 + * i.e. number of LUNs is luns+1 ! */ + usbms->luns =3D luns + 1; + + grub_dprintf ("usbms", "alive\n"); =20 usbms->next =3D grub_usbms_dev_list; grub_usbms_dev_list =3D usbms; =20 - /* XXX: Activate the first configuration. */ - grub_usb_set_configuration (usbdev, 1); - +#if 0 /* All this part should be probably deleted. + * This make trouble on some devices if they are not in + * Phase Error state - and there they should be not in such state...= + * Bulk only mass storage reset procedure should be used only + * on place and in time when it is really necessary. */ + /* Reset recovery procedure */ /* Bulk-Only Mass Storage Reset, after the reset commands will be accepted. */ grub_usbms_reset (usbdev, i); + grub_usb_clear_halt (usbdev, usbms->in->endp_addr); + grub_usb_clear_halt (usbdev, usbms->out->endp_addr); +#endif =20 return 0; } =20 + grub_dprintf ("usbms", "alive\n"); return 0; } + grub_dprintf ("usbms", "alive\n"); =20 grub_usb_iterate (usb_iterate); + grub_dprintf ("usbms", "alive\n"); + } =20 =0C @@ -225,6 +254,7 @@ static grub_uint32_t tag =3D 0; grub_usb_err_t err =3D GRUB_USB_ERR_NONE; int retrycnt =3D 3 + 1; + grub_size_t i; =20 retry: retrycnt--; @@ -237,73 +267,89 @@ cbw.tag =3D tag++; cbw.transfer_length =3D grub_cpu_to_le32 (size); cbw.flags =3D (!read_write) << GRUB_USBMS_DIRECTION_BIT; - cbw.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + cbw.lun =3D scsi->lun; /* In USB MS CBW are LUN bits on another place = than in SCSI CDB, both should be set correctly. */ cbw.length =3D cmdsize; grub_memcpy (cbw.cbwcb, cmd, cmdsize); + =20 + /* Debug print of CBW content. */ + grub_dprintf ("usb", "CBW: sign=3D0x%08x tag=3D0x%08x len=3D0x%08x\n",= + cbw.signature, cbw.tag, cbw.transfer_length); + grub_dprintf ("usb", "CBW: flags=3D0x%02x lun=3D0x%02x CB_len=3D0x%02x= \n", + cbw.flags, cbw.lun, cbw.length); + grub_dprintf ("usb", "CBW: cmd:\n %02x %02x %02x %02x %02x %02x %02x %= 02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + cbw.cbwcb[ 0], cbw.cbwcb[ 1], cbw.cbwcb[ 2], cbw.cbwcb[ 3], + cbw.cbwcb[ 4], cbw.cbwcb[ 5], cbw.cbwcb[ 6], cbw.cbwcb[ 7], + cbw.cbwcb[ 8], cbw.cbwcb[ 9], cbw.cbwcb[10], cbw.cbwcb[11], + cbw.cbwcb[12], cbw.cbwcb[13], cbw.cbwcb[14], cbw.cbwcb[15]); =20 - /* Write the request. */ - err =3D grub_usb_bulk_write (dev->dev, dev->out->endp_addr & 15, + /* Write the request. + * XXX: Error recovery is maybe still not fully correct. */ + err =3D grub_usb_bulk_write (dev->dev, dev->out->endp_addr, sizeof (cbw), (char *) &cbw); if (err) { if (err =3D=3D GRUB_USB_ERR_STALL) { + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); grub_usb_clear_halt (dev->dev, dev->out->endp_addr); goto retry; } return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed")= ; } =20 - /* Read/write the data. */ - if (read_write =3D=3D 0) + /* Read/write the data, (maybe) according to specification. */ + if (size && (read_write =3D=3D 0)) { - err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr & 15, siz= e, buf); - grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL); - if (err) - { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->in->endp_addr); - goto retry; - } - return grub_error (GRUB_ERR_READ_ERROR, - "can't read from USB Mass Storage device"); - } + err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr, size, bu= f); + grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL);=20 + if (err) goto CheckCSW; + /* Debug print of received data. */ + grub_dprintf ("usb", "buf:\n"); + if (size <=3D 64) + for (i=3D0; idev, dev->in->endp_addr & 15, si= ze, buf); + err =3D grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, = buf); grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL); - if (err) - { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->out->endp_addr); - goto retry; - } - return grub_error (GRUB_ERR_WRITE_ERROR, - "can't write to USB Mass Storage device"); - } + grub_dprintf ("usb", "buf:\n"); + /* Debug print of sent data. */ + if (size <=3D 256) + for (i=3D0; idev, dev->in->endp_addr & 15, - sizeof (status), (char *) &status); + /* Read the status - (maybe) according to specification. */ +CheckCSW: + err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr, + sizeof (status), (char *) &status); if (err) { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr, + sizeof (status), (char *) &status); + if (err) + { /* Bulk-only reset device. */ + grub_usbms_reset (dev->dev, dev->interface); + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + grub_usb_clear_halt (dev->dev, dev->out->endp_addr); goto retry; - } - return grub_error (GRUB_ERR_READ_ERROR, - "can't read status from USB Mass Storage device"); + } } =20 - /* XXX: Magic and check this code. */ + /* Debug print of CSW content. */ + grub_dprintf ("usb", "CSW: sign=3D0x%08x tag=3D0x%08x resid=3D0x%08x\n= ", + status.signature, status.tag, status.residue); + grub_dprintf ("usb", "CSW: status=3D0x%02x\n", status.status); + =20 + /* If phase error, do bulk-only reset device. */ if (status.status =3D=3D 2) { - /* XXX: Phase error, reset device. */ grub_usbms_reset (dev->dev, dev->interface); grub_usb_clear_halt (dev->dev, dev->in->endp_addr); grub_usb_clear_halt (dev->dev, dev->out->endp_addr); @@ -384,8 +430,11 @@ =20 GRUB_MOD_INIT(usbms) { + grub_dprintf ("usbms", "alive\n"); grub_usbms_finddevs (); + grub_dprintf ("usbms", "alive\n"); grub_scsi_dev_register (&grub_usbms_dev); + grub_dprintf ("usbms", "alive\n"); } =20 GRUB_MOD_FINI(usbms) =3D=3D=3D modified file 'include/grub/scsicmd.h' --- include/grub/scsicmd.h 2008-08-27 15:05:00 +0000 +++ include/grub/scsicmd.h 2010-05-23 13:08:06 +0000 @@ -25,14 +25,26 @@ #define GRUB_SCSI_REMOVABLE_BIT 7 #define GRUB_SCSI_LUN_SHIFT 5 =20 +struct grub_scsi_test_unit_ready +{ + grub_uint8_t opcode; + grub_uint8_t lun; /* 7-5 LUN, 4-0 reserved */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t reserved3; + grub_uint8_t control; + grub_uint8_t pad[6]; /* To be ATAPI compatible */ +} __attribute__((packed)); + struct grub_scsi_inquiry { grub_uint8_t opcode; - grub_uint8_t lun; - grub_uint16_t reserved; - grub_uint16_t alloc_length; - grub_uint8_t reserved2; - grub_uint8_t pad[5]; + grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 EVPD */ + grub_uint8_t page; /* page code if EVPD=3D1 */ + grub_uint8_t reserved; + grub_uint8_t alloc_length; + grub_uint8_t control; + grub_uint8_t pad[6]; /* To be ATAPI compatible */ } __attribute__((packed)); =20 struct grub_scsi_inquiry_data @@ -47,12 +59,42 @@ char prodrev[4]; } __attribute__((packed)); =20 +struct grub_scsi_request_sense +{ + grub_uint8_t opcode; + grub_uint8_t lun; /* 7-5 LUN, 4-0 reserved */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t alloc_length; + grub_uint8_t control; + grub_uint8_t pad[6]; /* To be ATAPI compatible */ +} __attribute__((packed)); + +struct grub_scsi_request_sense_data +{ + grub_uint8_t error_code; /* 7 Valid, 6-0 Err. code */ + grub_uint8_t segment_number; + grub_uint8_t sense_key; /*7 FileMark, 6 EndOfMedia, 5 ILI, 4-0 sense k= ey */ + grub_uint32_t information; + grub_uint8_t additional_sense_length; + grub_uint32_t cmd_specific_info; + grub_uint8_t additional_sense_code; + grub_uint8_t additional_sense_code_qualifier; + grub_uint8_t field_replaceable_unit_code; + grub_uint8_t sense_key_specific[3]; + /* there can be additional sense field */ +} __attribute__((packed)); + struct grub_scsi_read_capacity { grub_uint8_t opcode; - grub_uint8_t lun; - grub_uint8_t reserved[8]; - grub_uint8_t pad[2]; + grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 reserved */ + grub_uint32_t logical_block_addr; /* only if PMI=3D1 */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t PMI; + grub_uint8_t control; + grub_uint16_t pad; /* To be ATAPI compatible */ } __attribute__((packed)); =20 struct grub_scsi_read_capacity_data @@ -106,11 +148,13 @@ typedef enum { grub_scsi_cmd_inquiry =3D 0x12, + grub_scsi_cmd_test_unit_ready =3D 0x00, grub_scsi_cmd_read_capacity =3D 0x25, grub_scsi_cmd_read10 =3D 0x28, grub_scsi_cmd_write10 =3D 0x2a, grub_scsi_cmd_read12 =3D 0xa8, - grub_scsi_cmd_write12 =3D 0xaa + grub_scsi_cmd_write12 =3D 0xaa, + grub_scsi_cmd_request_sense =3D 0x03 } grub_scsi_cmd_t; =20 typedef enum =3D=3D=3D modified file 'include/grub/usb.h' --- include/grub/usb.h 2009-11-09 17:43:53 +0000 +++ include/grub/usb.h 2010-05-23 13:08:06 +0000 @@ -156,7 +156,7 @@ int initialized; =20 /* Data toggle values (used for bulk transfers only). */ - int toggle[16]; + int toggle[256]; =20 /* Device-specific data. */ void *data; @@ -184,7 +184,12 @@ =20 typedef enum { - GRUB_USBMS_SUBCLASS_BULK =3D 0x06 + GRUB_USBMS_SUBCLASS_BULK =3D 0x06, + /* Experimental support for non-pure SCSI devices */ + GRUB_USBMS_SUBCLASS_RBC =3D 0x01, + GRUB_USBMS_SUBCLASS_MMC2 =3D 0x02, + GRUB_USBMS_SUBCLASS_UFI =3D 0x04, + GRUB_USBMS_SUBCLASS_SFF8070 =3D 0x05 } grub_usbms_subclass_t; =20 typedef enum =3D=3D=3D modified file 'include/grub/usbtrans.h' --- include/grub/usbtrans.h 2010-05-05 08:40:48 +0000 +++ include/grub/usbtrans.h 2010-05-23 13:08:06 +0000 @@ -86,9 +86,9 @@ =20 #define GRUB_USB_REQ_HUB_GET_PORT_STATUS 0x00 =20 -#define GRUB_USB_FEATURE_ENDP_HALT 0x01 -#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x02 -#define GRUB_USB_FEATURE_TEST_MODE 0x04 +#define GRUB_USB_FEATURE_ENDP_HALT 0x00 +#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 +#define GRUB_USB_FEATURE_TEST_MODE 0x02 =20 #define GRUB_USB_HUB_STATUS_CONNECTED (1 << 0) #define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9) =3D=3D=3D modified file 'kern/misc.c' --- kern/misc.c 2010-05-22 14:58:45 +0000 +++ kern/misc.c 2010-05-23 17:32:21 +0000 @@ -189,7 +189,7 @@ const char *debug =3D grub_env_get ("debug"); =20 if (! debug) - return; + debug =3D "all"; =20 if (grub_strword (debug, "all") || grub_strword (debug, condition)) { --------------010507070401040703060508-- --------------enig451A3162B1C0513E1C43E4BA Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iF4EAREKAAYFAkv5axMACgkQNak7dOguQglIkwD/RrIneIAPxC4JBPahyJqSOeCF cI1oMY4MU52YC5CQ1HwBALfUIPH+nS64lIOHu77NVkQAtS7WZfMPiOgXwPmqtQpG =zxEw -----END PGP SIGNATURE----- --------------enig451A3162B1C0513E1C43E4BA--