usb-host: Add usb host logic 38/37438/7
authorJiyoung Yun <jy910.yun@samsung.com>
Thu, 26 Mar 2015 12:29:15 +0000 (21:29 +0900)
committerJiyoung Yun <jy910.yun@samsung.com>
Mon, 30 Mar 2015 03:53:18 +0000 (12:53 +0900)
When usb host device is added or removed,
deviced receives the usb uevent and control internal usb host list.

Usb host device must have at least one interface.
And an interface is matched with a specific usb class.

Change-Id: Ib0164daa4b7649820146092f2f04e814f5cef4ca
Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
CMakeLists.txt
src/core/udev.h
src/usb/usb-host.c [new file with mode: 0644]

index 362ff82..08d5d7d 100755 (executable)
@@ -44,6 +44,7 @@ SET(SRCS
 SET(SRCS ${SRCS}
        src/usb/usb.c
        src/usb/usb-default.c
+       src/usb/usb-host.c
 )
 
 IF(TIZEN_BUZZER)
index ab231b4..f867026 100644 (file)
 /* host device */
 #define HOST_SUBSYSTEM         "host_notify"
 
+/* usb */
+#define USB_SUBSYSTEM           "usb"
+#define USB_INTERFACE_DEVTYPE   "usb_interface"
+
 /* power supply status */
 enum {
        POWER_SUPPLY_STATUS_UNKNOWN = 0,
diff --git a/src/usb/usb-host.c b/src/usb/usb-host.c
new file mode 100644 (file)
index 0000000..8831b60
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdio.h>
+#include <limits.h>
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/udev.h"
+#include "core/list.h"
+
+#define USB_INTERFACE_CLASS     "bInterfaceClass"
+#define USB_INTERFACE_SUBCLASS  "bInterfaceSubClass"
+#define USB_INTERFACE_PROTOCOL  "bInterfaceProtocol"
+#define USB_VENDOR_ID           "idVendor"
+#define USB_PRODUCT_ID          "idProduct"
+#define USB_MANUFACTURER        "manufacturer"
+#define USB_PRODUCT             "product"
+#define USB_SERIAL              "serial"
+
+struct usbhost_device {
+       char devpath[PATH_MAX]; /* unique info. */
+       int baseclass;
+       int subclass;
+       int protocol;
+       int vendorid;
+       int productid;
+       char *manufacturer;
+       char *product;
+       char *serial;
+};
+
+static dd_list *usbhost_list;
+
+static void print_usbhost(struct usbhost_device *usbhost)
+{
+       if (!usbhost)
+               return;
+
+       _I("devpath : %s", usbhost->devpath);
+       _I("interface baseclass : %xh", usbhost->baseclass);
+       _I("interface subclass : %xh", usbhost->subclass);
+       _I("interface protocol : %xh", usbhost->protocol);
+       _I("vendor id : %xh", usbhost->vendorid);
+       _I("product id : %xh", usbhost->productid);
+       _I("manufacturer : %s", usbhost->manufacturer);
+       _I("product : %s", usbhost->product);
+       _I("serial : %s", usbhost->serial);
+}
+
+static int add_usbhost_list(struct udev_device *dev, const char *devpath)
+{
+       struct usbhost_device *usbhost;
+       const char *str;
+       struct udev_device *parent;
+
+       /* allocate new usbhost device */
+       usbhost = calloc(1, sizeof(struct usbhost_device));
+       if (!usbhost) {
+               _E("fail to allocate usbhost memory : %s", strerror(errno));
+               return -errno;
+       }
+
+       /* save the devnode */
+       snprintf(usbhost->devpath, sizeof(usbhost->devpath),
+                       "%s", devpath);
+
+       /* get usb interface informations */
+       str = udev_device_get_sysattr_value(dev, USB_INTERFACE_CLASS);
+       if (str)
+               usbhost->baseclass = (int)strtol(str, NULL, 16);
+       str = udev_device_get_sysattr_value(dev, USB_INTERFACE_SUBCLASS);
+       if (str)
+               usbhost->subclass = (int)strtol(str, NULL, 16);
+       str = udev_device_get_sysattr_value(dev, USB_INTERFACE_PROTOCOL);
+       if (str)
+               usbhost->protocol = (int)strtol(str, NULL, 16);
+
+       /* parent has a lot of information about usb_interface */
+       parent = udev_device_get_parent(dev);
+       if (!parent) {
+               _E("fail to get parent");
+               free(usbhost);
+               return -EPERM;
+       }
+
+       /* get usb device informations */
+       str = udev_device_get_sysattr_value(parent, USB_VENDOR_ID);
+       if (str)
+               usbhost->vendorid = (int)strtol(str, NULL, 16);
+       str = udev_device_get_sysattr_value(parent, USB_PRODUCT_ID);
+       if (str)
+               usbhost->productid = (int)strtol(str, NULL, 16);
+       str = udev_device_get_sysattr_value(parent, USB_MANUFACTURER);
+       if (str)
+               usbhost->manufacturer = strdup(str);
+       str = udev_device_get_sysattr_value(parent, USB_PRODUCT);
+       if (str)
+               usbhost->product = strdup(str);
+       str = udev_device_get_sysattr_value(parent, USB_SERIAL);
+       if (str)
+               usbhost->serial = strdup(str);
+
+       DD_LIST_APPEND(usbhost_list, usbhost);
+
+       /* for debugging */
+       _I("USB HOST Added");
+       print_usbhost(usbhost);
+
+       return 0;
+}
+
+static int remove_usbhost_list(const char *devpath)
+{
+       struct usbhost_device *usbhost;
+       dd_list *n, *next;
+
+       /* find the matched item */
+       DD_LIST_FOREACH_SAFE(usbhost_list, n, next, usbhost) {
+               if (!strncmp(usbhost->devpath,
+                                       devpath, sizeof(usbhost->devpath)))
+                       break;
+       }
+
+       if (!usbhost) {
+               _E("fail to find the matched usbhost device");
+               return -ENODEV;
+       }
+
+       /* for debugging */
+       _I("USB HOST Removed");
+       _I("devpath : %s", usbhost->devpath);
+
+       DD_LIST_REMOVE(usbhost_list, usbhost);
+       free(usbhost->manufacturer);
+       free(usbhost->product);
+       free(usbhost->serial);
+       free(usbhost);
+
+       return 0;
+}
+
+static void remove_all_usbhost_list(void)
+{
+       struct usbhost_device *usbhost;
+       dd_list *n, *next;
+
+       DD_LIST_FOREACH_SAFE(usbhost_list, n, next, usbhost) {
+
+               /* for debugging */
+               _I("USB HOST Removed");
+               _I("devpath : %s", usbhost->devpath);
+
+               DD_LIST_REMOVE(usbhost_list, usbhost);
+               free(usbhost->manufacturer);
+               free(usbhost->product);
+               free(usbhost->serial);
+               free(usbhost);
+       }
+}
+
+static void uevent_usbhost_handler(struct udev_device *dev)
+{
+       const char *subsystem;
+       const char *devtype;
+       const char *devpath;
+       const char *action;
+
+       /**
+        * Usb host device must have at least one interface.
+        * An interface is matched with a specific usb class.
+        */
+       subsystem = udev_device_get_subsystem(dev);
+       devtype = udev_device_get_devtype(dev);
+       if (!subsystem || !devtype) {
+               _E("fail to get subsystem or devtype");
+               return;
+       }
+
+       /* devpath is an unique information among usb host devices */
+       devpath = udev_device_get_devpath(dev);
+       if (!devpath) {
+               _E("fail to get devpath from udev_device");
+               return;
+       }
+
+       /**
+        * if devtype is not matched with usb subsystem
+        * and usb_interface devtype, skip.
+        */
+       _I("subsystem : %s, devtype : %s", subsystem, devtype);
+       if (strncmp(subsystem, USB_SUBSYSTEM, sizeof(USB_SUBSYSTEM)) ||
+           strncmp(devtype, USB_INTERFACE_DEVTYPE, sizeof(USB_INTERFACE_DEVTYPE)))
+               return;
+
+       action = udev_device_get_action(dev);
+       if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)))
+               add_usbhost_list(dev, devpath);
+       else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)))
+               remove_usbhost_list(devpath);
+}
+
+static struct uevent_handler uh = {
+       .subsystem = USB_SUBSYSTEM,
+       .uevent_func = uevent_usbhost_handler,
+};
+
+static void usbhost_init(void *data)
+{
+       int ret;
+
+       /* register usbhost uevent */
+       ret = register_kernel_uevent_control(&uh);
+       if (ret < 0)
+               _E("fail to register usb uevent : %d", ret);
+}
+
+static void usbhost_exit(void *data)
+{
+       int ret;
+
+       /* unreigset usbhost uevent */
+       ret = unregister_kernel_uevent_control(&uh);
+       if (ret < 0)
+               _E("fail to unregister usb uevent : %d", ret);
+
+       /* remove all usbhost list */
+       remove_all_usbhost_list();
+}
+
+static const struct device_ops usbhost_device_ops = {
+       .name   = "usbhost",
+       .init   = usbhost_init,
+       .exit   = usbhost_exit,
+};
+
+DEVICE_OPS_REGISTER(&usbhost_device_ops)