Re: [PATCH 1/6] HID: hid-playstation: Allow removal of touchpad

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

On 5/5/22 01:50, Benjamin Tissoires wrote:
> Hi Vicki,
> 
> On Thu, Apr 28, 2022 at 12:52 AM Vicki Pfau <vi@xxxxxxxxxxx> wrote:
>>
>> This allows the touchpad input_dev to be removed and have the driver remain
>> functional without its presence. This will be used to allow the touchpad to
>> be disabled, e.g. by a module parameter.
> 
> Thanks for the contribution.
> I'd like to hear from Roderick, but I have a general comment here:
> We had Wii and Steam controllers following this logic. Now we are
> adding Sony PS ones... That seems like a lot of duplication, and I
> wonder if we should not have something more generic.
> 
> We are working on an ioctl to revoke hidraw nodes and I wonder if we
> should not take this opportunity to have a more generic mechanism in
> HID to also disable input events when the hidraw node is opened...

I would much rather that. I (attempted) to start a discussion on this a few weeks ago (https://lore.kernel.org/linux-input/b5f229c3-26e5-4fe1-aecb-504aa3c38bee@xxxxxxxxxxx/T/) but no one replied, so I went ahead and implemented what I assumed would be a substandard implementation, if at the very least so my sponsor would be happy, and as an attempt to start the conversation again.

> 
> One comment on the code itself below.
> 
>>
>> Signed-off-by: Vicki Pfau <vi@xxxxxxxxxxx>
>> ---
>>  drivers/hid/hid-playstation.c | 60 +++++++++++++++++++++++++----------
>>  1 file changed, 43 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
>> index ab7c82c2e886..f859a8dd8a2e 100644
>> --- a/drivers/hid/hid-playstation.c
>> +++ b/drivers/hid/hid-playstation.c
>> @@ -29,6 +29,7 @@ static DEFINE_IDA(ps_player_id_allocator);
>>  struct ps_device {
>>         struct list_head list;
>>         struct hid_device *hdev;
>> +       struct mutex mutex;
>>         spinlock_t lock;
>>
>>         uint32_t player_id;
>> @@ -130,7 +131,7 @@ struct dualsense {
>>         struct ps_device base;
>>         struct input_dev *gamepad;
>>         struct input_dev *sensors;
>> -       struct input_dev *touchpad;
>> +       struct input_dev __rcu *touchpad;
>>
>>         /* Calibration data for accelerometer and gyroscope. */
>>         struct ps_calibration_data accel_calib_data[3];
>> @@ -590,6 +591,22 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width,
>>         return touchpad;
>>  }
>>
>> +static void dualsense_unregister_touchpad(struct dualsense *ds)
>> +{
>> +       struct input_dev *touchpad;
>> +
>> +       rcu_read_lock();
>> +       touchpad = rcu_dereference(ds->touchpad);
>> +       rcu_read_unlock();
>> +
>> +       if (!touchpad)
>> +               return;
>> +
>> +       RCU_INIT_POINTER(ds->touchpad, NULL);
>> +       synchronize_rcu();
>> +       input_unregister_device(touchpad);
>> +}
>> +
>>  static ssize_t firmware_version_show(struct device *dev,
>>                                 struct device_attribute
>>                                 *attr, char *buf)
>> @@ -888,6 +905,7 @@ 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;
>> +       struct input_dev *touchpad = NULL;
>>         uint8_t battery_data, battery_capacity, charging_status, value;
>>         int battery_status;
>>         uint32_t sensor_timestamp;
>> @@ -1002,24 +1020,29 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
>>         input_event(ds->sensors, EV_MSC, MSC_TIMESTAMP, ds->sensor_timestamp_us);
>>         input_sync(ds->sensors);
>>
>> -       for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) {
>> -               struct dualsense_touch_point *point = &ds_report->points[i];
>> -               bool active = (point->contact & DS_TOUCH_POINT_INACTIVE) ? false : true;
>> +       rcu_read_lock();
>> +       touchpad = rcu_dereference(ds->touchpad);
>> +       rcu_read_unlock();
>> +       if (touchpad) {
> 
> Access to touchpad should probably be guarded under RCU (that's what I
> understand when I read
> https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html#rcu-dereference)

Ah, I'm new to this so I overlooked that. I'll fix this in a v2, if it's even worth having a v2 given that, as I said, I would really rather not have implemented it this way in the first place.

> 
>> +               for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) {
>> +                       struct dualsense_touch_point *point = &ds_report->points[i];
>> +                       bool active = (point->contact & DS_TOUCH_POINT_INACTIVE) ? false : true;
>>
>> -               input_mt_slot(ds->touchpad, i);
>> -               input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active);
>> +                       input_mt_slot(ds->touchpad, i);
>> +                       input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active);
>>
>> -               if (active) {
>> -                       int x = (point->x_hi << 8) | point->x_lo;
>> -                       int y = (point->y_hi << 4) | point->y_lo;
>> +                       if (active) {
>> +                               int x = (point->x_hi << 8) | point->x_lo;
>> +                               int y = (point->y_hi << 4) | point->y_lo;
>>
>> -                       input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x);
>> -                       input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y);
>> +                               input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x);
>> +                               input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y);
>> +                       }
>>                 }
>> +               input_mt_sync_frame(ds->touchpad);
>> +               input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD);
>> +               input_sync(ds->touchpad);
>>         }
>> -       input_mt_sync_frame(ds->touchpad);
>> -       input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD);
>> -       input_sync(ds->touchpad);
>>
>>         battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY;
>>         charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT;
>> @@ -1141,6 +1164,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
>>  {
>>         struct dualsense *ds;
>>         struct ps_device *ps_dev;
>> +       struct input_dev *touchpad;
>>         uint8_t max_output_report_size;
>>         int ret;
>>
>> @@ -1157,6 +1181,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
>>         ps_dev = &ds->base;
>>         ps_dev->hdev = hdev;
>>         spin_lock_init(&ps_dev->lock);
>> +       mutex_init(&ps_dev->mutex);
> 
> This mutex is never used.

The mutex is used in both patch 2 and 3, so I put it here in case either 2 or 3 is rejected, but not the other.

> 
> Cheers,
> Benjamin
> 
>>         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;
>> @@ -1204,11 +1229,12 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
>>                 goto err;
>>         }
>>
>> -       ds->touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2);
>> -       if (IS_ERR(ds->touchpad)) {
>> -               ret = PTR_ERR(ds->touchpad);
>> +       touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2);
>> +       if (IS_ERR(touchpad)) {
>> +               ret = PTR_ERR(touchpad);
>>                 goto err;
>>         }
>> +       rcu_assign_pointer(ds->touchpad, touchpad);
>>
>>         ret = ps_device_register_battery(ps_dev);
>>         if (ret)
>> --
>> 2.36.0
>>
> 

Thanks,
Vicki



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux