- USB keypad now supported (patch from Ben Lunt)
- USB port config option now handled in the pciusb code (the devices "mouse" and "keypad" are currently supported)
This commit is contained in:
parent
09420bc8d2
commit
2c001794a2
@ -516,8 +516,8 @@ floppy_command_delay: 500
|
||||
# With the mouse type option you can select the type of mouse to emulate.
|
||||
# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
|
||||
# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
|
||||
# 'mode=mouse') and 'usb' (3-button mouse on USB port #1 - requires PCI and
|
||||
# USB support).
|
||||
# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
|
||||
# connected with the 'mouse' device - requires PCI and USB support).
|
||||
#
|
||||
# Examples:
|
||||
# mouse: enabled=1
|
||||
@ -649,11 +649,13 @@ keyboard_mapping: enabled=0, map=
|
||||
#=======================================================================
|
||||
# USB1:
|
||||
# This option controls the presence of the USB root hub which is a part
|
||||
# of the i440FX PCI chipset. If you enable USB and use the mouse option
|
||||
# 'type=usb' you'll have a 3-button mouse connected to port #1.
|
||||
# of the i440FX PCI chipset. With the portX option you can connect devices
|
||||
# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
|
||||
# the mouse to one of the ports and use the mouse option 'type=usb' you'll
|
||||
# have a 3-button USB mouse.
|
||||
#
|
||||
# Example:
|
||||
# usb1: enabled=1, ioaddr=0xFF80
|
||||
# usb1: enabled=1, ioaddr=0xFF80, port1=mouse, port2=keypad
|
||||
#=======================================================================
|
||||
#usb1: enabled=1, ioaddr=0xFF80
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: iodev.h,v 1.57 2004-12-31 16:40:36 vruppert Exp $
|
||||
// $Id: iodev.h,v 1.58 2005-01-14 18:28:46 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
@ -323,10 +323,13 @@ class BOCHSAPI bx_usb_stub_c : public bx_devmodel_c {
|
||||
virtual void usb_mouse_enable(bx_bool enable) {
|
||||
STUBFUNC(pciusb, usb_mouse_enable);
|
||||
}
|
||||
virtual bx_bool usb_key_enq(Bit32u key) {
|
||||
virtual bx_bool usb_key_enq(Bit8u *scan_code) {
|
||||
STUBFUNC(pciusb, usb_key_enq);
|
||||
return 0;
|
||||
}
|
||||
virtual bx_bool usb_keyboard_connected() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: keyboard.cc,v 1.99 2004-12-16 19:03:30 vruppert Exp $
|
||||
// $Id: keyboard.cc,v 1.100 2005-01-14 18:28:46 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
@ -125,7 +125,7 @@ bx_keyb_c::resetinternals(bx_bool powerup)
|
||||
void
|
||||
bx_keyb_c::init(void)
|
||||
{
|
||||
BX_DEBUG(("Init $Id: keyboard.cc,v 1.99 2004-12-16 19:03:30 vruppert Exp $"));
|
||||
BX_DEBUG(("Init $Id: keyboard.cc,v 1.100 2005-01-14 18:28:46 vruppert Exp $"));
|
||||
Bit32u i;
|
||||
|
||||
DEV_register_irq(1, "8042 Keyboard controller");
|
||||
@ -744,6 +744,14 @@ bx_keyb_c::gen_scancode(Bit32u key)
|
||||
else
|
||||
scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].make;
|
||||
|
||||
#if BX_SUPPORT_PCIUSB
|
||||
if (DEV_usb_keyboard_connected()) {
|
||||
// if we have a keyboard/keypad installed, we need to call its handler first
|
||||
if (DEV_usb_key_enq(scancode)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (BX_KEY_THIS s.kbd_controller.scancodes_translate) {
|
||||
// Translate before send
|
||||
Bit8u escaped=0x00;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: pciusb.cc,v 1.18 2004-12-30 14:50:37 vruppert Exp $
|
||||
// $Id: pciusb.cc,v 1.19 2005-01-14 18:28:47 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004 MandrakeSoft S.A.
|
||||
@ -172,8 +172,8 @@ bx_pciusb_c::reset(unsigned type)
|
||||
BX_USB_THIS last_connect = 0xFF;
|
||||
BX_USB_THIS global_reset = 0;
|
||||
BX_USB_THIS set_address_stk = 0;
|
||||
BX_USB_THIS saved_key = 0;
|
||||
BX_USB_THIS packet_key = 0;
|
||||
memset(BX_USB_THIS saved_key, 0, 8);
|
||||
memset(BX_USB_THIS key_pad_packet, 0, 8);
|
||||
|
||||
// mouse packet stuff
|
||||
BX_USB_THIS mouse_delayed_dx = 0;
|
||||
@ -223,22 +223,44 @@ bx_pciusb_c::reset(unsigned type)
|
||||
for (j=0; j<USB_CUR_DEVS; j++)
|
||||
memset(&BX_USB_THIS hub[i].device[j], 0, sizeof(USB_DEVICE));
|
||||
|
||||
BX_USB_THIS keyboard_connected = 0;
|
||||
|
||||
// include the device(s) initialize code
|
||||
#include "pciusb_devs.h"
|
||||
|
||||
// Check to see if we should connect the devices and other initialization items
|
||||
if (bx_options.Omouse_type->get() == BX_MOUSE_TYPE_USB) {
|
||||
// If one of the devices is a mouse, enable it if the user has stated so in the rc file.
|
||||
usb_set_connect_status(USB_DEV_TYPE_MOUSE, bx_options.Omouse_enabled->get());
|
||||
}
|
||||
|
||||
//if (bx_options.usb_keypad.Oenabled->get()) { // Key Pad
|
||||
if (0) { // Key Pad disabled for now
|
||||
// If one of the devices is a keypad, enable it if the user has stated so in the rc file.
|
||||
usb_set_connect_status(USB_DEV_TYPE_KEYPAD, 1);
|
||||
init_device(0, bx_options.usb[0].Oport1->getptr());
|
||||
init_device(1, bx_options.usb[0].Oport2->getptr());
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
bx_pciusb_c::init_device(Bit8u port, char *devname)
|
||||
{
|
||||
Bit8u type = USB_DEV_TYPE_NONE;
|
||||
bx_bool connected = 0;
|
||||
|
||||
if (!strlen(devname)) return;
|
||||
|
||||
if (!strcmp(devname, "mouse")) {
|
||||
type = USB_DEV_TYPE_MOUSE;
|
||||
connected = bx_options.Omouse_enabled->get();
|
||||
if (bx_options.Omouse_type->get() != BX_MOUSE_TYPE_USB) {
|
||||
BX_ERROR(("USB mouse present, but other mouse type configured"));
|
||||
}
|
||||
} else if (!strcmp(devname, "keypad")) {
|
||||
type = USB_DEV_TYPE_KEYPAD;
|
||||
connected = 1;
|
||||
BX_USB_THIS keyboard_connected = 1;
|
||||
} else {
|
||||
BX_PANIC(("unknown USB device: %s", devname));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i<USB_CUR_DEVS; i++) {
|
||||
if (BX_USB_THIS hub[0].device[i].dev_type == type) {
|
||||
BX_USB_THIS hub[0].usb_port[port].device_num = i;
|
||||
}
|
||||
}
|
||||
usb_set_connect_status(type, connected);
|
||||
}
|
||||
|
||||
void
|
||||
@ -771,8 +793,7 @@ void bx_pciusb_c::DoTransfer(struct TD *td) {
|
||||
switch (protocol) {
|
||||
case 1: // keypad
|
||||
|
||||
memset(device_buffer, 0, 8);
|
||||
device_buffer[2] = BX_USB_THIS packet_key;
|
||||
memcpy(device_buffer, BX_USB_THIS key_pad_packet, 8);
|
||||
|
||||
BX_MEM_WRITE_PHYSICAL(td->dword3, cnt, device_buffer);
|
||||
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, cnt-1);
|
||||
@ -1514,13 +1535,29 @@ bx_pciusb_c::usb_mouse_enq(int delta_x, int delta_y, int delta_z, unsigned butto
|
||||
}
|
||||
|
||||
bx_bool
|
||||
bx_pciusb_c::usb_key_enq(Bit32u key)
|
||||
bx_pciusb_c::usb_key_enq(Bit8u *scan_code)
|
||||
{
|
||||
|
||||
// BX_INFO(("scan code: len = %i 0x%02x 0x%02x 0x%02x", strlen((char *) scan_code), scan_code[0], scan_code[1], scan_code[2]));
|
||||
// return 0;
|
||||
|
||||
bx_bool is_break_code = 0;
|
||||
Bit8u our_scan_code[8];
|
||||
|
||||
memset(our_scan_code, 0, 8);
|
||||
int os = 0;
|
||||
for (int s=0; s<8; s++) {
|
||||
if ((scan_code[s] == 0xF0) && ((s == 0) || ((s == 1) && (scan_code[0] == 0xE0)))) {
|
||||
is_break_code = 1;
|
||||
} else {
|
||||
if (!(our_scan_code[os++] = scan_code[s])) break;
|
||||
}
|
||||
}
|
||||
|
||||
// if it is the break code of the saved key, then clear our packet key.
|
||||
if ((key & BX_KEY_RELEASED) && (BX_USB_THIS saved_key == (key & ~BX_KEY_RELEASED))) {
|
||||
BX_USB_THIS packet_key = 0;
|
||||
BX_USB_THIS saved_key = key;
|
||||
if (is_break_code && !memcmp(BX_USB_THIS saved_key, our_scan_code, 8)) {
|
||||
memset(BX_USB_THIS saved_key, 0, 8);
|
||||
memset(BX_USB_THIS key_pad_packet, 0, 8);
|
||||
return 1; // tell the keyboard handler that we used it, and to return with out processing key
|
||||
}
|
||||
|
||||
@ -1537,12 +1574,18 @@ bx_pciusb_c::usb_key_enq(Bit32u key)
|
||||
for (int l=0; l<dev->function.device_config[k].interfaces && !fnd; l++) {
|
||||
if ((dev->function.device_config[k].Interface[l].protocol == 1)
|
||||
&& dev->function.device_config[k].Interface[l].lookup_cnt) {
|
||||
for (int m=0; m<dev->function.device_config[k].Interface[l].lookup_cnt; m++) {
|
||||
if (dev->function.device_config[k].Interface[l].lookup[m].key == key) {
|
||||
BX_USB_THIS packet_key = dev->function.device_config[k].Interface[l].lookup[m].keypad;
|
||||
fnd = 1;
|
||||
break;
|
||||
// Only do this if the keypad is in the configured state
|
||||
if (dev->state == STATE_CONFIGURED) {
|
||||
for (int m=0; m<dev->function.device_config[k].Interface[l].lookup_cnt; m++) {
|
||||
if (!memcmp(dev->function.device_config[k].Interface[l].lookup[m].scan_code, our_scan_code, 8)) {
|
||||
memcpy(BX_USB_THIS key_pad_packet, dev->function.device_config[k].Interface[l].lookup[m].keypad_packet, 8);
|
||||
fnd = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memset(BX_USB_THIS saved_key, 0, 8);
|
||||
return 0; // if keypad is not configured, it can't send scan codes.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1550,13 +1593,31 @@ bx_pciusb_c::usb_key_enq(Bit32u key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BX_USB_THIS saved_key = key;
|
||||
|
||||
if (!fnd) BX_USB_THIS packet_key = 0;
|
||||
|
||||
if (!fnd) {
|
||||
memset(BX_USB_THIS key_pad_packet, 0, 8);
|
||||
memset(BX_USB_THIS saved_key, 0, 8);
|
||||
} else {
|
||||
memcpy(BX_USB_THIS saved_key, our_scan_code, 8);
|
||||
// print a debug line to the log file
|
||||
char bx_debug_code[128] = "";
|
||||
char value[8];
|
||||
for (unsigned i=0; i<strlen((char *) our_scan_code); i++) {
|
||||
sprintf(value, "0x%02x", our_scan_code[i]);
|
||||
if (i) strcat(bx_debug_code, " ");
|
||||
strcat(bx_debug_code, value);
|
||||
}
|
||||
BX_DEBUG(("Re-routing scan code (%s) to USB keypad", bx_debug_code));
|
||||
}
|
||||
|
||||
// tell the keyboard handler whether we used it or not. (0 = no, 1 = yes and keyboard.cc ignores keystoke)
|
||||
return fnd;
|
||||
}
|
||||
|
||||
bx_bool
|
||||
bx_pciusb_c::usb_keyboard_connected()
|
||||
{
|
||||
return BX_USB_THIS keyboard_connected;
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: pciusb.h,v 1.7 2004-12-24 21:38:01 vruppert Exp $
|
||||
// $Id: pciusb.h,v 1.8 2005-01-14 18:28:47 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004 MandrakeSoft S.A.
|
||||
@ -95,8 +95,8 @@ struct REQUEST_PACKET {
|
||||
|
||||
#define KEYPAD_LEN 128
|
||||
struct KEYPAD {
|
||||
Bit32u key;
|
||||
Bit8u keypad;
|
||||
Bit8u scan_code[8];
|
||||
Bit8u keypad_packet[8];
|
||||
};
|
||||
|
||||
#define USB_DEV_TYPE_NONE 0
|
||||
@ -355,7 +355,8 @@ public:
|
||||
virtual void reset(unsigned);
|
||||
virtual void usb_mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state);
|
||||
virtual void usb_mouse_enable(bx_bool enable);
|
||||
virtual bx_bool usb_key_enq(Bit32u key);
|
||||
virtual bx_bool usb_key_enq(Bit8u *scan_code);
|
||||
virtual bx_bool usb_keyboard_connected();
|
||||
|
||||
private:
|
||||
|
||||
@ -373,8 +374,8 @@ private:
|
||||
Bit8s mouse_z;
|
||||
Bit8u b_state;
|
||||
|
||||
Bit32u saved_key;
|
||||
Bit8u packet_key;
|
||||
Bit8u saved_key[8];
|
||||
Bit8u key_pad_packet[8];
|
||||
|
||||
static void set_irq_level(bx_bool level);
|
||||
Bit8u *device_buffer;
|
||||
@ -383,6 +384,9 @@ private:
|
||||
Bit8u set_address[128];
|
||||
|
||||
bx_bool last_connect;
|
||||
bx_bool keyboard_connected;
|
||||
|
||||
static void init_device(Bit8u port, char *devname);
|
||||
static void usb_set_connect_status(int type, bx_bool connected);
|
||||
|
||||
static void usb_timer_handler(void *);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: pciusb_devs.h,v 1.2 2004-12-19 09:59:40 vruppert Exp $
|
||||
// $Id: pciusb_devs.h,v 1.3 2005-01-14 18:28:47 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2004 MandrakeSoft S.A.
|
||||
@ -44,7 +44,6 @@
|
||||
#if USB_CYPRESS
|
||||
|
||||
BX_USB_THIS hub[0].device[0].connect_status = 0;
|
||||
BX_USB_THIS hub[0].usb_port[0].device_num = 0;
|
||||
BX_USB_THIS hub[0].device[0].dev_type = USB_DEV_TYPE_MOUSE;
|
||||
|
||||
BX_USB_THIS hub[0].device[0].state = STATE_DEFAULT;
|
||||
@ -180,7 +179,6 @@
|
||||
#if USB_KEYPAD
|
||||
|
||||
BX_USB_THIS hub[0].device[1].connect_status = 0;
|
||||
BX_USB_THIS hub[0].usb_port[1].device_num = 1;
|
||||
BX_USB_THIS hub[0].device[1].dev_type = USB_DEV_TYPE_KEYPAD;
|
||||
|
||||
BX_USB_THIS hub[0].device[1].state = STATE_DEFAULT;
|
||||
@ -229,11 +227,25 @@
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].subclass = 1;
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].protocol = 1;
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].str_indx = 5;
|
||||
|
||||
// this interface has a key conversion table of len = 18
|
||||
struct KEYPAD dev0_int0[KEYPAD_LEN] = {
|
||||
{ 0x2A, 0x45 }, { 0x53, 0x11 }, { 0x54, 0x65 }, { 0x55, 0x64 }, { 0x56, 0x53 }, { 0x57, 0x52 },
|
||||
{ 0x58, 0x63 }, { 0x59, 0x54 }, { 0x5A, 0x55 }, { 0x5B, 0x56 }, { 0x5C, 0x57 }, { 0x5D, 0x5E },
|
||||
{ 0x5E, 0x58 }, { 0x5F, 0x59 }, { 0x60, 0x5A }, { 0x61, 0x5B }, { 0x62, 0x5C }, { 0x63, 0x5D },
|
||||
{ { 0x6C, }, { 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 7
|
||||
{ { 0x6B, }, { 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 4
|
||||
{ { 0x69, }, { 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 1
|
||||
{ { 0x70, }, { 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 0
|
||||
{ { 0xE0, 0x4A, }, { 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // /
|
||||
{ { 0x75, }, { 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 8
|
||||
{ { 0x73, }, { 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 5
|
||||
{ { 0x72, }, { 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 2
|
||||
{ { 0x7C, }, { 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // *
|
||||
{ { 0x7D, }, { 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 9
|
||||
{ { 0x74, }, { 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 6
|
||||
{ { 0x7A, }, { 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // 3
|
||||
{ { 0x71, }, { 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // -
|
||||
{ { 0x7B, }, { 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // +
|
||||
{ { 0x79, }, { 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // .
|
||||
{ { 0xE0, 0x5A }, { 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00 } }, // Enter
|
||||
};
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].lookup_cnt = 18;
|
||||
memcpy(&BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].lookup, &dev0_int0, sizeof(struct KEYPAD) * KEYPAD_LEN);
|
||||
@ -281,7 +293,7 @@
|
||||
// this interface has no key conversion table
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].lookup_cnt = 0;
|
||||
memset(&BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].lookup, 0, sizeof(struct KEYPAD) * KEYPAD_LEN);
|
||||
|
||||
|
||||
// HID descriptor #2
|
||||
// 0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, 0x32, 0x00 // hid descriptor
|
||||
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].dev_hid_descript.size = 9;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: plugin.h,v 1.37 2004-12-31 16:40:36 vruppert Exp $
|
||||
// $Id: plugin.h,v 1.38 2005-01-14 18:28:45 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file provides macros and types needed for plugins. It is based on
|
||||
@ -205,14 +205,16 @@ extern "C" {
|
||||
#define DEV_bus_mouse_enq(dx, dy, dz, state) \
|
||||
(bx_devices.pluginBusMouse->bus_mouse_enq(dx, dy, 0, state))
|
||||
|
||||
///////// USB mouse macro
|
||||
///////// USB device macros
|
||||
#if BX_SUPPORT_PCIUSB
|
||||
#define DEV_usb_mouse_enq(dx, dy, dz, state) \
|
||||
#define DEV_usb_mouse_enq(dx, dy, dz, state) \
|
||||
(bx_devices.pluginPciUSBAdapter->usb_mouse_enq(dx, dy, dz, state))
|
||||
#define DEV_usb_mouse_enable(enable) \
|
||||
#define DEV_usb_mouse_enable(enable) \
|
||||
(bx_devices.pluginPciUSBAdapter->usb_mouse_enable(enable))
|
||||
#define DEV_usb_key_enq(key) \
|
||||
(bx_devices.pluginPciUSBAdapter->usb_key_enq(key))
|
||||
#define DEV_usb_key_enq(scan_code) \
|
||||
(bx_devices.pluginPciUSBAdapter->usb_key_enq(scan_code))
|
||||
#define DEV_usb_keyboard_connected() \
|
||||
(bx_devices.pluginPciUSBAdapter->usb_keyboard_connected())
|
||||
#endif
|
||||
|
||||
//////// Memory macros
|
||||
|
Loading…
Reference in New Issue
Block a user