USB: Sony DPP-MP1 printer emulation

This commit is contained in:
Florin9doi 2021-07-12 22:47:54 +03:00 committed by refractionpcsx2
parent 04ef9af703
commit 6a3f093cfa
7 changed files with 478 additions and 5 deletions

View File

@ -412,6 +412,7 @@ set(pcsx2USBSources
USB/shared/shared_usb.cpp
USB/shared/inifile_usb.cpp
USB/shared/ringbuffer.cpp
USB/usb-printer/usb-printer.cpp
)
# USB headers
@ -456,6 +457,7 @@ set(pcsx2USBHeaders
USB/shared/shared_usb.h
USB/shared/inifile_usb.h
USB/shared/ringbuffer.h
USB/usb-printer/usb-printer.h
)
if(TARGET PulseAudio::PulseAudio)

View File

@ -15,12 +15,13 @@
#include "PrecompiledHeader.h"
#include "deviceproxy.h"
#include "usb-pad/usb-pad.h"
#include "usb-msd/usb-msd.h"
#include "usb-mic/usb-mic-singstar.h"
#include "usb-mic/usb-headset.h"
#include "usb-hid/usb-hid.h"
#include "usb-eyetoy/usb-eyetoy-webcam.h"
#include "usb-hid/usb-hid.h"
#include "usb-mic/usb-headset.h"
#include "usb-mic/usb-mic-singstar.h"
#include "usb-msd/usb-msd.h"
#include "usb-pad/usb-pad.h"
#include "usb-printer/usb-printer.h"
void RegisterDevice::Register()
{
@ -43,6 +44,7 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_EYETOY, new DeviceProxy<usb_eyetoy::EyeToyWebCamDevice>());
inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy<usb_hid::BeatManiaDevice>());
inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>());
inst.Add(DEVTYPE_PRINTER, new DeviceProxy<usb_printer::PrinterDevice>());
inst.Add(DEVTYPE_KEYBOARDMANIA, new DeviceProxy<usb_pad::KeyboardmaniaDevice>());
RegisterAPIs();

View File

@ -49,6 +49,7 @@ enum DeviceType
DEVTYPE_EYETOY,
DEVTYPE_BEATMANIA_DADADA,
DEVTYPE_SEGA_SEAMIC,
DEVTYPE_PRINTER,
DEVTYPE_KEYBOARDMANIA,
};

View File

@ -0,0 +1,296 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "../qemu-usb/vl.h"
#include "../shared/inifile_usb.h"
#include "usb-printer.h"
#include "gui/AppConfig.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
namespace usb_printer
{
typedef struct PrinterState
{
USBDevice dev;
USBDesc desc;
USBDescDevice desc_dev;
int selected_printer;
int cmd_state;
uint8_t last_command[65];
int last_command_size;
int print_file;
int width;
int height;
int data_size;
} PrinterState;
static void usb_printer_handle_reset(USBDevice* dev)
{
PrinterState* s = (PrinterState*)dev;
s->cmd_state = 0;
if (s->print_file > 0)
{
close(s->print_file);
}
s->print_file = -1;
}
static void usb_printer_handle_control(USBDevice* dev, USBPacket* p, int request, int value,
int index, int length, uint8_t* data)
{
PrinterState* s = (PrinterState*)dev;
int ret = 0;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0)
{
return;
}
switch (request)
{
case ClassInterfaceRequest | GET_DEVICE_ID:
ret = 2 + sprintf((char*)data + 2, sPrinters[s->selected_printer].device_id);
data[0] = ret >> 8;
data[1] = ret & 0xff;
p->actual_length = ret;
break;
case ClassInterfaceRequest | GET_PORT_STATUS:
data[0] = GET_PORT_STATUS_PAPER_NOT_EMPTY | GET_PORT_STATUS_SELECTED | GET_PORT_STATUS_NO_ERROR;
p->actual_length = 1;
break;
}
}
void sony_open_file(PrinterState* s)
{
char filepath[1024];
char cur_time_str[32];
const time_t cur_time = time(nullptr);
strftime(cur_time_str, sizeof(cur_time_str), "%Y_%m_%d_%H_%M_%S", localtime(&cur_time));
snprintf(filepath, sizeof(filepath), "%s/print_%s.ppm",
g_Conf->Folders.Snapshots.ToString().ToStdString().c_str(), cur_time_str);
s->print_file = open(filepath, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 666);
if (s->print_file < 0)
{
Console.WriteLn("Printer: Sony: Cannot open: %s", filepath);
return;
}
Console.WriteLn("Printer: Sony: Saving to... %s", filepath);
char header[30];
int header_size = sprintf(header, "P6 %d %d 255\n", s->width, s->height);
write(s->print_file, header, header_size);
}
void sony_write_data(PrinterState* s, int size, uint8_t* data)
{
if (s->print_file >= 0)
{
write(s->print_file, data, size);
}
}
void sony_close_file(PrinterState* s)
{
Console.WriteLn("Printer: Sony: done.");
if (s->print_file >= 0)
{
close(s->print_file);
}
s->print_file = -1;
}
static void usb_printer_handle_data_sony(USBDevice* dev, USBPacket* p)
{
struct req_reply
{
uint8_t cmd[64];
uint8_t ret[256];
};
const struct req_reply commands[] =
{
{
{0x1B, 0xE0, 0x00, 0x00, 0x00, 0x0E, 0x00},
{0x0D, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x24, 0x38, 0x03, 0xF2, 0x02, 0x74}
},
{
{0x1B, 0xCF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00},
{0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
},
{
{0x1B, 0xCF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00},
{0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x07}
},
{
{0x1B, 0xCF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00},
{0x00, 0x00, 0x00, 0x12, 0x03, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x04}
},
{
{0x1B, 0xCF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00},
{0x00, 0x00, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x18, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00}
},
{
{0x1B, 0xCF, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00},
{0x00, 0x00, 0x00, 0x0E, 0x05, 0x00, 0x02, 0x74, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00}
},
{
{0x1B, 0x12, 0x01, 0x00, 0x00, 0x19, 0x00},
{0x02, 0xC0, 0x00, 0x15, 0x03, 0xF2, 0x02, 0x74, 0x03, 0xF2, 0x02, 0x74, 0x01, 0x33, 0x00, 0x00,
0x15, 0x01, 0x03, 0x23, 0x30, 0x31, 0x2E, 0x30, 0x30}
}
};
const uint8_t set_size[] = {0x00, 0x00, 0x00, 0x00, 0xa7, 0x00};
const uint8_t set_data[] = {0x1b, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t print_compl[] = {0x1b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00};
PrinterState* s = (PrinterState*)dev;
const uint8_t ep_nr = p->ep->nr;
const uint8_t ep_type = p->ep->type;
switch (p->pid)
{
case USB_TOKEN_OUT:
s->last_command_size = p->iov.size;
usb_packet_copy(p, s->last_command, s->last_command_size);
if (s->cmd_state == 0 && s->last_command_size > 5)
{
if (memcmp(s->last_command, set_size, sizeof(set_size)) == 0)
{
s->width = s->last_command[9] << 8 | s->last_command[10];
s->height = s->last_command[11] << 8 | s->last_command[12];
Console.WriteLn("Printer: Sony: Size=%dx%d", s->width, s->height);
sony_open_file(s);
}
else if (memcmp(s->last_command, set_data, sizeof(set_data)) == 0)
{
s->data_size = s->last_command[8] << 8 | s->last_command[9];
s->cmd_state = 1;
}
else if (memcmp(s->last_command, print_compl, sizeof(print_compl)) == 0)
{
sony_close_file(s);
}
}
else if (s->cmd_state == 1 && s->last_command_size > 0)
{
sony_write_data(s, s->last_command_size, s->last_command);
s->data_size -= s->last_command_size;
if (s->data_size <= 0)
{
s->cmd_state = 0;
}
}
break;
case USB_TOKEN_IN:
if (s->cmd_state == 0 && s->last_command_size > 0)
{
for (int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
{
if (s->last_command[1] == 0xCF)
{
if (memcmp(s->last_command, commands[i].cmd, 11) == 0)
{
int length = commands[i].cmd[9];
usb_packet_copy(p, (void*)commands[i].ret, length);
s->last_command_size = 0;
}
}
else
{
if (memcmp(s->last_command, commands[i].cmd, 7) == 0)
{
int length = commands[i].cmd[5];
usb_packet_copy(p, (void*)commands[i].ret, length);
s->last_command_size = 0;
}
}
}
}
break;
default:
p->status = USB_RET_STALL;
break;
}
}
static void usb_printer_handle_destroy(USBDevice* dev)
{
PrinterState* s = (PrinterState*)dev;
delete s;
}
USBDevice* PrinterDevice::CreateDevice(int port)
{
PrinterState* s = new PrinterState();
std::string api = *PrinterDevice::ListAPIs().begin();
int subtype = GetSelectedSubtype(std::make_pair(port, TypeName()));
if (subtype >= sizeof(sPrinters) / sizeof(sPrinters[0])) {
subtype = 0;
}
s->selected_printer = subtype;
s->dev.speed = USB_SPEED_FULL;
s->desc.full = &s->desc_dev;
s->desc.str = sPrinters[subtype].usb_strings;
if (usb_desc_parse_dev(sPrinters[subtype].device_descriptor, sPrinters[subtype].device_descriptor_size, s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(sPrinters[subtype].config_descriptor, sPrinters[subtype].config_descriptor_size, s->desc_dev) < 0)
goto fail;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = usb_printer_handle_reset;
s->dev.klass.handle_control = usb_printer_handle_control;
switch (sPrinters[subtype].protocol)
{
case ProtocolSonyUPD:
s->dev.klass.handle_data = usb_printer_handle_data_sony;
break;
}
s->dev.klass.unrealize = usb_printer_handle_destroy;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = s->desc.str[2];
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
usb_printer_handle_reset((USBDevice*)s);
return (USBDevice*)s;
fail:
usb_printer_handle_destroy((USBDevice*)s);
return nullptr;
}
int PrinterDevice::Configure(int port, const std::string& api, void* data)
{
return 0;
}
int PrinterDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data)
{
return 0;
}
} // namespace usb_printer

View File

@ -0,0 +1,161 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USBPRINTER_H
#define USBPRINTER_H
#include "../deviceproxy.h"
#include "../qemu-usb/desc.h"
#define GET_DEVICE_ID 0
#define GET_PORT_STATUS 1
#define SOFT_RESET 2
#define GET_PORT_STATUS_PAPER_EMPTY 1<<5
#define GET_PORT_STATUS_PAPER_NOT_EMPTY 0<<5
#define GET_PORT_STATUS_SELECTED 1<<4
#define GET_PORT_STATUS_NOT_SELECTED 0<<4
#define GET_PORT_STATUS_NO_ERROR 1<<3
#define GET_PORT_STATUS_ERROR 0<<3
namespace usb_printer
{
static const uint8_t dpp_mp1_dev_desciptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0x4C, 0x05, // idVendor 0x054C
0x65, 0x00, // idProduct 0x0065
0x04, 0x02, // bcdDevice 2.04
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static int dpp_mp1_dev_desciptor_size = sizeof(dpp_mp1_dev_desciptor);
static const uint8_t dpp_mp1_config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x20, 0x00, // wTotalLength 32
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0xC0, // bmAttributes Self Powered
0x00, // bMaxPower 0mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x07, // bInterfaceClass
0x01, // bInterfaceSubClass
0x02, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x01, // bEndpointAddress (OUT/H2D)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x82, // bEndpointAddress (IN/D2H)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
};
static int dpp_mp1_config_descriptor_size = sizeof(dpp_mp1_config_descriptor);
enum PrinterModel
{
Sony_DPP_MP1,
};
enum PrinterProtocol
{
ProtocolSonyUPD,
};
struct PrinterData
{
PrinterModel model;
char* commercial_name;
const uint8_t* device_descriptor;
const int device_descriptor_size;
const uint8_t* config_descriptor;
const int config_descriptor_size;
const USBDescStrings usb_strings;
char* device_id;
PrinterProtocol protocol;
};
static const PrinterData sPrinters[] = {
{
Sony_DPP_MP1,
"Sony DPP-MP1",
dpp_mp1_dev_desciptor, dpp_mp1_dev_desciptor_size,
dpp_mp1_config_descriptor, dpp_mp1_config_descriptor_size,
{"", "SONY", "USB printer"},
"MFG:SONY;MDL:DPP-MP1;DES:SONYDPP-MP1;CMD:SONY-Original;CLS:PRINTER",
ProtocolSonyUPD,
},
};
static const char* APINAME = "default";
class PrinterDevice
{
public:
virtual ~PrinterDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
return TEXT("Printer");
}
static const char* TypeName()
{
return "printer";
}
static std::list<std::string> ListAPIs()
{
return std::list<std::string>{APINAME};
}
static const TCHAR* LongAPIName(const std::string& name)
{
return TEXT("Default");
}
static int Configure(int port, const std::string& api, void* data);
static int Freeze(FreezeAction mode, USBDevice* dev, void* data);
static std::vector<std::string> SubTypes()
{
std::vector<std::string> ret;
for (int i = 0; i < sizeof(sPrinters) / sizeof(sPrinters[0]); i++)
{
ret.push_back(sPrinters[i].commercial_name);
}
return ret;
}
};
} // namespace usb_printer
#endif

View File

@ -453,6 +453,7 @@
<ClCompile Include="USB\usb-pad\usb-pad-ff.cpp" />
<ClCompile Include="USB\usb-pad\usb-pad.cpp" />
<ClCompile Include="USB\usb-pad\usb-seamic.cpp" />
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
<ClCompile Include="USB\USB.cpp" />
<ClCompile Include="USB\Win32\Config_usb.cpp" />
<ClCompile Include="GS\Renderers\OpenGL\GLLoader.cpp" />
@ -943,6 +944,7 @@
<ClInclude Include="USB\usb-pad\raw\raw-config-res.h" />
<ClInclude Include="USB\usb-pad\raw\usb-pad-raw.h" />
<ClInclude Include="USB\usb-pad\usb-pad.h" />
<ClInclude Include="USB\usb-printer\usb-printer.h" />
<ClInclude Include="USB\USB.h" />
<ClInclude Include="USB\Win32\Config_usb.h" />
<ClInclude Include="USB\Win32\resource_usb.h" />

View File

@ -241,6 +241,9 @@
<Filter Include="System\Ps2\USB\usb-pad\raw">
<UniqueIdentifier>{8640e8ca-7d79-4221-b1bf-35bc142a9add}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\USB\usb-printer">
<UniqueIdentifier>{343981c6-ca99-462d-9b20-0500a23ae4cd}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\PAD">
<UniqueIdentifier>{e1cbcaf6-9f65-4f14-9e89-27dd0f10e047}</UniqueIdentifier>
</Filter>
@ -1316,6 +1319,9 @@
<ClCompile Include="USB\usb-msd\usb-msd-win32.cpp">
<Filter>System\Ps2\USB\usb-msd</Filter>
</ClCompile>
<ClCompile Include="USB\usb-printer\usb-printer.cpp">
<Filter>System\Ps2\USB\usb-printer</Filter>
</ClCompile>
<ClCompile Include="USB\shared\hidapi.cpp">
<Filter>System\Ps2\USB\shared</Filter>
</ClCompile>
@ -2386,6 +2392,9 @@
<ClInclude Include="USB\usb-mic\audiodev-wasapi.h">
<Filter>System\Ps2\USB\usb-mic</Filter>
</ClInclude>
<ClInclude Include="USB\usb-printer\usb-printer.h">
<Filter>System\Ps2\USB\usb-printer</Filter>
</ClInclude>
<ClInclude Include="USB\shared\hidapi.h">
<Filter>System\Ps2\USB\shared</Filter>
</ClInclude>