Revision a0a3167a hw/usb-ehci.c

b/hw/usb-ehci.c
20 20
 *
21 21
 * You should have received a copy of the GNU General Public License
22 22
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23
 *
24
 * TODO:
25
 *  o Downstream port handoff
26 23
 */
27 24

  
28 25
#include "hw.h"
......
106 103
 * Bits that are reserved or are read-only are masked out of values
107 104
 * written to us by software
108 105
 */
109
#define PORTSC_RO_MASK       0x007021c0
106
#define PORTSC_RO_MASK       0x007001c0
110 107
#define PORTSC_RWC_MASK      0x0000002a
111 108
#define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
112 109
#define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
......
373 370
    qemu_irq irq;
374 371
    target_phys_addr_t mem_base;
375 372
    int mem;
373
    int companion_count;
376 374

  
377 375
    /* properties */
378 376
    uint32_t freq;
......
408 406
    int astate;                        // Current state in asynchronous schedule
409 407
    int pstate;                        // Current state in periodic schedule
410 408
    USBPort ports[NB_PORTS];
409
    USBPort *companion_ports[NB_PORTS];
411 410
    uint32_t usbsts_pending;
412 411
    QTAILQ_HEAD(, EHCIQueue) queues;
413 412

  
......
730 729

  
731 730
    trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
732 731

  
732
    if (*portsc & PORTSC_POWNER) {
733
        USBPort *companion = s->companion_ports[port->index];
734
        companion->dev = port->dev;
735
        companion->ops->attach(companion);
736
        return;
737
    }
738

  
733 739
    *portsc |= PORTSC_CONNECT;
734 740
    *portsc |= PORTSC_CSC;
735 741

  
736
    /*
737
     *  If a high speed device is attached then we own this port(indicated
738
     *  by zero in the PORTSC_POWNER bit field) so set the status bit
739
     *  and set an interrupt if enabled.
740
     */
741
    if ( !(*portsc & PORTSC_POWNER)) {
742
        ehci_set_interrupt(s, USBSTS_PCD);
743
    }
742
    ehci_set_interrupt(s, USBSTS_PCD);
744 743
}
745 744

  
746 745
static void ehci_detach(USBPort *port)
......
750 749

  
751 750
    trace_usb_ehci_port_detach(port->index);
752 751

  
752
    if (*portsc & PORTSC_POWNER) {
753
        USBPort *companion = s->companion_ports[port->index];
754
        companion->ops->detach(companion);
755
        companion->dev = NULL;
756
        return;
757
    }
758

  
753 759
    ehci_queues_rip_device(s, port->dev);
754 760

  
755 761
    *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
756 762
    *portsc |= PORTSC_CSC;
757 763

  
758
    /*
759
     *  If a high speed device is attached then we own this port(indicated
760
     *  by zero in the PORTSC_POWNER bit field) so set the status bit
761
     *  and set an interrupt if enabled.
762
     */
763
    if ( !(*portsc & PORTSC_POWNER)) {
764
        ehci_set_interrupt(s, USBSTS_PCD);
765
    }
764
    ehci_set_interrupt(s, USBSTS_PCD);
766 765
}
767 766

  
768 767
static void ehci_child_detach(USBPort *port, USBDevice *child)
769 768
{
770 769
    EHCIState *s = port->opaque;
770
    uint32_t portsc = s->portsc[port->index];
771

  
772
    if (portsc & PORTSC_POWNER) {
773
        USBPort *companion = s->companion_ports[port->index];
774
        companion->ops->child_detach(companion, child);
775
        companion->dev = NULL;
776
        return;
777
    }
771 778

  
772 779
    ehci_queues_rip_device(s, child);
773 780
}
774 781

  
782
static void ehci_wakeup(USBPort *port)
783
{
784
    EHCIState *s = port->opaque;
785
    uint32_t portsc = s->portsc[port->index];
786

  
787
    if (portsc & PORTSC_POWNER) {
788
        USBPort *companion = s->companion_ports[port->index];
789
        if (companion->ops->wakeup) {
790
            companion->ops->wakeup(companion);
791
        }
792
    }
793
}
794

  
795
static int ehci_register_companion(USBBus *bus, USBPort *ports[],
796
                                   uint32_t portcount, uint32_t firstport)
797
{
798
    EHCIState *s = container_of(bus, EHCIState, bus);
799
    uint32_t i;
800

  
801
    if (firstport + portcount > NB_PORTS) {
802
        qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
803
                      "firstport on masterbus");
804
        error_printf_unless_qmp(
805
            "firstport value of %u makes companion take ports %u - %u, which "
806
            "is outside of the valid range of 0 - %u\n", firstport, firstport,
807
            firstport + portcount - 1, NB_PORTS - 1);
808
        return -1;
809
    }
810

  
811
    for (i = 0; i < portcount; i++) {
812
        if (s->companion_ports[firstport + i]) {
813
            qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
814
                          "an USB masterbus");
815
            error_printf_unless_qmp(
816
                "port %u on masterbus %s already has a companion assigned\n",
817
                firstport + i, bus->qbus.name);
818
            return -1;
819
        }
820
    }
821

  
822
    for (i = 0; i < portcount; i++) {
823
        s->companion_ports[firstport + i] = ports[i];
824
        s->ports[firstport + i].speedmask |=
825
            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
826
        /* Ensure devs attached before the initial reset go to the companion */
827
        s->portsc[firstport + i] = PORTSC_POWNER;
828
    }
829

  
830
    s->companion_count++;
831
    s->mmio[0x05] = (s->companion_count << 4) | portcount;
832

  
833
    return 0;
834
}
835

  
775 836
/* 4.1 host controller initialization */
776 837
static void ehci_reset(void *opaque)
777 838
{
778 839
    EHCIState *s = opaque;
779 840
    int i;
841
    USBDevice *devs[NB_PORTS];
780 842

  
781 843
    trace_usb_ehci_reset();
782 844

  
845
    /*
846
     * Do the detach before touching portsc, so that it correctly gets send to
847
     * us or to our companion based on PORTSC_POWNER before the reset.
848
     */
849
    for(i = 0; i < NB_PORTS; i++) {
850
        devs[i] = s->ports[i].dev;
851
        if (devs[i]) {
852
            usb_attach(&s->ports[i], NULL);
853
        }
854
    }
855

  
783 856
    memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
784 857

  
785 858
    s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
......
791 864
    s->attach_poll_counter = 0;
792 865

  
793 866
    for(i = 0; i < NB_PORTS; i++) {
794
        s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
795

  
796
        if (s->ports[i].dev) {
797
            usb_attach(&s->ports[i], s->ports[i].dev);
867
        if (s->companion_ports[i]) {
868
            s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
869
        } else {
870
            s->portsc[i] = PORTSC_PPOWER;
871
        }
872
        if (devs[i]) {
873
            usb_attach(&s->ports[i], devs[i]);
798 874
        }
799 875
    }
800 876
    ehci_queues_rip_all(s);
......
844 920
    exit(1);
845 921
}
846 922

  
923
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
924
{
925
    USBDevice *dev = s->ports[port].dev;
926
    uint32_t *portsc = &s->portsc[port];
927
    uint32_t orig;
928

  
929
    if (s->companion_ports[port] == NULL)
930
        return;
931

  
932
    owner = owner & PORTSC_POWNER;
933
    orig  = *portsc & PORTSC_POWNER;
934

  
935
    if (!(owner ^ orig)) {
936
        return;
937
    }
938

  
939
    if (dev) {
940
        usb_attach(&s->ports[port], NULL);
941
    }
942

  
943
    *portsc &= ~PORTSC_POWNER;
944
    *portsc |= owner;
945

  
946
    if (dev) {
947
        usb_attach(&s->ports[port], dev);
948
    }
949
}
950

  
847 951
static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
848 952
{
849 953
    uint32_t *portsc = &s->portsc[port];
......
853 957
    *portsc &= ~(val & PORTSC_RWC_MASK);
854 958
    /* The guest may clear, but not set the PED bit */
855 959
    *portsc &= val | ~PORTSC_PED;
960
    /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
961
    handle_port_owner_write(s, port, val);
962
    /* And finally apply RO_MASK */
856 963
    val &= PORTSC_RO_MASK;
857 964

  
858 965
    if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
......
956 1063
        val &= 0x1;
957 1064
        if (val) {
958 1065
            for(i = 0; i < NB_PORTS; i++)
959
                s->portsc[i] &= ~PORTSC_POWNER;
1066
                handle_port_owner_write(s, i, 0);
960 1067
        }
961 1068
        break;
962 1069

  
......
1114 1221

  
1115 1222
static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
1116 1223
{
1117
    EHCIQueue *q = container_of(packet, EHCIQueue, packet);
1224
    EHCIQueue *q;
1225
    EHCIState *s = port->opaque;
1226
    uint32_t portsc = s->portsc[port->index];
1227

  
1228
    if (portsc & PORTSC_POWNER) {
1229
        USBPort *companion = s->companion_ports[port->index];
1230
        companion->ops->complete(companion, packet);
1231
        return;
1232
    }
1118 1233

  
1234
    q = container_of(packet, EHCIQueue, packet);
1119 1235
    trace_usb_ehci_queue_action(q, "wakeup");
1120 1236
    assert(q->async == EHCI_ASYNC_INFLIGHT);
1121 1237
    q->async = EHCI_ASYNC_FINISHED;
......
1245 1361
        port = &q->ehci->ports[i];
1246 1362
        dev = port->dev;
1247 1363

  
1248
        // TODO sometime we will also need to check if we are the port owner
1249

  
1250 1364
        if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
1251 1365
            DPRINTF("Port %d, no exec, not connected(%08X)\n",
1252 1366
                    i, q->ehci->portsc[i]);
......
1339 1453
                port = &ehci->ports[j];
1340 1454
                dev = port->dev;
1341 1455

  
1342
                // TODO sometime we will also need to check if we are the port owner
1343

  
1344 1456
                if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
1345 1457
                    continue;
1346 1458
                }
......
2124 2236
    .attach = ehci_attach,
2125 2237
    .detach = ehci_detach,
2126 2238
    .child_detach = ehci_child_detach,
2239
    .wakeup = ehci_wakeup,
2127 2240
    .complete = ehci_async_complete_packet,
2128 2241
};
2129 2242

  
2130 2243
static USBBusOps ehci_bus_ops = {
2244
    .register_companion = ehci_register_companion,
2131 2245
};
2132 2246

  
2133 2247
static PCIDeviceInfo ehci_info = {

Also available in: Unified diff