static void EthHandleBinding(void) { net_binding_t *bind; request_eth_t req_eth; union { uint8_t raw[ETH_FRAME_LEN]; net_ether header; } packet; page_array_t *pages; io_callback_t cb; event_t *event; net_hwaddr_t src, dst; bind = ThrGetCurrent()->info->param; pages = MemCreatePageArray(packet.raw, sizeof(packet.raw)); event = EvtCreate(false); src.type = dst.type = NET_HW_ETHERNET; src.data_size = dst.data_size = 6; while (true) { req_eth.header.code = ETH_RECEIVE; req_eth.header.param = (void*) event; memcpy(req_eth.params.eth_receive.from, bcast, sizeof(bcast)); req_eth.params.eth_receive.type = (uint16_t) (addr_t) bind->hw_cookie; req_eth.params.eth_receive.pages = pages; req_eth.params.eth_receive.length = sizeof(packet.raw); cb.type = IO_CALLBACK_FUNCTION; cb.u.function = EthHandleBindingCompletion; if (!IoRequest(&cb, bind->dev, &req_eth.header)) { wprintf(L"EthHandleBinding: IoRequest error\n"); break; } ThrWaitHandle(ThrGetCurrent(), &event->hdr); KeYield(); memcpy(src.u.ethernet, packet.header.src, sizeof(src.u.ethernet)); memcpy(dst.u.ethernet, packet.header.dst, sizeof(dst.u.ethernet)); if (bind->proto->vtbl->receive_packet != NULL) bind->proto->vtbl->receive_packet(bind->proto, bind, &src, &dst, packet.raw + sizeof(packet.header), req_eth.params.eth_receive.length - sizeof(packet.header)); } HndClose(&event->hdr); ThrExitThread(0); KeYield(); }
bool IoAlcorFirmware::GetVersion(uint16_t& out_version) { const Operation inst(Op::Version); Operation outbuf; if(IoRequest(inst, outbuf) && IoWaitRequestOutput4(inst, outbuf)) { out_version = outbuf.Out0<uint16_t>(); return true; } return false; }
bool IoAlcorFirmware::FlashTellSuccessProgramming() { const Operation inst_program(Op::Program, true, 0, 0); Operation outbuf; // XXX weirdly CoolerMaster does [something like] IoRequest in a loop here until it acks instead of IoWait'ing. if(IoRequest(inst_program, outbuf) && IoWaitRequestOutput4(inst_program, outbuf)) { return (outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == success_request; } return false; }
bool IoAlcorFirmware::GetNumber2(uint32_t& out_2) { const Operation inst(Op::Return2); Operation outbuf; if(IoRequest(inst, outbuf) && IoWaitRequestOutput4(inst, outbuf)) { out_2 = outbuf.Out0<uint32_t>(); return true; } return false; }
bool IoAlcorFirmware::FlashProgram(uint32_t begin, uint32_t end, void* datav, uint16_t& out_datav_checksum) { const Operation inst_program(Op::Program, false, begin, end); Operation outbuf; uint8_t* data = (uint8_t*)(datav); out_datav_checksum = 0; // Ensure range is correct. if(begin > end) return false; // Ensure word alignment on begin, and one byte before alignment on end. if((begin % 4) != 0 || (end % 4) != 3) return false; // For security reasons only allow flashing the user settings area. if(begin >= 0xD800 && end <= 0x1F7FF) { if(IoRequest(inst_program, outbuf) && IoWaitRequestOutput4(inst_program, outbuf)) { if((outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == success_request) { for(uint32_t addr = begin; addr < end; addr += bytes_step) { // We need a temporary buffer because of report id on the first byte uint8_t buffer[feature_size]; auto left = (end - addr) + 1; auto it_bytes = (std::min)(left, bytes_step); std::memset(buffer, 0, feature_size); // necessary because next memcpy mayn't copy feature_size due to std::min std::memcpy(&buffer[1], &data[addr - begin], it_bytes); for(uint32_t idsum = 0; idsum < it_bytes; ++idsum) { if((addr + idsum != 0xD800) && (addr + idsum != 0xD801)) { out_datav_checksum += buffer[idsum+1]; // (+1 to skip report id) } } if(!IoBytesInput(inst_program, buffer, feature_size)) return false; } return true; } } } return false; }
bool IoAlcorFirmware::IoEnableUnsafe(bool enable) { const Operation inst(Op::EnableUnsafe, uint32_t(enable? 0x29156767 : 0x0)); Operation outbuf; if(IoRequest(inst, outbuf) && IoWaitRequestOutput4(inst, outbuf)) { if(enable) return ((outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == success_request); else return ((outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == failed_request); } return false; }
bool IoAlcorFirmware::MemoryRead(uint32_t begin, uint32_t end, void* dataoutv) { const Operation inst_trigger(Op::ReadBytes, begin, end); Operation outbuf; uint8_t* dataout = (uint8_t*)(dataoutv); // Ensure range is correct. if(begin > end) return false; // Ensure word alignment on begin, and one byte before alignment on end. if((begin % 4) != 0 || (end % 4) != 3) return false; // Ensure the memory won't segfault during writing, if it is to segfault when reading from // the mouse memory, bad things may happen. std::memset(dataoutv, 0, (end - begin) + 1); if(IoRequest(inst_trigger, outbuf) && IoWaitRequestOutput4(inst_trigger, outbuf)) { if((outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == success_request) { static_assert(bytes_step + 1 == feature_size, ""); for(uint32_t addr = begin; addr < end; addr += bytes_step) { // We need a temporary buffer because of report id on the first byte uint8_t buffer[feature_size]; if(!IoBytesOutput(buffer, feature_size)) return false; auto left = (end - addr) + 1; std::memcpy(&dataout[addr - begin], &buffer[1], (std::min)(left, bytes_step)); } return true; } } return false; }
bool IoAlcorFirmware::FlashErasePages(uint32_t begin, uint32_t end) { const Operation inst_erase(Op::Erase, begin, end); Operation outbuf; // Ensure range is correct. if(begin > end) return false; // Ensure word alignment on begin, and one byte before alignment on end. if((begin % 4) != 0 || (end % 4) != 3) return false; // For security reasons only allow flashing the user settings area. if(begin >= 0xD800 && end <= 0x1F7FF) { if(IoRequest(inst_erase, outbuf) && IoWaitRequestOutput4(inst_erase, outbuf)) { return ((outbuf.out[0] & outbuf.out[1] & outbuf.out[2] & outbuf.out[3]) == success_request); } } return false; }
bool IoAlcorFirmware::Checksum(uint32_t begin, uint32_t end, uint16_t& out_checksum) { const Operation inst_checksum(Op::Checksum, begin, end); Operation outbuf; // Ensure range is correct. if(begin > end) return false; // Ensure word alignment on begin, and one byte before alignment on end. if((begin % 4) != 0 || (end % 4) != 3) return false; if(IoRequest(inst_checksum, outbuf) && IoWaitRequestOutput2(inst_checksum, outbuf)) { if((outbuf.out[0] & outbuf.out[1]) == success_request) { out_checksum = outbuf.Out2<uint16_t>(); return true; } } return false; }
status_t CdfsReadWriteFile(fsd_t *fsd, const fs_request_t *req, size_t *bytes) { cdfs_t *cdfs; cdnode_t *cdnode; io_callback_t cb; request_dev_t *dev_request; int length; uint32_t aligned_file_length; cdfs = (cdfs_t*) fsd; cdnode = req->file->fsd_cookie; //wprintf(L"CdfsReadWriteFile(%x): %u bytes at %u\n", //cdnode->id, req->length, (unsigned) req->pos); if (!req->is_reading) { wprintf(L"CdfsReadWriteFile: read-only\n"); return EACCESS; } aligned_file_length = (cdnode->entry.length.native + SECTOR_SIZE - 1) & -SECTOR_SIZE; if (req->pos >= aligned_file_length) { wprintf(L"CdfsReadWriteFile: read past end of file (aligned_file_length = %u)\n", aligned_file_length); return EEOF; } if (req->pos + req->length >= aligned_file_length) length = aligned_file_length - req->pos; else length = req->length; assert((req->pos & (SECTOR_SIZE - 1)) == 0); assert((length & (SECTOR_SIZE - 1)) == 0); assert(length == SECTOR_SIZE); dev_request = malloc(sizeof(*dev_request)); if (dev_request == NULL) return errno; dev_request->header.code = DEV_READ; dev_request->params.buffered.pages = req->pages; dev_request->params.buffered.length = length; dev_request->params.buffered.offset = cdnode->entry.first_sector.native * SECTOR_SIZE + req->pos; dev_request->header.param = req->io; //wprintf(L"\t=> %u bytes at 0x%x\n", //dev_request->params.buffered.length, //dev_request->params.buffered.offset); cb.type = IO_CALLBACK_FSD; cb.u.fsd = &cdfs->fsd; if (!IoRequest(&cb, cdfs->device, &dev_request->header)) { status_t ret; wprintf(L"CdfsReadWriteFile: request failed straight away\n"); *bytes = dev_request->params.buffered.length; ret = dev_request->header.result; free(dev_request); return ret; } return SIOPENDING; }