1#!/bin/bash
2
3# an auxiliary script to produce a "stub" usbhid-ups subdriver from
4# the output of
5#
6# drivers/usbhid-ups -DD -u root -x generic -x vendorid=XXXX auto
7#
8# Usage: cat debuginfo | gen-usbhid-subdriver.sh
9#
10# See also: docs/hid-subdrivers.txt
11
12usage() {
13    echo "Usage: $0 [options] [file]"
14    echo "Options:"
15    echo " -h, --help           -- show this message and quit"
16    echo " -n name              -- driver name (use natural capitalization)"
17    echo " -v XXXX              -- vendor id"
18    echo " -p XXXX              -- product id"
19    echo " -k                   -- keep temporary files (for debugging)"
20    echo " file                 -- read from file instead of stdin"
21}
22
23DRIVER=""
24VENDORID=""
25PRODUCTID=""
26KEEP=""
27
28while [ $# -gt 0 ]; do
29    if [ $# -gt 1 -a "$1" = "-n" ]; then
30        DRIVER="$2"
31        shift 2
32    elif [ $# -gt 1 -a "$1" = "-v" ]; then
33        VENDORID="$2"
34        shift 2
35    elif [ $# -gt 1 -a "$1" = "-p" ]; then
36        PRODUCTID="$2"
37        shift 2
38    elif [ "$1" = "-k" ]; then
39        KEEP=yes
40        shift
41    elif echo "$1" | grep -qv '^-'; then
42	FILE="$1"
43	shift
44    elif [ "$1" = "--help" -o "$1" = "-h" ]; then
45        usage
46        exit 0
47    else
48        echo "Illegal option $1. Try --help for more info." >&2
49        exit 1
50    fi
51done
52
53# delete temporary files: this is called just before exiting.
54cleanup () {
55    rm -f "$DEBUG" "$UTABLE" "$USAGES" "$SUBST" "$SEDFILE" "$NEWUTABLE"
56}
57if [ -z "$KEEP" ]; then
58    trap cleanup EXIT
59fi
60
61NAME=gen-usbhid-subdriver
62TMPDIR="${TEMPDIR:-/tmp}"
63DEBUG=`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"`
64UTABLE=`mktemp "$TMPDIR/$NAME-UTABLE.XXXXXX"`
65USAGES=`mktemp "$TMPDIR/$NAME-USAGES.XXXXXX"`
66SUBST=`mktemp "$TMPDIR/$NAME-SUBST.XXXXXX"`
67SEDFILE=`mktemp "$TMPDIR/$NAME-SEDFILE.XXXXXX"`
68NEWUTABLE=`mktemp "$TMPDIR/$NAME-NEWUTABLE.XXXXXX"`
69
70# save standard input to a file
71if [ -z "$FILE" ]; then
72    FILE="$DEBUG"
73    cat > "$DEBUG"
74fi
75
76# prompt use for name of driver
77while [ -z "$DRIVER" ]; do
78    echo "
79Please enter a name for this driver. Use only letters and numbers. Use
80natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'."
81    read -p "Name of subdriver: " DRIVER < /dev/tty
82    if echo $DRIVER | egrep -q '[^a-zA-Z0-9]'; then
83	echo "Please use only letters and digits"
84	DRIVER=""
85    fi
86done
87
88# try to determine product and vendor id
89VENDORID=`cat "$FILE" | sed -n 's/.*- VendorID: \([0-9a-fA-F]*\).*/\1/p' | tail -1`
90PRODUCTID=`cat "$FILE" | sed -n 's/.*- ProductID: \([0-9a-fA-F]*\).*/\1/p' | tail -1`
91
92# prompt for productid, vendorid if necessary
93if [ -z "$VENDORID" ]; then
94    read -p "Vendor ID: " VENDORID < /dev/tty
95fi
96if [ -z "$PRODUCTID" ]; then
97    read -p "Product ID: " PRODUCTID < /dev/tty
98fi
99
100LDRIVER=`echo $DRIVER | tr A-Z a-z`
101UDRIVER=`echo $DRIVER | tr a-z A-Z`
102CFILE="$LDRIVER-hid.c"
103HFILE="$LDRIVER-hid.h"
104
105# extract Usage Table
106cat "$FILE" | sed -n 's/.*Path: \([^,][^,]*\), Type:.*/\1/p' > "$UTABLE"
107
108# extract Usage codes
109cat "$UTABLE" | tr '.' $'\n' | sort -u > "$USAGES"
110
111# make up dummy names for unknown usages
112count=0
113cat "$USAGES" | egrep '[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]' |\
114while read U; do
115    count=`expr $count + 1`
116    echo "$U $UDRIVER$count"
117done > "$SUBST"
118
119# create an sed script for substitutions
120cat "$SUBST" | sed 's/\(.*\) \(.*\)/s!\1!\2!g;/' > "$SEDFILE"
121
122# create modified usage table
123sed -f "$SEDFILE" < "$UTABLE" > "$NEWUTABLE"
124
125# generate header file
126echo "Creating $HFILE"
127cat > "$HFILE" <<EOF
128/* ${HFILE} - subdriver to monitor ${DRIVER} USB/HID devices with NUT
129 *
130 *  Copyright (C)
131 *  2003 - 2009	Arnaud Quette <ArnaudQuette@Eaton.com>
132 *  2005 - 2006	Peter Selinger <selinger@users.sourceforge.net>
133 *  2008 - 2009	Arjen de Korte <adkorte-guest@alioth.debian.org>
134 *
135 *  This program is free software; you can redistribute it and/or modify
136 *  it under the terms of the GNU General Public License as published by
137 *  the Free Software Foundation; either version 2 of the License, or
138 *  (at your option) any later version.
139 *
140 *  This program is distributed in the hope that it will be useful,
141 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
142 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
143 *  GNU General Public License for more details.
144 *
145 *  You should have received a copy of the GNU General Public License
146 *  along with this program; if not, write to the Free Software
147 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
148 */
149
150#ifndef ${UDRIVER}_HID_H
151#define ${UDRIVER}_HID_H
152
153#include "usbhid-ups.h"
154
155extern subdriver_t ${LDRIVER}_subdriver;
156
157#endif /* ${UDRIVER}_HID_H */
158EOF
159
160# generate source file
161echo "Creating $CFILE"
162cat > "$CFILE" <<EOF
163/* ${CFILE} - subdriver to monitor ${DRIVER} USB/HID devices with NUT
164 *
165 *  Copyright (C)
166 *  2003 - 2012	Arnaud Quette <ArnaudQuette@Eaton.com>
167 *  2005 - 2006	Peter Selinger <selinger@users.sourceforge.net>
168 *  2008 - 2009	Arjen de Korte <adkorte-guest@alioth.debian.org>
169 *  2013 Charles Lepple <clepple+nut@gmail.com>
170 *
171 *  TODO: Add year and name for new subdriver author (contributor)
172 *  Mention in docs/acknowledgements.txt if this is a vendor contribution
173 *
174 *  Note: this subdriver was initially generated as a "stub" by the
175 *  gen-usbhid-subdriver script. It must be customized.
176 *
177 *  This program is free software; you can redistribute it and/or modify
178 *  it under the terms of the GNU General Public License as published by
179 *  the Free Software Foundation; either version 2 of the License, or
180 *  (at your option) any later version.
181 *
182 *  This program is distributed in the hope that it will be useful,
183 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
184 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
185 *  GNU General Public License for more details.
186 *
187 *  You should have received a copy of the GNU General Public License
188 *  along with this program; if not, write to the Free Software
189 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
190 */
191
192#include "usbhid-ups.h"
193#include "${HFILE}"
194#include "main.h"	/* for getval() */
195#include "usb-common.h"
196
197#define ${UDRIVER}_HID_VERSION	"${DRIVER} HID 0.1"
198/* FIXME: experimental flag to be put in upsdrv_info */
199
200/* ${DRIVER} */
201#define ${UDRIVER}_VENDORID	0x${VENDORID}
202
203/* USB IDs device table */
204static usb_device_id_t ${LDRIVER}_usb_device_table[] = {
205	/* ${DRIVER} */
206	{ USB_DEVICE(${UDRIVER}_VENDORID, 0x${PRODUCTID}), NULL },
207
208	/* Terminating entry */
209	{ 0, 0, NULL }
210};
211
212
213/* --------------------------------------------------------------- */
214/*      Vendor-specific usage table */
215/* --------------------------------------------------------------- */
216
217/* ${UDRIVER} usage table */
218static usage_lkp_t ${LDRIVER}_usage_lkp[] = {
219EOF
220
221cat "$SUBST" | sed 's/\(.*\) \(.*\)/\t{ "\2",\t0x\1 },/' >> "$CFILE"
222
223cat >> "$CFILE" <<EOF
224	{ NULL, 0 }
225};
226
227static usage_tables_t ${LDRIVER}_utab[] = {
228	${LDRIVER}_usage_lkp,
229	hid_usage_lkp,
230	NULL,
231};
232
233/* --------------------------------------------------------------- */
234/* HID2NUT lookup table                                            */
235/* --------------------------------------------------------------- */
236
237static hid_info_t ${LDRIVER}_hid2nut[] = {
238
239EOF
240
241cat "$NEWUTABLE" | sort -u | while read U; do
242    UL=`echo $U | tr A-Z a-z`
243    cat >> "$CFILE" <<EOF
244	{ "unmapped.${UL}", 0, 0, "${U}", NULL, "%.0f", 0, NULL },
245EOF
246done
247
248cat >> "$CFILE" <<EOF
249
250	/* end of structure. */
251	{ NULL, 0, 0, NULL, NULL, NULL, 0, NULL }
252};
253
254static const char *${LDRIVER}_format_model(HIDDevice_t *hd) {
255	return hd->Product;
256}
257
258static const char *${LDRIVER}_format_mfr(HIDDevice_t *hd) {
259	return hd->Vendor ? hd->Vendor : "${DRIVER}";
260}
261
262static const char *${LDRIVER}_format_serial(HIDDevice_t *hd) {
263	return hd->Serial;
264}
265
266/* this function allows the subdriver to "claim" a device: return 1 if
267 * the device is supported by this subdriver, else 0. */
268static int ${LDRIVER}_claim(HIDDevice_t *hd)
269{
270	int status = is_usb_device_supported(${LDRIVER}_usb_device_table, hd);
271
272	switch (status)
273	{
274	case POSSIBLY_SUPPORTED:
275		/* by default, reject, unless the productid option is given */
276		if (getval("productid")) {
277			return 1;
278		}
279		possibly_supported("${DRIVER}", hd);
280		return 0;
281
282	case SUPPORTED:
283		return 1;
284
285	case NOT_SUPPORTED:
286	default:
287		return 0;
288	}
289}
290
291subdriver_t ${LDRIVER}_subdriver = {
292	${UDRIVER}_HID_VERSION,
293	${LDRIVER}_claim,
294	${LDRIVER}_utab,
295	${LDRIVER}_hid2nut,
296	${LDRIVER}_format_model,
297	${LDRIVER}_format_mfr,
298	${LDRIVER}_format_serial,
299};
300EOF
301
302cat <<EOF
303Done.
304
305Do not forget to:
306* add #include "${HFILE}" to drivers/usbhid-ups.c,
307* add &${LDRIVER}_subdriver to drivers/usbhid-ups.c:subdriver_list,
308* add ${LDRIVER}-hid.c to USBHID_UPS_SUBDRIVERS in drivers/Makefile.am
309* add ${LDRIVER}-hid.h to dist_noinst_HEADERS in drivers/Makefile.am
310* "autoreconf" from the top level directory
311EOF
312