ChangeSet 1.859, 2002/11/14 13:57:34-08:00, david-b@pacbell.net

[PATCH] HID patches for MGE UPS

I thought I'd send the results of some experimentation of mine getting
an MGE UPS (Evolution) to talk to 2.5 ... basically it behaved after
some patches, though the "hidups" driver didn't.  They're all attached:

   - "hiddev-1.patch"  ... The default queue size was so small that this
     low-speed device couldn't queue up about 110 control requests
     (that many reports to check!) during init.

   - "hiddev-2.patch" ... Makes hid debug output more useful by
      (a) making it compile again;
      (b) adding lots of "Power Device" and "Battery System" reports,
          and putting all that data into the readonly data section;
      (c) actually printing the usage strings, if they're known;
      (d) printing a message when neither input nor hiddev claim
          the device ... likely something's wrong, like someone
          didn't configure in input subsystem or hiddev support.

   - "hiddev-3.patch" ... Teaches hiddev to expose the physical ID
     just like the input event framework does.  Useful to help sort
     out which UPS is which, so you won't power down the wrong set
     of servers by accident.


diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Thu Nov 14 14:11:53 2002
+++ b/drivers/usb/input/hid-core.c	Thu Nov 14 14:11:53 2002
@@ -1572,7 +1572,8 @@
 	int i;
 	char *c;
 
-	dbg("HID probe called for ifnum %d", intf->ifnum);
+	dbg("HID probe called for ifnum %d",
+			intf->altsetting->desc.bInterfaceNumber);
 
 	if (!(hid = usb_hid_configure(intf)))
 		return -EIO;
@@ -1590,6 +1591,7 @@
 	dev_set_drvdata(&intf->dev, hid);
 
 	if (!hid->claimed) {
+		printk ("HID device not claimed by input or hiddev\n");
 		hid_disconnect(intf);
 		return -EIO;
 	}
diff -Nru a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h	Thu Nov 14 14:11:53 2002
+++ b/drivers/usb/input/hid-debug.h	Thu Nov 14 14:11:53 2002
@@ -33,7 +33,7 @@
 	char     *description;
 };
 
-static struct hid_usage_entry hid_usage_table[] = {
+static const struct hid_usage_entry hid_usage_table[] = {
   {  0,      0, "Undefined" },
   {  1,      0, "GenericDesktop" },
     {0, 0x01, "Pointer"},
@@ -218,11 +218,95 @@
     {0, 0xAA, "Shared_Parameter_Blocks"},
     {0, 0xAB, "Create_New_Effect_Report"},
     {0, 0xAC, "RAM_Pool_Available"},
+  { 0x84, 0, "Power Device" },
+    { 0x84, 0x02, "PresentStatus" },
+    { 0x84, 0x03, "ChangeStatus" },
+    { 0x84, 0x04, "UPS" },
+    { 0x84, 0x05, "PowerSupply" },
+    { 0x84, 0x10, "BatterySystem" },
+    { 0x84, 0x11, "BatterySystemID" },
+    { 0x84, 0x12, "Battery" },
+    { 0x84, 0x13, "BatteryID" },
+    { 0x84, 0x14, "Charger" },
+    { 0x84, 0x15, "ChargerID" },
+    { 0x84, 0x16, "PowerConverter" },
+    { 0x84, 0x17, "PowerConverterID" },
+    { 0x84, 0x18, "OutletSystem" },
+    { 0x84, 0x19, "OutletSystemID" },
+    { 0x84, 0x1a, "Input" },
+    { 0x84, 0x1b, "InputID" },
+    { 0x84, 0x1c, "Output" },
+    { 0x84, 0x1d, "OutputID" },
+    { 0x84, 0x1e, "Flow" },
+    { 0x84, 0x1f, "FlowID" },
+    { 0x84, 0x20, "Outlet" },
+    { 0x84, 0x21, "OutletID" },
+    { 0x84, 0x22, "Gang" },
+    { 0x84, 0x24, "PowerSummary" },
+    { 0x84, 0x25, "PowerSummaryID" },
+    { 0x84, 0x30, "Voltage" },
+    { 0x84, 0x31, "Current" },
+    { 0x84, 0x32, "Frequency" },
+    { 0x84, 0x33, "ApparentPower" },
+    { 0x84, 0x35, "PercentLoad" },
+    { 0x84, 0x40, "ConfigVoltage" },
+    { 0x84, 0x41, "ConfigCurrent" },
+    { 0x84, 0x43, "ConfigApparentPower" },
+    { 0x84, 0x53, "LowVoltageTransfer" },
+    { 0x84, 0x54, "HighVoltageTransfer" },
+    { 0x84, 0x56, "DelayBeforeStartup" },
+    { 0x84, 0x57, "DelayBeforeShutdown" },
+    { 0x84, 0x58, "Test" },
+    { 0x84, 0x5a, "AudibleAlarmControl" },
+    { 0x84, 0x60, "Present" },
+    { 0x84, 0x61, "Good" },
+    { 0x84, 0x62, "InternalFailure" },
+    { 0x84, 0x65, "Overload" },
+    { 0x84, 0x66, "OverCharged" },
+    { 0x84, 0x67, "OverTemperature" },
+    { 0x84, 0x68, "ShutdownRequested" },
+    { 0x84, 0x69, "ShutdownImminent" },
+    { 0x84, 0x6b, "SwitchOn/Off" },
+    { 0x84, 0x6c, "Switchable" },
+    { 0x84, 0x6d, "Used" },
+    { 0x84, 0x6e, "Boost" },
+    { 0x84, 0x73, "CommunicationLost" },
+    { 0x84, 0xfd, "iManufacturer" },
+    { 0x84, 0xfe, "iProduct" },
+    { 0x84, 0xff, "iSerialNumber" },
+  { 0x85, 0, "Battery System" },
+    { 0x85, 0x01, "SMBBatteryMode" },
+    { 0x85, 0x02, "SMBBatteryStatus" },
+    { 0x85, 0x03, "SMBAlarmWarning" },
+    { 0x85, 0x04, "SMBChargerMode" },
+    { 0x85, 0x05, "SMBChargerStatus" },
+    { 0x85, 0x06, "SMBChargerSpecInfo" },
+    { 0x85, 0x07, "SMBSelectorState" },
+    { 0x85, 0x08, "SMBSelectorPresets" },
+    { 0x85, 0x09, "SMBSelectorInfo" },
+    { 0x85, 0x29, "RemainingCapacityLimit" },
+    { 0x85, 0x2c, "CapacityMode" },
+    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+    { 0x85, 0x44, "Charging" },
+    { 0x85, 0x45, "Discharging" },
+    { 0x85, 0x4b, "NeedReplacement" },
+    { 0x85, 0x66, "RemainingCapacity" },
+    { 0x85, 0x68, "RunTimeToEmpty" },
+    { 0x85, 0x6a, "AverageTimeToFull" },
+    { 0x85, 0x83, "DesignCapacity" },
+    { 0x85, 0x85, "ManufacturerDate" },
+    { 0x85, 0x89, "iDeviceChemistry" },
+    { 0x85, 0x8b, "Rechargable" },
+    { 0x85, 0x8f, "iOEMInformation" },
+    { 0x85, 0x8d, "CapacityGranularity1" },
+    { 0x85, 0xd0, "ACPresent" },
+  /* pages 0xff00 to 0xffff are vendor-specific */
+  { 0xffff, 0, "Vendor-specific-FF" },
   { 0, 0, NULL }
 };
 
 static void resolv_usage_page(unsigned page) {
-	struct hid_usage_entry *p;
+	const struct hid_usage_entry *p;
 
 	for (p = hid_usage_table; p->description; p++)
 		if (p->page == page) {
@@ -233,13 +317,13 @@
 }
 
 static void resolv_usage(unsigned usage) {
-	struct hid_usage_entry *p;
+	const struct hid_usage_entry *p;
 
 	resolv_usage_page(usage >> 16);
 	printk(".");
 	for (p = hid_usage_table; p->description; p++)
 		if (p->page == (usage >> 16)) {
-			for(++p; p->description && p->page == 0; p++)
+			for(++p; p->description && p->page != 0; p++)
 				if (p->usage == (usage & 0xffff)) {
 					printk("%s", p->description);
 					return;
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	Thu Nov 14 14:11:53 2002
+++ b/drivers/usb/input/hid.h	Thu Nov 14 14:11:53 2002
@@ -306,7 +306,7 @@
 #define HID_REPORT_TYPES 3
 
 #define HID_BUFFER_SIZE		32
-#define HID_CONTROL_FIFO_SIZE	64
+#define HID_CONTROL_FIFO_SIZE	256		/* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE	64
 
 struct hid_control_fifo {
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Thu Nov 14 14:11:53 2002
+++ b/drivers/usb/input/hiddev.c	Thu Nov 14 14:11:53 2002
@@ -652,6 +652,15 @@
 			return copy_to_user((char *) arg, hid->name, len) ?
 				-EFAULT : len;
 		}
+
+		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
+			int len;
+			if (!hid->phys) return 0;
+			len = strlen(hid->phys) + 1;
+			if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+			return copy_to_user((char *) arg, hid->phys, len) ?
+				-EFAULT : len;
+		}
 	}
 	return -EINVAL;
 }
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h	Thu Nov 14 14:11:53 2002
+++ b/include/linux/hiddev.h	Thu Nov 14 14:11:53 2002
@@ -159,6 +159,7 @@
 #define HIDIOCSFLAG		_IOW('H', 0x0F, int)
 #define HIDIOCGCOLLECTIONINDEX	_IOW('H', 0x10, struct hiddev_usage_ref)
 #define HIDIOCGCOLLECTIONINFO	_IOWR('H', 0x11, struct hiddev_collection_info)
+#define HIDIOCGPHYS(len)	_IOC(_IOC_READ, 'H', 0x12, len)
 
 /* 
  * Flags to be used in HIDIOCSFLAG
