1#!/bin/sh
2
3hid_conf_directory="/sys/kernel/config/usb_gadget/obmc_hid"
4dev_name="80401000.udc"
5
6create_hid() {
7    # create gadget
8    mkdir "${hid_conf_directory}"
9    cd "${hid_conf_directory}" || exit 1
10
11    # add basic information
12    echo 0x0100 > bcdDevice
13    echo 0x0200 > bcdUSB
14    echo 0x0104 > idProduct		# Multifunction Composite Gadget
15    echo 0x1d6b > idVendor		# Linux Foundation
16
17    # create English locale
18    mkdir strings/0x409
19
20    echo "OpenBMC" > strings/0x409/manufacturer
21    echo "virtual_input" > strings/0x409/product
22    echo "OBMC0001" > strings/0x409/serialnumber
23
24    # Create HID keyboard function
25    mkdir functions/hid.0
26
27    echo 1 > functions/hid.0/protocol	# 1: keyboard
28    echo 8 > functions/hid.0/report_length
29    echo 1 > functions/hid.0/subclass
30
31    # Binary HID keyboard descriptor
32    #  0x05, 0x01, // USAGE_PAGE (Generic Desktop)
33    #  0x09, 0x06, // USAGE (Keyboard)
34    #  0xa1, 0x01, // COLLECTION (Application)
35    #  0x05, 0x07, //   USAGE_PAGE (Keyboard)
36    #  0x19, 0xe0, //   USAGE_MINIMUM (Keyboard LeftControl)
37    #  0x29, 0xe7, //   USAGE_MAXIMUM (Keyboard Right GUI)
38    #  0x15, 0x00, //   LOGICAL_MINIMUM (0)
39    #  0x25, 0x01, //   LOGICAL_MAXIMUM (1)
40    #  0x75, 0x01, //   REPORT_SIZE (1)
41    #  0x95, 0x08, //   REPORT_COUNT (8)
42    #  0x81, 0x02, //   INPUT (Data,Var,Abs)
43    #  0x95, 0x01, //   REPORT_COUNT (1)
44    #  0x75, 0x08, //   REPORT_SIZE (8)
45    #  0x81, 0x03, //   INPUT (Data,Var,Abs)
46    #  0x95, 0x05, //   REPORT_COUNT (5)
47    #  0x75, 0x01, //   REPORT_SIZE (1)
48    #  0x05, 0x08, //   USAGE_PAGE (LEDs)
49    #  0x19, 0x01, //   USAGE_MINIMUM (Num Lock)
50    #  0x29, 0x05, //   USAGE_MAXIMUM (Kana)
51    #  0x91, 0x02, //   OUTPUT (Data,Var,Abs)
52    #  0x95, 0x01, //   REPORT_COUNT (1)
53    #  0x75, 0x03, //   REPORT_SIZE (3)
54    #  0x91, 0x03, //   OUTPUT (Cnst,Var,Abs)
55    #  0x95, 0x06, //   REPORT_COUNT (6)
56    #  0x75, 0x08, //   REPORT_SIZE (8)
57    #  0x15, 0x00, //   LOGICAL_MINIMUM (0)
58    #  0x25, 0x65, //   LOGICAL_MAXIMUM (101)
59    #  0x05, 0x07, //   USAGE_PAGE (Keyboard)
60    #  0x19, 0x00, //   USAGE_MINIMUM (Reserved (no event indicated))
61    #  0x29, 0x65, //   USAGE_MAXIMUM (Keyboard Application)
62    #  0x81, 0x00, //   INPUT (Data,Ary,Abs)
63    #  0xc0        // END_COLLECTION
64    printf '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc
65
66    # Create HID mouse function
67    mkdir functions/hid.1
68
69    echo 2 > functions/hid.1/protocol	# 2: mouse
70    echo 6 > functions/hid.1/report_length
71    echo 1 > functions/hid.1/subclass
72
73    # Binary HID mouse descriptor (absolute coordinate)
74    #  0x05, 0x01,       // USAGE_PAGE (Generic Desktop)
75    #  0x09, 0x02,       // USAGE (Mouse)
76    #  0xa1, 0x01,       // COLLECTION (Application)
77    #  0x09, 0x01,       //   USAGE (Pointer)
78    #  0xa1, 0x00,       //   COLLECTION (Physical)
79    #  0x05, 0x09,       //     USAGE_PAGE (Button)
80    #  0x19, 0x01,       //     USAGE_MINIMUM (Button 1)
81    #  0x29, 0x03,       //     USAGE_MAXIMUM (Button 3)
82    #  0x15, 0x00,       //     LOGICAL_MINIMUM (0)
83    #  0x25, 0x01,       //     LOGICAL_MAXIMUM (1)
84    #  0x95, 0x03,       //     REPORT_COUNT (3)
85    #  0x75, 0x01,       //     REPORT_SIZE (1)
86    #  0x81, 0x02,       //     INPUT (Data,Var,Abs)
87    #  0x95, 0x01,       //     REPORT_COUNT (1)
88    #  0x75, 0x05,       //     REPORT_SIZE (5)
89    #  0x81, 0x03,       //     INPUT (Cnst,Var,Abs)
90    #  0x05, 0x01,       //     USAGE_PAGE (Generic Desktop)
91    #  0x09, 0x30,       //     USAGE (X)
92    #  0x09, 0x31,       //     USAGE (Y)
93    #  0x35, 0x00,       //     PHYSICAL_MINIMUM (0)
94    #  0x46, 0xff, 0x7f, //     PHYSICAL_MAXIMUM (32767)
95    #  0x15, 0x00,       //     LOGICAL_MINIMUM (0)
96    #  0x26, 0xff, 0x7f, //     LOGICAL_MAXIMUM (32767)
97    #  0x65, 0x11,       //     UNIT (SI Lin:Distance)
98    #  0x55, 0x00,       //     UNIT_EXPONENT (0)
99    #  0x75, 0x10,       //     REPORT_SIZE (16)
100    #  0x95, 0x02,       //     REPORT_COUNT (2)
101    #  0x81, 0x02,       //     INPUT (Data,Var,Abs)
102    #  0x09, 0x38,       //     Usage (Wheel)
103    #  0x15, 0xff,       //     LOGICAL_MINIMUM (-1)
104    #  0x25, 0x01,       //     LOGICAL_MAXIMUM (1)
105    #  0x35, 0x00,       //     PHYSICAL_MINIMUM (-127)
106    #  0x45, 0x00,       //     PHYSICAL_MAXIMUM (127)
107    #  0x75, 0x08,       //     REPORT_SIZE (8)
108    #  0x95, 0x01,       //     REPORT_COUNT (1)
109    #  0x81, 0x06,       //     INPUT (Data,Var,Rel)
110    #  0xc0,             //   END_COLLECTION
111    #  0xc0              // END_COLLECTION
112    printf '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\x09\x38\x15\xff\x25\x01\x35\x00\x45\x00\x75\x08\x95\x01\x81\x06\xc0\xc0' > functions/hid.1/report_desc
113
114    # Create configuration
115    mkdir configs/c.1
116    mkdir configs/c.1/strings/0x409
117
118    echo 0xe0 > configs/c.1/bmAttributes
119    echo 200 > configs/c.1/MaxPower
120    echo "" > configs/c.1/strings/0x409/configuration
121
122    # Link HID functions to configuration
123    ln -s functions/hid.0 configs/c.1
124    ln -s functions/hid.1 configs/c.1
125}
126
127connect_hid() {
128    if ! grep -q "${dev_name}" UDC; then
129        echo "${dev_name}" > UDC
130    fi
131}
132
133disconnect_hid() {
134    if grep -q "${dev_name}" UDC; then
135        echo "" > UDC
136    fi
137}
138
139if [ ! -e "${hid_conf_directory}" ]; then
140    create_hid
141else
142    cd "${hid_conf_directory}" || exit 1
143fi
144
145if [ "$1" = "connect" ]; then
146    connect_hid
147elif [ "$1" = "disconnect" ]; then
148    disconnect_hid
149else
150    echo >&2 "Invalid option: $1. Use 'connect' or 'disconnect'."
151    exit 1
152fi
153