static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)

{

    EHCIState *s = ptr;

    uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);

    uint32_t old = *mmio;

    int i;



    trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);



    /* Only aligned reads are allowed on OHCI */

    if (addr & 3) {

        fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"

                TARGET_FMT_plx "\n", addr);

        return;

    }



    if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {

        handle_port_status_write(s, (addr-PORTSC)/4, val);

        trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);

        return;

    }



    if (addr < OPREGBASE) {

        fprintf(stderr, "usb-ehci: write attempt to read-only register"

                TARGET_FMT_plx "\n", addr);

        return;

    }





    /* Do any register specific pre-write processing here.  */

    switch(addr) {

    case USBCMD:

        if (val & USBCMD_HCRESET) {

            ehci_reset(s);

            val = s->usbcmd;

            break;

        }



        if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=

            ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {

            if (!ehci_enabled(s)) {

                qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));

                SET_LAST_RUN_CLOCK(s);

            }

            ehci_update_halt(s);

        }



        /* not supporting dynamic frame list size at the moment */

        if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {

            fprintf(stderr, "attempt to set frame list size -- value %d\n",

                    val & USBCMD_FLS);

            val &= ~USBCMD_FLS;

        }

        break;



    case USBSTS:

        val &= USBSTS_RO_MASK;              // bits 6 through 31 are RO

        ehci_clear_usbsts(s, val);          // bits 0 through 5 are R/WC

        val = s->usbsts;

        ehci_set_interrupt(s, 0);

        break;



    case USBINTR:

        val &= USBINTR_MASK;

        break;



    case FRINDEX:

        val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */

        break;



    case CONFIGFLAG:

        val &= 0x1;

        if (val) {

            for(i = 0; i < NB_PORTS; i++)

                handle_port_owner_write(s, i, 0);

        }

        break;



    case PERIODICLISTBASE:

        if (ehci_periodic_enabled(s)) {

            fprintf(stderr,

              "ehci: PERIODIC list base register set while periodic schedule\n"

              "      is enabled and HC is enabled\n");

        }

        break;



    case ASYNCLISTADDR:

        if (ehci_async_enabled(s)) {

            fprintf(stderr,

              "ehci: ASYNC list address register set while async schedule\n"

              "      is enabled and HC is enabled\n");

        }

        break;

    }



    *mmio = val;

    trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);

}
