static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,

                               int completion)

{

    int dir;

    size_t len = 0;

#ifdef DEBUG_ISOCH

    const char *str = NULL;

#endif

    int pid;

    int ret;

    int i;

    USBDevice *dev;

    struct ohci_iso_td iso_td;

    uint32_t addr;

    uint16_t starting_frame;

    int16_t relative_frame_number;

    int frame_count;

    uint32_t start_offset, next_offset, end_offset = 0;

    uint32_t start_addr, end_addr;



    addr = ed->head & OHCI_DPTR_MASK;



    if (!ohci_read_iso_td(ohci, addr, &iso_td)) {

        printf("usb-ohci: ISO_TD read error at %x\n", addr);

        return 0;

    }



    starting_frame = OHCI_BM(iso_td.flags, TD_SF);

    frame_count = OHCI_BM(iso_td.flags, TD_FC);

    relative_frame_number = USUB(ohci->frame_number, starting_frame); 



#ifdef DEBUG_ISOCH

    printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "frame_number 0x%.8x starting_frame 0x%.8x\n"

           "frame_count  0x%.8x relative %d\n"

           "di 0x%.8x cc 0x%.8x\n",

           ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,

           iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,

           iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],

           iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],

           ohci->frame_number, starting_frame, 

           frame_count, relative_frame_number,         

           OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));

#endif



    if (relative_frame_number < 0) {

        DPRINTF("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number);

        return 1;

    } else if (relative_frame_number > frame_count) {

        /* ISO TD expired - retire the TD to the Done Queue and continue with

           the next ISO TD of the same ED */

        DPRINTF("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number, 

               frame_count);

        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);

        ed->head &= ~OHCI_DPTR_MASK;

        ed->head |= (iso_td.next & OHCI_DPTR_MASK);

        iso_td.next = ohci->done;

        ohci->done = addr;

        i = OHCI_BM(iso_td.flags, TD_DI);

        if (i < ohci->done_count)

            ohci->done_count = i;

        ohci_put_iso_td(ohci, addr, &iso_td);

        return 0;

    }



    dir = OHCI_BM(ed->flags, ED_D);

    switch (dir) {

    case OHCI_TD_DIR_IN:

#ifdef DEBUG_ISOCH

        str = "in";

#endif

        pid = USB_TOKEN_IN;

        break;

    case OHCI_TD_DIR_OUT:

#ifdef DEBUG_ISOCH

        str = "out";

#endif

        pid = USB_TOKEN_OUT;

        break;

    case OHCI_TD_DIR_SETUP:

#ifdef DEBUG_ISOCH

        str = "setup";

#endif

        pid = USB_TOKEN_SETUP;

        break;

    default:

        printf("usb-ohci: Bad direction %d\n", dir);

        return 1;

    }



    if (!iso_td.bp || !iso_td.be) {

        printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be);

        return 1;

    }



    start_offset = iso_td.offset[relative_frame_number];

    next_offset = iso_td.offset[relative_frame_number + 1];



    if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 

        ((relative_frame_number < frame_count) && 

         !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {

        printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",

               start_offset, next_offset);

        return 1;

    }



    if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {

        printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",

                start_offset, next_offset);

        return 1;

    }



    if ((start_offset & 0x1000) == 0) {

        start_addr = (iso_td.bp & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    } else {

        start_addr = (iso_td.be & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    }



    if (relative_frame_number < frame_count) {

        end_offset = next_offset - 1;

        if ((end_offset & 0x1000) == 0) {

            end_addr = (iso_td.bp & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        } else {

            end_addr = (iso_td.be & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        }

    } else {

        /* Last packet in the ISO TD */

        end_addr = iso_td.be;

    }



    if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {

        len = (end_addr & OHCI_OFFSET_MASK) + 0x1001

            - (start_addr & OHCI_OFFSET_MASK);

    } else {

        len = end_addr - start_addr + 1;

    }



    if (len && dir != OHCI_TD_DIR_IN) {

        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);

    }



    if (completion) {

        ret = ohci->usb_packet.result;

    } else {

        usb_packet_setup(&ohci->usb_packet, pid,

                         OHCI_BM(ed->flags, ED_FA),

                         OHCI_BM(ed->flags, ED_EN));

        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);

        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);

        ret = usb_handle_packet(dev, &ohci->usb_packet);

        if (ret == USB_RET_ASYNC) {

            return 1;

        }

    }



#ifdef DEBUG_ISOCH

    printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",

           start_offset, end_offset, start_addr, end_addr, str, len, ret);

#endif



    /* Writeback */

    if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {

        /* IN transfer succeeded */

        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);

    } else if (dir == OHCI_TD_DIR_OUT && ret == len) {

        /* OUT transfer succeeded */

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);

    } else {

        if (ret > (ssize_t) len) {

            printf("usb-ohci: DataOverrun %d > %zu\n", ret, len);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAOVERRUN);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                        len);

        } else if (ret >= 0) {

            printf("usb-ohci: DataUnderrun %d\n", ret);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAUNDERRUN);

        } else {

            switch (ret) {

            case USB_RET_NODEV:

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_DEVICENOTRESPONDING);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            case USB_RET_NAK:

            case USB_RET_STALL:

                printf("usb-ohci: got NAK/STALL %d\n", ret);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_STALL);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            default:

                printf("usb-ohci: Bad device response %d\n", ret);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_UNDEXPETEDPID);

                break;

            }

        }

    }



    if (relative_frame_number == frame_count) {

        /* Last data packet of ISO TD - retire the TD to the Done Queue */

        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);

        ed->head &= ~OHCI_DPTR_MASK;

        ed->head |= (iso_td.next & OHCI_DPTR_MASK);

        iso_td.next = ohci->done;

        ohci->done = addr;

        i = OHCI_BM(iso_td.flags, TD_DI);

        if (i < ohci->done_count)

            ohci->done_count = i;

    }

    ohci_put_iso_td(ohci, addr, &iso_td);

    return 1;

}

static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,

                               int completion)

{

    int dir;

    size_t len = 0;

#ifdef DEBUG_ISOCH

    const char *str = NULL;

#endif

    int pid;

    int ret;

    int i;

    USBDevice *dev;

    struct ohci_iso_td iso_td;

    uint32_t addr;

    uint16_t starting_frame;

    int16_t relative_frame_number;

    int frame_count;

    uint32_t start_offset, next_offset, end_offset = 0;

    uint32_t start_addr, end_addr;



    addr = ed->head & OHCI_DPTR_MASK;



    if (!ohci_read_iso_td(ohci, addr, &iso_td)) {

        printf("usb-ohci: ISO_TD read error at %x\n", addr);

        return 0;

    }



    starting_frame = OHCI_BM(iso_td.flags, TD_SF);

    frame_count = OHCI_BM(iso_td.flags, TD_FC);

    relative_frame_number = USUB(ohci->frame_number, starting_frame); 



#ifdef DEBUG_ISOCH

    printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "frame_number 0x%.8x starting_frame 0x%.8x\n"

           "frame_count  0x%.8x relative %d\n"

           "di 0x%.8x cc 0x%.8x\n",

           ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,

           iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,

           iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],

           iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],

           ohci->frame_number, starting_frame, 

           frame_count, relative_frame_number,         

           OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));

#endif



    if (relative_frame_number < 0) {

        DPRINTF("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number);

        return 1;

    } else if (relative_frame_number > frame_count) {

        



        DPRINTF("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number, 

               frame_count);

        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);

        ed->head &= ~OHCI_DPTR_MASK;

        ed->head |= (iso_td.next & OHCI_DPTR_MASK);

        iso_td.next = ohci->done;

        ohci->done = addr;

        i = OHCI_BM(iso_td.flags, TD_DI);

        if (i < ohci->done_count)

            ohci->done_count = i;

        ohci_put_iso_td(ohci, addr, &iso_td);

        return 0;

    }



    dir = OHCI_BM(ed->flags, ED_D);

    switch (dir) {

    case OHCI_TD_DIR_IN:

#ifdef DEBUG_ISOCH

        str = "in";

#endif

        pid = USB_TOKEN_IN;

        break;

    case OHCI_TD_DIR_OUT:

#ifdef DEBUG_ISOCH

        str = "out";

#endif

        pid = USB_TOKEN_OUT;

        break;

    case OHCI_TD_DIR_SETUP:

#ifdef DEBUG_ISOCH

        str = "setup";

#endif

        pid = USB_TOKEN_SETUP;

        break;

    default:

        printf("usb-ohci: Bad direction %d\n", dir);

        return 1;

    }



    if (!iso_td.bp || !iso_td.be) {

        printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be);

        return 1;

    }



    start_offset = iso_td.offset[relative_frame_number];

    next_offset = iso_td.offset[relative_frame_number + 1];



    if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 

        ((relative_frame_number < frame_count) && 

         !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {

        printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",

               start_offset, next_offset);

        return 1;

    }



    if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {

        printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",

                start_offset, next_offset);

        return 1;

    }



    if ((start_offset & 0x1000) == 0) {

        start_addr = (iso_td.bp & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    } else {

        start_addr = (iso_td.be & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    }



    if (relative_frame_number < frame_count) {

        end_offset = next_offset - 1;

        if ((end_offset & 0x1000) == 0) {

            end_addr = (iso_td.bp & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        } else {

            end_addr = (iso_td.be & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        }

    } else {

        

        end_addr = iso_td.be;

    }



    if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {

        len = (end_addr & OHCI_OFFSET_MASK) + 0x1001

            - (start_addr & OHCI_OFFSET_MASK);

    } else {

        len = end_addr - start_addr + 1;

    }



    if (len && dir != OHCI_TD_DIR_IN) {

        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);

    }



    if (completion) {

        ret = ohci->usb_packet.result;

    } else {

        usb_packet_setup(&ohci->usb_packet, pid,

                         OHCI_BM(ed->flags, ED_FA),

                         OHCI_BM(ed->flags, ED_EN));

        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);

        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);

        ret = usb_handle_packet(dev, &ohci->usb_packet);

        if (ret == USB_RET_ASYNC) {

            return 1;

        }

    }



#ifdef DEBUG_ISOCH

    printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",

           start_offset, end_offset, start_addr, end_addr, str, len, ret);

#endif



    

    if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {

        

        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);

    } else if (dir == OHCI_TD_DIR_OUT && ret == len) {

        

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);

    } else {

        if (ret > (ssize_t) len) {

            printf("usb-ohci: DataOverrun %d > %zu\n", ret, len);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAOVERRUN);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                        len);

        } else if (ret >= 0) {

            printf("usb-ohci: DataUnderrun %d\n", ret);

            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAUNDERRUN);

        } else {

            switch (ret) {

            case USB_RET_NODEV:

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_DEVICENOTRESPONDING);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            case USB_RET_NAK:

            case USB_RET_STALL:

                printf("usb-ohci: got NAK/STALL %d\n", ret);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_STALL);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            default:

                printf("usb-ohci: Bad device response %d\n", ret);

                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_UNDEXPETEDPID);

                break;

            }

        }

    }



    if (relative_frame_number == frame_count) {

        

        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);

        ed->head &= ~OHCI_DPTR_MASK;

        ed->head |= (iso_td.next & OHCI_DPTR_MASK);

        iso_td.next = ohci->done;

        ohci->done = addr;

        i = OHCI_BM(iso_td.flags, TD_DI);

        if (i < ohci->done_count)

            ohci->done_count = i;

    }

    ohci_put_iso_td(ohci, addr, &iso_td);

    return 1;

}

static int FUNC_0(OHCIState *VAR_0, struct ohci_ed *VAR_1,

                               int VAR_2)

{

    int VAR_3;

    size_t len = 0;

#ifdef DEBUG_ISOCH

    const char *str = NULL;

#endif

    int VAR_4;

    int VAR_5;

    int VAR_6;

    USBDevice *dev;

    struct ohci_iso_td VAR_7;

    uint32_t addr;

    uint16_t starting_frame;

    int16_t relative_frame_number;

    int VAR_8;

    uint32_t start_offset, next_offset, end_offset = 0;

    uint32_t start_addr, end_addr;



    addr = VAR_1->head & OHCI_DPTR_MASK;



    if (!ohci_read_iso_td(VAR_0, addr, &VAR_7)) {

        printf("usb-VAR_0: ISO_TD read error at %x\n", addr);

        return 0;

    }



    starting_frame = OHCI_BM(VAR_7.flags, TD_SF);

    VAR_8 = OHCI_BM(VAR_7.flags, TD_FC);

    relative_frame_number = USUB(VAR_0->frame_number, starting_frame); 



#ifdef DEBUG_ISOCH

    printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"

           "frame_number 0x%.8x starting_frame 0x%.8x\n"

           "VAR_8  0x%.8x relative %d\n"

           "di 0x%.8x cc 0x%.8x\n",

           VAR_1->head & OHCI_DPTR_MASK, VAR_1->tail & OHCI_DPTR_MASK,

           VAR_7.flags, VAR_7.bp, VAR_7.next, VAR_7.be,

           VAR_7.offset[0], VAR_7.offset[1], VAR_7.offset[2], VAR_7.offset[3],

           VAR_7.offset[4], VAR_7.offset[5], VAR_7.offset[6], VAR_7.offset[7],

           VAR_0->frame_number, starting_frame, 

           VAR_8, relative_frame_number,         

           OHCI_BM(VAR_7.flags, TD_DI), OHCI_BM(VAR_7.flags, TD_CC));

#endif



    if (relative_frame_number < 0) {

        DPRINTF("usb-VAR_0: ISO_TD R=%d < 0\n", relative_frame_number);

        return 1;

    } else if (relative_frame_number > VAR_8) {

        



        DPRINTF("usb-VAR_0: ISO_TD R=%d > FC=%d\n", relative_frame_number, 

               VAR_8);

        OHCI_SET_BM(VAR_7.flags, TD_CC, OHCI_CC_DATAOVERRUN);

        VAR_1->head &= ~OHCI_DPTR_MASK;

        VAR_1->head |= (VAR_7.next & OHCI_DPTR_MASK);

        VAR_7.next = VAR_0->done;

        VAR_0->done = addr;

        VAR_6 = OHCI_BM(VAR_7.flags, TD_DI);

        if (VAR_6 < VAR_0->done_count)

            VAR_0->done_count = VAR_6;

        ohci_put_iso_td(VAR_0, addr, &VAR_7);

        return 0;

    }



    VAR_3 = OHCI_BM(VAR_1->flags, ED_D);

    switch (VAR_3) {

    case OHCI_TD_DIR_IN:

#ifdef DEBUG_ISOCH

        str = "in";

#endif

        VAR_4 = USB_TOKEN_IN;

        break;

    case OHCI_TD_DIR_OUT:

#ifdef DEBUG_ISOCH

        str = "out";

#endif

        VAR_4 = USB_TOKEN_OUT;

        break;

    case OHCI_TD_DIR_SETUP:

#ifdef DEBUG_ISOCH

        str = "setup";

#endif

        VAR_4 = USB_TOKEN_SETUP;

        break;

    default:

        printf("usb-VAR_0: Bad direction %d\n", VAR_3);

        return 1;

    }



    if (!VAR_7.bp || !VAR_7.be) {

        printf("usb-VAR_0: ISO_TD bp 0x%.8x be 0x%.8x\n", VAR_7.bp, VAR_7.be);

        return 1;

    }



    start_offset = VAR_7.offset[relative_frame_number];

    next_offset = VAR_7.offset[relative_frame_number + 1];



    if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 

        ((relative_frame_number < VAR_8) && 

         !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {

        printf("usb-VAR_0: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",

               start_offset, next_offset);

        return 1;

    }



    if ((relative_frame_number < VAR_8) && (start_offset > next_offset)) {

        printf("usb-VAR_0: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",

                start_offset, next_offset);

        return 1;

    }



    if ((start_offset & 0x1000) == 0) {

        start_addr = (VAR_7.bp & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    } else {

        start_addr = (VAR_7.be & OHCI_PAGE_MASK) |

            (start_offset & OHCI_OFFSET_MASK);

    }



    if (relative_frame_number < VAR_8) {

        end_offset = next_offset - 1;

        if ((end_offset & 0x1000) == 0) {

            end_addr = (VAR_7.bp & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        } else {

            end_addr = (VAR_7.be & OHCI_PAGE_MASK) |

                (end_offset & OHCI_OFFSET_MASK);

        }

    } else {

        

        end_addr = VAR_7.be;

    }



    if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {

        len = (end_addr & OHCI_OFFSET_MASK) + 0x1001

            - (start_addr & OHCI_OFFSET_MASK);

    } else {

        len = end_addr - start_addr + 1;

    }



    if (len && VAR_3 != OHCI_TD_DIR_IN) {

        ohci_copy_iso_td(VAR_0, start_addr, end_addr, VAR_0->usb_buf, len, 0);

    }



    if (VAR_2) {

        VAR_5 = VAR_0->usb_packet.result;

    } else {

        usb_packet_setup(&VAR_0->usb_packet, VAR_4,

                         OHCI_BM(VAR_1->flags, ED_FA),

                         OHCI_BM(VAR_1->flags, ED_EN));

        usb_packet_addbuf(&VAR_0->usb_packet, VAR_0->usb_buf, len);

        dev = ohci_find_device(VAR_0, VAR_0->usb_packet.devaddr);

        VAR_5 = usb_handle_packet(dev, &VAR_0->usb_packet);

        if (VAR_5 == USB_RET_ASYNC) {

            return 1;

        }

    }



#ifdef DEBUG_ISOCH

    printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu VAR_5 %d\n",

           start_offset, end_offset, start_addr, end_addr, str, len, VAR_5);

#endif



    

    if (VAR_3 == OHCI_TD_DIR_IN && VAR_5 >= 0 && VAR_5 <= len) {

        

        ohci_copy_iso_td(VAR_0, start_addr, end_addr, VAR_0->usb_buf, VAR_5, 1);

        OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE, VAR_5);

    } else if (VAR_3 == OHCI_TD_DIR_OUT && VAR_5 == len) {

        

        OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                    OHCI_CC_NOERROR);

        OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE, 0);

    } else {

        if (VAR_5 > (ssize_t) len) {

            printf("usb-VAR_0: DataOverrun %d > %zu\n", VAR_5, len);

            OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAOVERRUN);

            OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,

                        len);

        } else if (VAR_5 >= 0) {

            printf("usb-VAR_0: DataUnderrun %d\n", VAR_5);

            OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                        OHCI_CC_DATAUNDERRUN);

        } else {

            switch (VAR_5) {

            case USB_RET_NODEV:

                OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_DEVICENOTRESPONDING);

                OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            case USB_RET_NAK:

            case USB_RET_STALL:

                printf("usb-VAR_0: got NAK/STALL %d\n", VAR_5);

                OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_STALL);

                OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,

                            0);

                break;

            default:

                printf("usb-VAR_0: Bad device response %d\n", VAR_5);

                OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,

                            OHCI_CC_UNDEXPETEDPID);

                break;

            }

        }

    }



    if (relative_frame_number == VAR_8) {

        

        OHCI_SET_BM(VAR_7.flags, TD_CC, OHCI_CC_NOERROR);

        VAR_1->head &= ~OHCI_DPTR_MASK;

        VAR_1->head |= (VAR_7.next & OHCI_DPTR_MASK);

        VAR_7.next = VAR_0->done;

        VAR_0->done = addr;

        VAR_6 = OHCI_BM(VAR_7.flags, TD_DI);

        if (VAR_6 < VAR_0->done_count)

            VAR_0->done_count = VAR_6;

    }

    ohci_put_iso_td(VAR_0, addr, &VAR_7);

    return 1;

}

static int FUNC_0(OHCIState *VAR_0, struct ohci_ed *VAR_1,
int VAR_2)
{ int VAR_3; size_t len = 0; #ifdef DEBUG_ISOCH
const char *str = NULL; #endif
int VAR_4; int VAR_5; int VAR_6; USBDevice *dev; struct ohci_iso_td VAR_7; uint32_t addr; uint16_t starting_frame; int16_t relative_frame_number; int VAR_8; uint32_t start_offset, next_offset, end_offset = 0; uint32_t start_addr, end_addr; addr = VAR_1->head & OHCI_DPTR_MASK; if (!ohci_read_iso_td(VAR_0, addr, &VAR_7)) { printf("usb-VAR_0: ISO_TD read error at %x\n", addr); return 0; } starting_frame = OHCI_BM(VAR_7.flags, TD_SF); VAR_8 = OHCI_BM(VAR_7.flags, TD_FC); relative_frame_number = USUB(VAR_0->frame_number, starting_frame); #ifdef DEBUG_ISOCH
printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
"frame_number 0x%.8x starting_frame 0x%.8x\n"
"VAR_8  0x%.8x relative %d\n"
"di 0x%.8x cc 0x%.8x\n",
VAR_1->head & OHCI_DPTR_MASK, VAR_1->tail & OHCI_DPTR_MASK,
VAR_7.flags, VAR_7.bp, VAR_7.next, VAR_7.be,
VAR_7.offset[0], VAR_7.offset[1], VAR_7.offset[2], VAR_7.offset[3],
VAR_7.offset[4], VAR_7.offset[5], VAR_7.offset[6], VAR_7.offset[7],
VAR_0->frame_number, starting_frame,
VAR_8, relative_frame_number,
OHCI_BM(VAR_7.flags, TD_DI), OHCI_BM(VAR_7.flags, TD_CC)); #endif
if (relative_frame_number < 0) { DPRINTF("usb-VAR_0: ISO_TD R=%d < 0\n", relative_frame_number); return 1; } else if (relative_frame_number > VAR_8) { DPRINTF("usb-VAR_0: ISO_TD R=%d > FC=%d\n", relative_frame_number,
VAR_8); OHCI_SET_BM(VAR_7.flags, TD_CC, OHCI_CC_DATAOVERRUN); VAR_1->head &= ~OHCI_DPTR_MASK; VAR_1->head |= (VAR_7.next & OHCI_DPTR_MASK); VAR_7.next = VAR_0->done; VAR_0->done = addr; VAR_6 = OHCI_BM(VAR_7.flags, TD_DI); if (VAR_6 < VAR_0->done_count)
VAR_0->done_count = VAR_6; ohci_put_iso_td(VAR_0, addr, &VAR_7); return 0; } VAR_3 = OHCI_BM(VAR_1->flags, ED_D); switch (VAR_3) { case OHCI_TD_DIR_IN:
#ifdef DEBUG_ISOCH
str = "in"; #endif
VAR_4 = USB_TOKEN_IN; break; case OHCI_TD_DIR_OUT:
#ifdef DEBUG_ISOCH
str = "out"; #endif
VAR_4 = USB_TOKEN_OUT; break; case OHCI_TD_DIR_SETUP:
#ifdef DEBUG_ISOCH
str = "setup"; #endif
VAR_4 = USB_TOKEN_SETUP; break; default:
printf("usb-VAR_0: Bad direction %d\n", VAR_3); return 1; } if (!VAR_7.bp || !VAR_7.be) { printf("usb-VAR_0: ISO_TD bp 0x%.8x be 0x%.8x\n", VAR_7.bp, VAR_7.be); return 1; } start_offset = VAR_7.offset[relative_frame_number]; next_offset = VAR_7.offset[relative_frame_number + 1]; if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
((relative_frame_number < VAR_8) &&
!(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { printf("usb-VAR_0: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",
start_offset, next_offset); return 1; } if ((relative_frame_number < VAR_8) && (start_offset > next_offset)) { printf("usb-VAR_0: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",
start_offset, next_offset); return 1; } if ((start_offset & 0x1000) == 0) { start_addr = (VAR_7.bp & OHCI_PAGE_MASK) |
(start_offset & OHCI_OFFSET_MASK); } else { start_addr = (VAR_7.be & OHCI_PAGE_MASK) |
(start_offset & OHCI_OFFSET_MASK); } if (relative_frame_number < VAR_8) { end_offset = next_offset - 1; if ((end_offset & 0x1000) == 0) { end_addr = (VAR_7.bp & OHCI_PAGE_MASK) |
(end_offset & OHCI_OFFSET_MASK); } else { end_addr = (VAR_7.be & OHCI_PAGE_MASK) |
(end_offset & OHCI_OFFSET_MASK); } } else { end_addr = VAR_7.be; } if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
- (start_addr & OHCI_OFFSET_MASK); } else { len = end_addr - start_addr + 1; } if (len && VAR_3 != OHCI_TD_DIR_IN) { ohci_copy_iso_td(VAR_0, start_addr, end_addr, VAR_0->usb_buf, len, 0); } if (VAR_2) { VAR_5 = VAR_0->usb_packet.result; } else { usb_packet_setup(&VAR_0->usb_packet, VAR_4,
OHCI_BM(VAR_1->flags, ED_FA),
OHCI_BM(VAR_1->flags, ED_EN)); usb_packet_addbuf(&VAR_0->usb_packet, VAR_0->usb_buf, len); dev = ohci_find_device(VAR_0, VAR_0->usb_packet.devaddr); VAR_5 = usb_handle_packet(dev, &VAR_0->usb_packet); if (VAR_5 == USB_RET_ASYNC) { return 1; } } #ifdef DEBUG_ISOCH
printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu VAR_5 %d\n",
start_offset, end_offset, start_addr, end_addr, str, len, VAR_5); #endif
if (VAR_3 == OHCI_TD_DIR_IN && VAR_5 >= 0 && VAR_5 <= len) { ohci_copy_iso_td(VAR_0, start_addr, end_addr, VAR_0->usb_buf, VAR_5, 1); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_NOERROR); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE, VAR_5); } else if (VAR_3 == OHCI_TD_DIR_OUT && VAR_5 == len) { OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_NOERROR); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE, 0); } else { if (VAR_5 > (ssize_t) len) { printf("usb-VAR_0: DataOverrun %d > %zu\n", VAR_5, len); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_DATAOVERRUN); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,
len); } else if (VAR_5 >= 0) { printf("usb-VAR_0: DataUnderrun %d\n", VAR_5); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_DATAUNDERRUN); } else { switch (VAR_5) { case USB_RET_NODEV:
OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_DEVICENOTRESPONDING); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,
0); break; case USB_RET_NAK:
case USB_RET_STALL:
printf("usb-VAR_0: got NAK/STALL %d\n", VAR_5); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_STALL); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_SIZE,
0); break; default:
printf("usb-VAR_0: Bad device response %d\n", VAR_5); OHCI_SET_BM(VAR_7.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_UNDEXPETEDPID); break; } } } if (relative_frame_number == VAR_8) { OHCI_SET_BM(VAR_7.flags, TD_CC, OHCI_CC_NOERROR); VAR_1->head &= ~OHCI_DPTR_MASK; VAR_1->head |= (VAR_7.next & OHCI_DPTR_MASK); VAR_7.next = VAR_0->done; VAR_0->done = addr; VAR_6 = OHCI_BM(VAR_7.flags, TD_DI); if (VAR_6 < VAR_0->done_count)
VAR_0->done_count = VAR_6; } ohci_put_iso_td(VAR_0, addr, &VAR_7); return 1; }