⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dock.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * register_dock_notifier - add yourself to the dock notifier list * @nb: the callers notifier block * * If a driver wishes to be notified about dock events, they can * use this function to put a notifier block on the dock notifier list. * this notifier call chain will be called after a dock event, but * before hotplugging any new devices. */int register_dock_notifier(struct notifier_block *nb){	if (!dock_station)		return -ENODEV;	return atomic_notifier_chain_register(&dock_notifier_list, nb);}EXPORT_SYMBOL_GPL(register_dock_notifier);/** * unregister_dock_notifier - remove yourself from the dock notifier list * @nb: the callers notifier block */void unregister_dock_notifier(struct notifier_block *nb){	if (!dock_station)		return;	atomic_notifier_chain_unregister(&dock_notifier_list, nb);}EXPORT_SYMBOL_GPL(unregister_dock_notifier);/** * register_hotplug_dock_device - register a hotplug function * @handle: the handle of the device * @handler: the acpi_notifier_handler to call after docking * @context: device specific data * * If a driver would like to perform a hotplug operation after a dock * event, they can register an acpi_notifiy_handler to be called by * the dock driver after _DCK is executed. */intregister_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,			     void *context){	struct dock_dependent_device *dd;	if (!dock_station)		return -ENODEV;	/*	 * make sure this handle is for a device dependent on the dock,	 * this would include the dock station itself	 */	dd = find_dock_dependent_device(dock_station, handle);	if (dd) {		dd->handler = handler;		dd->context = context;		dock_add_hotplug_device(dock_station, dd);		return 0;	}	return -EINVAL;}EXPORT_SYMBOL_GPL(register_hotplug_dock_device);/** * unregister_hotplug_dock_device - remove yourself from the hotplug list * @handle: the acpi handle of the device */void unregister_hotplug_dock_device(acpi_handle handle){	struct dock_dependent_device *dd;	if (!dock_station)		return;	dd = find_dock_dependent_device(dock_station, handle);	if (dd)		dock_del_hotplug_device(dock_station, dd);}EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);/** * handle_eject_request - handle an undock request checking for error conditions * * Check to make sure the dock device is still present, then undock and * hotremove all the devices that may need removing. */static int handle_eject_request(struct dock_station *ds, u32 event){	if (!dock_present(ds))		return -ENODEV;	if (dock_in_progress(ds))		return -EBUSY;	/*	 * here we need to generate the undock	 * event prior to actually doing the undock	 * so that the device struct still exists.	 */	dock_event(ds, event, UNDOCK_EVENT);	hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);	undock(ds);	eject_dock(ds);	if (dock_present(ds)) {		printk(KERN_ERR PREFIX "Unable to undock!\n");		return -EBUSY;	}	complete_undock(ds);	return 0;}/** * dock_notify - act upon an acpi dock notification * @handle: the dock station handle * @event: the acpi event * @data: our driver data struct * * If we are notified to dock, then check to see if the dock is * present and then dock.  Notify all drivers of the dock event, * and then hotplug and devices that may need hotplugging. */static void dock_notify(acpi_handle handle, u32 event, void *data){	struct dock_station *ds = data;	switch (event) {	case ACPI_NOTIFY_BUS_CHECK:		if (!dock_in_progress(ds) && dock_present(ds)) {			begin_dock(ds);			dock(ds);			if (!dock_present(ds)) {				printk(KERN_ERR PREFIX "Unable to dock!\n");				break;			}			atomic_notifier_call_chain(&dock_notifier_list,						   event, NULL);			hotplug_dock_devices(ds, event);			complete_dock(ds);			dock_event(ds, event, DOCK_EVENT);		}		break;	case ACPI_NOTIFY_DEVICE_CHECK:	/*         * According to acpi spec 3.0a, if a DEVICE_CHECK notification         * is sent and _DCK is present, it is assumed to mean an         * undock request.  This notify routine will only be called         * for objects defining _DCK, so we will fall through to eject         * request here.  However, we will pass an eject request through	 * to the driver who wish to hotplug.         */	case ACPI_NOTIFY_EJECT_REQUEST:		begin_undock(ds);		if (immediate_undock)			handle_eject_request(ds, event);		else			dock_event(ds, event, UNDOCK_EVENT);		break;	default:		printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);	}}/** * find_dock_devices - find devices on the dock station * @handle: the handle of the device we are examining * @lvl: unused * @context: the dock station private data * @rv: unused * * This function is called by acpi_walk_namespace.  It will * check to see if an object has an _EJD method.  If it does, then it * will see if it is dependent on the dock station. */static acpi_statusfind_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv){	acpi_status status;	acpi_handle tmp, parent;	struct dock_station *ds = context;	struct dock_dependent_device *dd;	status = acpi_bus_get_ejd(handle, &tmp);	if (ACPI_FAILURE(status)) {		/* try the parent device as well */		status = acpi_get_parent(handle, &parent);		if (ACPI_FAILURE(status))			goto fdd_out;		/* see if parent is dependent on dock */		status = acpi_bus_get_ejd(parent, &tmp);		if (ACPI_FAILURE(status))			goto fdd_out;	}	if (tmp == ds->handle) {		dd = alloc_dock_dependent_device(handle);		if (dd)			add_dock_dependent_device(ds, dd);	}fdd_out:	return AE_OK;}/* * show_docked - read method for "docked" file in sysfs */static ssize_t show_docked(struct device *dev,			   struct device_attribute *attr, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));}DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);/* * show_flags - read method for flags file in sysfs */static ssize_t show_flags(struct device *dev,			  struct device_attribute *attr, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);}DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);/* * write_undock - write method for "undock" file in sysfs */static ssize_t write_undock(struct device *dev, struct device_attribute *attr,			   const char *buf, size_t count){	int ret;	if (!count)		return -EINVAL;	ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);	return ret ? ret: count;}DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);/* * show_dock_uid - read method for "uid" file in sysfs */static ssize_t show_dock_uid(struct device *dev,			     struct device_attribute *attr, char *buf){	unsigned long lbuf;	acpi_status status = acpi_evaluate_integer(dock_station->handle,					"_UID", NULL, &lbuf);	if (ACPI_FAILURE(status))	    return 0;	return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);}DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);/** * dock_add - add a new dock station * @handle: the dock station handle * * allocated and initialize a new dock station device.  Find all devices * that are on the dock station, and register for dock event notifications. */static int dock_add(acpi_handle handle){	int ret;	acpi_status status;	struct dock_dependent_device *dd;	/* allocate & initialize the dock_station private data */	dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);	if (!dock_station)		return -ENOMEM;	dock_station->handle = handle;	dock_station->last_dock_time = jiffies - HZ;	INIT_LIST_HEAD(&dock_station->dependent_devices);	INIT_LIST_HEAD(&dock_station->hotplug_devices);	spin_lock_init(&dock_station->dd_lock);	mutex_init(&dock_station->hp_lock);	ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);	/* initialize platform device stuff */	dock_device =		platform_device_register_simple(dock_device_name, 0, NULL, 0);	if (IS_ERR(dock_device)) {		kfree(dock_station);		dock_station = NULL;		return PTR_ERR(dock_device);	}	/* we want the dock device to send uevents */	dock_device->dev.uevent_suppress = 0;	ret = device_create_file(&dock_device->dev, &dev_attr_docked);	if (ret) {		printk("Error %d adding sysfs file\n", ret);		platform_device_unregister(dock_device);		kfree(dock_station);		dock_station = NULL;		return ret;	}	ret = device_create_file(&dock_device->dev, &dev_attr_undock);	if (ret) {		printk("Error %d adding sysfs file\n", ret);		device_remove_file(&dock_device->dev, &dev_attr_docked);		platform_device_unregister(dock_device);		kfree(dock_station);		dock_station = NULL;		return ret;	}	ret = device_create_file(&dock_device->dev, &dev_attr_uid);	if (ret) {		printk("Error %d adding sysfs file\n", ret);		device_remove_file(&dock_device->dev, &dev_attr_docked);		device_remove_file(&dock_device->dev, &dev_attr_undock);		platform_device_unregister(dock_device);		kfree(dock_station);		dock_station = NULL;		return ret;	}	ret = device_create_file(&dock_device->dev, &dev_attr_flags);	if (ret) {		printk("Error %d adding sysfs file\n", ret);		device_remove_file(&dock_device->dev, &dev_attr_docked);		device_remove_file(&dock_device->dev, &dev_attr_undock);		device_remove_file(&dock_device->dev, &dev_attr_uid);		platform_device_unregister(dock_device);		kfree(dock_station);		dock_station = NULL;		return ret;	}	/* Find dependent devices */	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,			    ACPI_UINT32_MAX, find_dock_devices, dock_station,			    NULL);	/* add the dock station as a device dependent on itself */	dd = alloc_dock_dependent_device(handle);	if (!dd) {		kfree(dock_station);		dock_station = NULL;		ret = -ENOMEM;		goto dock_add_err_unregister;	}	add_dock_dependent_device(dock_station, dd);	/* register for dock events */	status = acpi_install_notify_handler(dock_station->handle,					     ACPI_SYSTEM_NOTIFY,					     dock_notify, dock_station);	if (ACPI_FAILURE(status)) {		printk(KERN_ERR PREFIX "Error installing notify handler\n");		ret = -ENODEV;		goto dock_add_err;	}	printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION);	return 0;dock_add_err:	kfree(dd);dock_add_err_unregister:	device_remove_file(&dock_device->dev, &dev_attr_docked);	device_remove_file(&dock_device->dev, &dev_attr_undock);	device_remove_file(&dock_device->dev, &dev_attr_uid);	device_remove_file(&dock_device->dev, &dev_attr_flags);	platform_device_unregister(dock_device);	kfree(dock_station);	dock_station = NULL;	return ret;}/** * dock_remove - free up resources related to the dock station */static int dock_remove(void){	struct dock_dependent_device *dd, *tmp;	acpi_status status;	if (!dock_station)		return 0;	/* remove dependent devices */	list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,				 list)	    kfree(dd);	/* remove dock notify handler */	status = acpi_remove_notify_handler(dock_station->handle,					    ACPI_SYSTEM_NOTIFY,					    dock_notify);	if (ACPI_FAILURE(status))		printk(KERN_ERR "Error removing notify handler\n");	/* cleanup sysfs */	device_remove_file(&dock_device->dev, &dev_attr_docked);	device_remove_file(&dock_device->dev, &dev_attr_undock);	device_remove_file(&dock_device->dev, &dev_attr_uid);	device_remove_file(&dock_device->dev, &dev_attr_flags);	platform_device_unregister(dock_device);	/* free dock station memory */	kfree(dock_station);	dock_station = NULL;	return 0;}/** * find_dock - look for a dock station * @handle: acpi handle of a device * @lvl: unused * @context: counter of dock stations found * @rv: unused * * This is called by acpi_walk_namespace to look for dock stations. */static acpi_statusfind_dock(acpi_handle handle, u32 lvl, void *context, void **rv){	int *count = context;	acpi_status status = AE_OK;	if (is_dock(handle)) {		if (dock_add(handle) >= 0) {			(*count)++;			status = AE_CTRL_TERMINATE;		}	}	return status;}static int __init dock_init(void){	int num = 0;	dock_station = NULL;	/* look for a dock station */	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,			    ACPI_UINT32_MAX, find_dock, &num, NULL);	if (!num)		printk(KERN_INFO "No dock devices found.\n");	return 0;}static void __exit dock_exit(void){	dock_remove();}postcore_initcall(dock_init);module_exit(dock_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -