123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2016-2023 Samsung Electronics Co. Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- /* usb notify layer v4.0 */
- #define pr_fmt(fmt) "usb_notify: " fmt
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/err.h>
- #include <linux/usb.h>
- #include <linux/usb_notify.h>
- struct external_notify_struct {
- struct blocking_notifier_head notifier_call_chain;
- int call_chain_init;
- };
- #define SET_EXTERNAL_NOTIFY_BLOCK(nb, fn, dev) do { \
- (nb)->notifier_call = (fn); \
- (nb)->priority = (dev); \
- } while (0)
- #define DESTROY_EXTERNAL_NOTIFY_BLOCK(nb) \
- SET_EXTERNAL_NOTIFY_BLOCK(nb, NULL, -1)
- static struct external_notify_struct external_notifier;
- static const char *cmd_string(unsigned long cmd)
- {
- switch (cmd) {
- case EXTERNAL_NOTIFY_3S_NODEVICE:
- return "3s_no_device";
- case EXTERNAL_NOTIFY_DEVICE_CONNECT:
- return "device_connect";
- case EXTERNAL_NOTIFY_HOSTBLOCK_PRE:
- return "host_block_pre";
- case EXTERNAL_NOTIFY_HOSTBLOCK_POST:
- return "host_block_post";
- case EXTERNAL_NOTIFY_MDMBLOCK_PRE:
- return "mdm_block_pre";
- case EXTERNAL_NOTIFY_MDMBLOCK_POST:
- return "mdm_block_post";
- case EXTERNAL_NOTIFY_POWERROLE:
- return "power_role_notify";
- case EXTERNAL_NOTIFY_DEVICEADD:
- return "host_mode_device_added";
- case EXTERNAL_NOTIFY_HOSTBLOCK_EARLY:
- return "host_block_pre_fast";
- case EXTERNAL_NOTIFY_VBUS_RESET:
- return "vbus_reset";
- case EXTERNAL_NOTIFY_POSSIBLE_USB:
- return "possible_usb";
- default:
- return "undefined";
- }
- }
- static const char *listener_string(int listener)
- {
- switch (listener) {
- case EXTERNAL_NOTIFY_DEV_MUIC:
- return "muic";
- case EXTERNAL_NOTIFY_DEV_CHARGER:
- return "charger";
- case EXTERNAL_NOTIFY_DEV_PDIC:
- return "pdic";
- case EXTERNAL_NOTIFY_DEV_MANAGER:
- return "manager";
- default:
- return "undefined";
- }
- }
- static int create_external_notify(void)
- {
- if (!external_notifier.call_chain_init) {
- unl_info("%s\n", __func__);
- BLOCKING_INIT_NOTIFIER_HEAD
- (&(external_notifier.notifier_call_chain));
- external_notifier.call_chain_init = 1;
- }
- return 0;
- }
- int usb_external_notify_register(struct notifier_block *nb,
- notifier_fn_t notifier, int listener)
- {
- int ret = 0;
- unl_info("%s: listener=(%s)%d register\n", __func__,
- listener_string(listener), listener);
- create_external_notify();
- SET_EXTERNAL_NOTIFY_BLOCK(nb, notifier, listener);
- ret = blocking_notifier_chain_register
- (&(external_notifier.notifier_call_chain), nb);
- if (ret < 0)
- unl_err("%s: blocking_notifier_chain_register error(%d)\n",
- __func__, ret);
- return ret;
- }
- EXPORT_SYMBOL(usb_external_notify_register);
- int usb_external_notify_unregister(struct notifier_block *nb)
- {
- int ret = 0;
- unl_info("%s: listener=(%s)%d unregister\n", __func__,
- listener_string(nb->priority),
- nb->priority);
- ret = blocking_notifier_chain_unregister
- (&(external_notifier.notifier_call_chain), nb);
- if (ret < 0)
- unl_err("%s: blocking_notifier_chain_unregister error(%d)\n",
- __func__, ret);
- DESTROY_EXTERNAL_NOTIFY_BLOCK(nb);
- return ret;
- }
- EXPORT_SYMBOL(usb_external_notify_unregister);
- int send_external_notify(unsigned long cmd, int data)
- {
- int ret = 0;
- unl_info("%s: cmd=%s(%lu), data=%d\n", __func__, cmd_string(cmd),
- cmd, data);
- create_external_notify();
- ret = blocking_notifier_call_chain
- (&(external_notifier.notifier_call_chain),
- cmd, (void *)&(data));
- switch (ret) {
- case NOTIFY_STOP_MASK:
- case NOTIFY_BAD:
- unl_err("%s: notify error occur(0x%x)\n", __func__, ret);
- break;
- case NOTIFY_DONE:
- case NOTIFY_OK:
- unl_info("%s: notify done(0x%x)\n", __func__, ret);
- break;
- default:
- unl_info("%s: notify status unknown(0x%x)\n", __func__, ret);
- break;
- }
- return ret;
- }
- EXPORT_SYMBOL(send_external_notify);
- void external_notifier_init(void)
- {
- unl_info("%s\n", __func__);
- create_external_notify();
- }
- EXPORT_SYMBOL(external_notifier_init);
|