Hi 2021. január 2., szombat 23:30 keltezéssel, Roderick Colenbrander írta: > From: Roderick Colenbrander <roderick.colenbrander@xxxxxxxx> > > Report DualSense battery status information through power_supply class. > > Signed-off-by: Roderick Colenbrander <roderick.colenbrander@xxxxxxxx> > [...] > @@ -21,6 +21,13 @@ > /* Base class for playstation devices. */ > struct ps_device { > struct hid_device *hdev; > + spinlock_t lock; I'm not sure, but isn't a spin_lock_init() missing from the code? > + > + struct power_supply_desc battery_desc; > + struct power_supply *battery; > + uint8_t battery_capacity; > + int battery_status; > + > uint8_t mac_address[6]; > > int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size); > [...] > @@ -136,6 +148,71 @@ static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const ch > return input_dev; > } > > +static enum power_supply_property ps_power_supply_props[] = { > + POWER_SUPPLY_PROP_STATUS, > + POWER_SUPPLY_PROP_PRESENT, > + POWER_SUPPLY_PROP_CAPACITY, > + POWER_SUPPLY_PROP_SCOPE I believe the preferred way is to have a comma after each array/enum/etc. element unless it is a terminating entry. > +}; > [...] > @@ -201,7 +278,9 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r > struct hid_device *hdev = ps_dev->hdev; > struct dualsense *ds = container_of(ps_dev, struct dualsense, base); > struct dualsense_input_report *ds_report; > - uint8_t value; > + uint8_t battery_data, battery_capacity, charging_status, value; > + int battery_status; > + unsigned long flags; > > /* DualSense in USB uses the full HID report for reportID 1, but > * Bluetooth uses a minimal HID report for reportID 1 and reports > @@ -242,12 +321,48 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r > input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME); > input_sync(ds->gamepad); > > + battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY; > + charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT; > + > + switch (charging_status) { > + case 0x0: > + /* Each unit of battery data corresponds to 10% > + * 0 = 0-9%, 1 = 10-19%, .. and 10 = 100% > + */ > + battery_capacity = battery_data == 10 ? 100 : battery_data * 10 + 5; In my opinion `min(battery_data * 10 + 5, 100)` seems cleaner, what do you think? > + battery_status = POWER_SUPPLY_STATUS_DISCHARGING; > + break; > + case 0x1: > + battery_capacity = battery_data == 10 ? 100 : battery_data * 10 + 5; > + battery_status = POWER_SUPPLY_STATUS_CHARGING; > + break; > + case 0x2: > + battery_capacity = 100; > + battery_status = POWER_SUPPLY_STATUS_FULL; > + break; > + case 0xa: /* voltage or temperature out of range */ > + case 0xb: /* temperature error */ > + battery_capacity = 0; > + battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; > + break; > + case 0xf: /* charging error */ > + default: > + battery_capacity = 0; > + battery_status = POWER_SUPPLY_STATUS_UNKNOWN; > + } > + > + spin_lock_irqsave(&ps_dev->lock, flags); > + ps_dev->battery_capacity = battery_capacity; > + ps_dev->battery_status = battery_status; > + spin_unlock_irqrestore(&ps_dev->lock, flags); > + > return 0; > } > > static struct ps_device *dualsense_create(struct hid_device *hdev) > { > struct dualsense *ds; > + struct ps_device *ps_dev; > int ret; > > ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL); > @@ -259,8 +374,11 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) > */ > hdev->version |= HID_PLAYSTATION_VERSION_PATCH; > > - ds->base.hdev = hdev; > - ds->base.parse_report = dualsense_parse_report; > + ps_dev = &ds->base; > + ps_dev->hdev = hdev; > + ps_dev->battery_capacity = 100; /* initial value until parse_report. */ > + ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN; > + ps_dev->parse_report = dualsense_parse_report; > hid_set_drvdata(hdev, ds); > > ret = dualsense_get_mac_address(ds); > @@ -276,6 +394,10 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) > goto err; > } > > + ret = ps_device_register_battery(ps_dev); > + if (ret < 0) I believe if `ps_device_register_battery()` can only return 0 on success or an errno, then `if (ret)` would be better. > + goto err; > + > return &ds->base; > > err: Regards, Barnabás Pőcze