| 1853 | } |
| 1854 | |
| 1855 | void vuart_av_thread::parse_tx_buffer(u32 buf_size) { |
| 1856 | if (buf_size >= PS3AV_TX_BUF_SIZE) { |
| 1857 | while (read_tx_data(temp_tx_buf, PS3AV_TX_BUF_SIZE) >= PS3AV_TX_BUF_SIZE) |
| 1858 | ; |
| 1859 | write_resp(reinterpret_cast<be_t<u16, 1> *>(temp_tx_buf)[3], |
| 1860 | PS3AV_STATUS_BUFFER_OVERFLOW); |
| 1861 | return; |
| 1862 | } |
| 1863 | |
| 1864 | u32 read_ptr = 0; |
| 1865 | |
| 1866 | while (buf_size) { |
| 1867 | const ps3av_header *const hdr = |
| 1868 | reinterpret_cast<ps3av_header *>(&temp_tx_buf[read_ptr]); |
| 1869 | const u16 pkt_size = hdr->length + 4; |
| 1870 | |
| 1871 | if (hdr->length == 0xFFFCU) { |
| 1872 | write_resp(0xDEAD, PS3AV_STATUS_FAILURE); |
| 1873 | return; |
| 1874 | } |
| 1875 | |
| 1876 | if (hdr->version != PS3AV_VERSION) { |
| 1877 | if (hdr->version >= 0x100 && hdr->version < PS3AV_VERSION) { |
| 1878 | sys_uart.todo("Unimplemented AV version: 0x%04x", hdr->version); |
| 1879 | } |
| 1880 | |
| 1881 | write_resp(static_cast<u16>(hdr->cid.get()), |
| 1882 | PS3AV_STATUS_INVALID_COMMAND); |
| 1883 | return; |
| 1884 | } |
| 1885 | |
| 1886 | const void *const pkt_storage = &temp_tx_buf[read_ptr]; |
| 1887 | read_ptr += pkt_size; |
| 1888 | buf_size = buf_size < pkt_size ? 0 : buf_size - pkt_size; |
| 1889 | |
| 1890 | auto cmd = get_cmd(hdr->cid); |
| 1891 | |
| 1892 | if (!cmd.get()) { |
| 1893 | sys_uart.error("Unknown AV cmd: 0x%08x", hdr->cid); |
| 1894 | continue; |
| 1895 | } |
| 1896 | |
| 1897 | const auto cmd_size = cmd->get_size(*this, pkt_storage); |
| 1898 | |
| 1899 | if (cmd_size != pkt_size && cmd_size) { |
| 1900 | sys_uart.error("Invalid size for cid=0x%x, expected=0x%x, got=0x%x", |
| 1901 | static_cast<const ps3av_header *>(pkt_storage)->cid, |
| 1902 | cmd_size, pkt_size); |
| 1903 | write_resp(static_cast<u16>(hdr->cid.get()), |
| 1904 | PS3AV_STATUS_INVALID_SAMPLE_SIZE); |
| 1905 | return; |
| 1906 | } |
| 1907 | |
| 1908 | cmd->execute(*this, pkt_storage); |
| 1909 | } |
| 1910 | } |
| 1911 | |
| 1912 | vuart_av_thread &vuart_av_thread::operator=(thread_state) { |