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

📄 ap_bus.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	return 0;}/** * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */static int ap_uevent (struct device *dev, struct kobj_uevent_env *env){	struct ap_device *ap_dev = to_ap_dev(dev);	int retval = 0;	if (!ap_dev)		return -ENODEV;	/* Set up DEV_TYPE environment variable. */	retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);	if (retval)		return retval;	/* Add MODALIAS= */	retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);	return retval;}static struct bus_type ap_bus_type = {	.name = "ap",	.match = &ap_bus_match,	.uevent = &ap_uevent,};static int ap_device_probe(struct device *dev){	struct ap_device *ap_dev = to_ap_dev(dev);	struct ap_driver *ap_drv = to_ap_drv(dev->driver);	int rc;	ap_dev->drv = ap_drv;	spin_lock_bh(&ap_device_lock);	list_add(&ap_dev->list, &ap_device_list);	spin_unlock_bh(&ap_device_lock);	rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;	return rc;}/** * Flush all requests from the request/pending queue of an AP device. * @ap_dev: pointer to the AP device. */static void __ap_flush_queue(struct ap_device *ap_dev){	struct ap_message *ap_msg, *next;	list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {		list_del_init(&ap_msg->list);		ap_dev->pendingq_count--;		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));	}	list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {		list_del_init(&ap_msg->list);		ap_dev->requestq_count--;		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));	}}void ap_flush_queue(struct ap_device *ap_dev){	spin_lock_bh(&ap_dev->lock);	__ap_flush_queue(ap_dev);	spin_unlock_bh(&ap_dev->lock);}EXPORT_SYMBOL(ap_flush_queue);static int ap_device_remove(struct device *dev){	struct ap_device *ap_dev = to_ap_dev(dev);	struct ap_driver *ap_drv = ap_dev->drv;	ap_flush_queue(ap_dev);	del_timer_sync(&ap_dev->timeout);	if (ap_drv->remove)		ap_drv->remove(ap_dev);	spin_lock_bh(&ap_device_lock);	list_del_init(&ap_dev->list);	spin_unlock_bh(&ap_device_lock);	spin_lock_bh(&ap_dev->lock);	atomic_sub(ap_dev->queue_count, &ap_poll_requests);	spin_unlock_bh(&ap_dev->lock);	return 0;}int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,		       char *name){	struct device_driver *drv = &ap_drv->driver;	drv->bus = &ap_bus_type;	drv->probe = ap_device_probe;	drv->remove = ap_device_remove;	drv->owner = owner;	drv->name = name;	return driver_register(drv);}EXPORT_SYMBOL(ap_driver_register);void ap_driver_unregister(struct ap_driver *ap_drv){	driver_unregister(&ap_drv->driver);}EXPORT_SYMBOL(ap_driver_unregister);/** * AP bus attributes. */static ssize_t ap_domain_show(struct bus_type *bus, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);}static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);static ssize_t ap_config_time_show(struct bus_type *bus, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);}static ssize_t ap_config_time_store(struct bus_type *bus,				    const char *buf, size_t count){	int time;	if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)		return -EINVAL;	ap_config_time = time;	if (!timer_pending(&ap_config_timer) ||	    !mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ)) {		ap_config_timer.expires = jiffies + ap_config_time * HZ;		add_timer(&ap_config_timer);	}	return count;}static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store);static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);}static ssize_t ap_poll_thread_store(struct bus_type *bus,				    const char *buf, size_t count){	int flag, rc;	if (sscanf(buf, "%d\n", &flag) != 1)		return -EINVAL;	if (flag) {		rc = ap_poll_thread_start();		if (rc)			return rc;	}	else		ap_poll_thread_stop();	return count;}static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);static struct bus_attribute *const ap_bus_attrs[] = {	&bus_attr_ap_domain,	&bus_attr_config_time,	&bus_attr_poll_thread,	NULL};/** * Pick one of the 16 ap domains. */static int ap_select_domain(void){	int queue_depth, device_type, count, max_count, best_domain;	int rc, i, j;	/**	 * We want to use a single domain. Either the one specified with	 * the "domain=" parameter or the domain with the maximum number	 * of devices.	 */	if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS)		/* Domain has already been selected. */		return 0;	best_domain = -1;	max_count = 0;	for (i = 0; i < AP_DOMAINS; i++) {		count = 0;		for (j = 0; j < AP_DEVICES; j++) {			ap_qid_t qid = AP_MKQID(j, i);			rc = ap_query_queue(qid, &queue_depth, &device_type);			if (rc)				continue;			count++;		}		if (count > max_count) {			max_count = count;			best_domain = i;		}	}	if (best_domain >= 0){		ap_domain_index = best_domain;		return 0;	}	return -ENODEV;}/** * Find the device type if query queue returned a device type of 0. * @ap_dev: pointer to the AP device. */static int ap_probe_device_type(struct ap_device *ap_dev){	static unsigned char msg[] = {		0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x01,0x00,0x43,0x43,0x41,0x2d,0x41,0x50,		0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,		0x00,0x00,0x00,0x00,0x50,0x4b,0x00,0x00,		0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x54,0x32,0x01,0x00,0xa0,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0xb8,0x05,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,		0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20,		0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,		0x2d,0x31,0x2e,0x32,0x37,0x00,0x11,0x22,		0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,		0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,		0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,		0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,		0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,		0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,		0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,		0x88,0x1e,0x00,0x00,0x57,0x00,0x00,0x00,		0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,		0x03,0x02,0x00,0x00,0x40,0x01,0x00,0x01,		0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,		0xf6,0xd2,0x7b,0x58,0x4b,0xf9,0x28,0x68,		0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,		0x63,0x42,0xef,0xf8,0xfd,0xa4,0xf8,0xb0,		0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,		0x53,0x8c,0x6f,0x4e,0x72,0x8f,0x6c,0x04,		0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,		0xf7,0xdd,0xfd,0x4f,0x11,0x36,0x95,0x5d,	};	struct ap_queue_status status;	unsigned long long psmid;	char *reply;	int rc, i;	reply = (void *) get_zeroed_page(GFP_KERNEL);	if (!reply) {		rc = -ENOMEM;		goto out;	}	status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,			   msg, sizeof(msg));	if (status.response_code != AP_RESPONSE_NORMAL) {		rc = -ENODEV;		goto out_free;	}	/* Wait for the test message to complete. */	for (i = 0; i < 6; i++) {		mdelay(300);		status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);		if (status.response_code == AP_RESPONSE_NORMAL &&		    psmid == 0x0102030405060708ULL)			break;	}	if (i < 6) {		/* Got an answer. */		if (reply[0] == 0x00 && reply[1] == 0x86)			ap_dev->device_type = AP_DEVICE_TYPE_PCICC;		else			ap_dev->device_type = AP_DEVICE_TYPE_PCICA;		rc = 0;	} else		rc = -ENODEV;out_free:	free_page((unsigned long) reply);out:	return rc;}/** * Scan the ap bus for new devices. */static int __ap_scan_bus(struct device *dev, void *data){	return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;}static void ap_device_release(struct device *dev){	struct ap_device *ap_dev = to_ap_dev(dev);	kfree(ap_dev);}static void ap_scan_bus(struct work_struct *unused){	struct ap_device *ap_dev;	struct device *dev;	ap_qid_t qid;	int queue_depth, device_type;	int rc, i;	if (ap_select_domain() != 0)		return;	for (i = 0; i < AP_DEVICES; i++) {		qid = AP_MKQID(i, ap_domain_index);		dev = bus_find_device(&ap_bus_type, NULL,				      (void *)(unsigned long)qid,				      __ap_scan_bus);		rc = ap_query_queue(qid, &queue_depth, &device_type);		if (dev) {			if (rc == -EBUSY) {				set_current_state(TASK_UNINTERRUPTIBLE);				schedule_timeout(AP_RESET_TIMEOUT);				rc = ap_query_queue(qid, &queue_depth,						    &device_type);			}			ap_dev = to_ap_dev(dev);			spin_lock_bh(&ap_dev->lock);			if (rc || ap_dev->unregistered) {				spin_unlock_bh(&ap_dev->lock);				device_unregister(dev);				put_device(dev);				continue;			}			spin_unlock_bh(&ap_dev->lock);			put_device(dev);			continue;		}		if (rc)			continue;		rc = ap_init_queue(qid);		if (rc)			continue;		ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);		if (!ap_dev)			break;		ap_dev->qid = qid;		ap_dev->queue_depth = queue_depth;		ap_dev->unregistered = 1;		spin_lock_init(&ap_dev->lock);		INIT_LIST_HEAD(&ap_dev->pendingq);		INIT_LIST_HEAD(&ap_dev->requestq);		INIT_LIST_HEAD(&ap_dev->list);		setup_timer(&ap_dev->timeout, ap_request_timeout,			    (unsigned long) ap_dev);		if (device_type == 0)			ap_probe_device_type(ap_dev);		else			ap_dev->device_type = device_type;		ap_dev->device.bus = &ap_bus_type;		ap_dev->device.parent = ap_root_device;		snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",			 AP_QID_DEVICE(ap_dev->qid));		ap_dev->device.release = ap_device_release;		rc = device_register(&ap_dev->device);		if (rc) {			kfree(ap_dev);			continue;		}		/* Add device attributes. */		rc = sysfs_create_group(&ap_dev->device.kobj,					&ap_dev_attr_group);		if (!rc) {			spin_lock_bh(&ap_dev->lock);			ap_dev->unregistered = 0;			spin_unlock_bh(&ap_dev->lock);		}		else			device_unregister(&ap_dev->device);	}}static voidap_config_timeout(unsigned long ptr){	queue_work(ap_work_queue, &ap_config_work);	ap_config_timer.expires = jiffies + ap_config_time * HZ;	add_timer(&ap_config_timer);}/** * Set up the timer to run the poll tasklet */static inline void ap_schedule_poll_timer(void){	if (timer_pending(&ap_poll_timer))		return;	mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME);}/** * Receive pending reply messages from an AP device. * @ap_dev: pointer to the AP device * @flags: pointer to control flags, bit 2^0 is set if another poll is *	   required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags){	struct ap_queue_status status;	struct ap_message *ap_msg;	if (ap_dev->queue_count <= 0)		return 0;	status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid,			   ap_dev->reply->message, ap_dev->reply->length);	switch (status.response_code) {	case AP_RESPONSE_NORMAL:		atomic_dec(&ap_poll_requests);		ap_decrease_queue_count(ap_dev);		list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {			if (ap_msg->psmid != ap_dev->reply->psmid)				continue;			list_del_init(&ap_msg->list);			ap_dev->pendingq_count--;			ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply);			break;		}

⌨️ 快捷键说明

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