+struct wacom_usbdev_data {
+ struct list_head list;
+ struct kref kref;
+ struct usb_device *dev;
+ struct wacom_shared shared;
+};
+
+static LIST_HEAD(wacom_udev_list);
+static DEFINE_MUTEX(wacom_udev_list_lock);
+
+static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
+{
+ struct wacom_usbdev_data *data;
+
+ list_for_each_entry(data, &wacom_udev_list, list) {
+ if (data->dev == dev) {
+ kref_get(&data->kref);
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+static int wacom_add_shared_data(struct wacom_wac *wacom,
+ struct usb_device *dev)
+{
+ struct wacom_usbdev_data *data;
+ int retval = 0;
+
+ mutex_lock(&wacom_udev_list_lock);
+
+ data = wacom_get_usbdev_data(dev);
+ if (!data) {
+ data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL);
+ if (!data) {
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ kref_init(&data->kref);
+ data->dev = dev;
+ list_add_tail(&data->list, &wacom_udev_list);
+ }
+
+ wacom->shared = &data->shared;
+
+out:
+ mutex_unlock(&wacom_udev_list_lock);
+ return retval;
+}
+
+static void wacom_release_shared_data(struct kref *kref)
+{
+ struct wacom_usbdev_data *data =
+ container_of(kref, struct wacom_usbdev_data, kref);
+
+ mutex_lock(&wacom_udev_list_lock);
+ list_del(&data->list);
+ mutex_unlock(&wacom_udev_list_lock);
+
+ kfree(data);
+}
+
+static void wacom_remove_shared_data(struct wacom_wac *wacom)
+{
+ struct wacom_usbdev_data *data;
+
+ if (wacom->shared) {
+ data = container_of(wacom->shared, struct wacom_usbdev_data, shared);
+ kref_put(&data->kref, wacom_release_shared_data);
+ wacom->shared = NULL;
+ }
+}
+