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

📄 adb.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Device driver for the Apple Desktop Bus * and the /dev/adb device on macintoshes. * * Copyright (C) 1996 Paul Mackerras. * * Modified to declare controllers as structures, added * client notification of bus reset and handles PowerBook * sleep, by Benjamin Herrenschmidt. * * To do: * * - /proc/adb to list the devices and infos * - more /dev/adb to allow userland to receive the *   flow of auto-polling datas from a given device. */#include <linux/config.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/devfs_fs_kernel.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/adb.h>#include <linux/cuda.h>#include <linux/pmu.h>#include <linux/notifier.h>#include <linux/wait.h>#include <linux/init.h>#include <asm/uaccess.h>#ifdef CONFIG_PPC#include <asm/prom.h>#include <asm/hydra.h>#endifEXPORT_SYMBOL(adb_controller);EXPORT_SYMBOL(adb_client_list);extern struct adb_driver via_macii_driver;extern struct adb_driver via_maciisi_driver;extern struct adb_driver via_cuda_driver;extern struct adb_driver adb_iop_driver;extern struct adb_driver via_pmu_driver;extern struct adb_driver macio_adb_driver;static struct adb_driver *adb_driver_list[] = {#ifdef CONFIG_ADB_MACII	&via_macii_driver,#endif#ifdef CONFIG_ADB_MACIISI	&via_maciisi_driver,#endif#ifdef CONFIG_ADB_CUDA	&via_cuda_driver,#endif#ifdef CONFIG_ADB_IOP	&adb_iop_driver,#endif#ifdef CONFIG_ADB_PMU	&via_pmu_driver,#endif#ifdef CONFIG_ADB_MACIO	&macio_adb_driver,#endif	NULL};struct adb_driver *adb_controller;struct notifier_block *adb_client_list = NULL;static int adb_got_sleep = 0;static int adb_inited = 0;#ifdef CONFIG_PMAC_PBOOKstatic int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);static struct pmu_sleep_notifier adb_sleep_notifier = {	adb_notify_sleep,	SLEEP_LEVEL_ADB,};#endifstatic int adb_scan_bus(void);static struct adb_handler {	void (*handler)(unsigned char *, int, struct pt_regs *, int);	int original_address;	int handler_id;} adb_handler[16];#if 0static void printADBreply(struct adb_request *req){        int i;        printk("adb reply (%d)", req->reply_len);        for(i = 0; i < req->reply_len; i++)                printk(" %x", req->reply[i]);        printk("\n");}#endifstatic int adb_scan_bus(void){	int i, highFree=0, noMovement;	int devmask = 0;	struct adb_request req;		/* assumes adb_handler[] is all zeroes at this point */	for (i = 1; i < 16; i++) {		/* see if there is anything at address i */		adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,                            (i << 4) | 0xf);		if (req.reply_len > 1)			/* one or more devices at this address */			adb_handler[i].original_address = i;		else if (i > highFree)			highFree = i;	}	/* Note we reset noMovement to 0 each time we move a device */	for (noMovement = 1; noMovement < 2 && highFree > 0; noMovement++) {		for (i = 1; i < 16; i++) {			if (adb_handler[i].original_address == 0)				continue;			/*			 * Send a "talk register 3" command to address i			 * to provoke a collision if there is more than			 * one device at this address.			 */			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,				    (i << 4) | 0xf);			/*			 * Move the device(s) which didn't detect a			 * collision to address `highFree'.  Hopefully			 * this only moves one device.			 */			adb_request(&req, NULL, ADBREQ_SYNC, 3,				    (i<< 4) | 0xb, (highFree | 0x60), 0xfe);			/*			 * See if anybody actually moved. This is suggested			 * by HW TechNote 01:			 *			 * http://developer.apple.com/technotes/hw/hw_01.html			 */			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,				    (highFree << 4) | 0xf);			if (req.reply_len <= 1) continue;			/*			 * Test whether there are any device(s) left			 * at address i.			 */			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,				    (i << 4) | 0xf);			if (req.reply_len > 1) {				/*				 * There are still one or more devices				 * left at address i.  Register the one(s)				 * we moved to `highFree', and find a new				 * value for highFree.				 */				adb_handler[highFree].original_address =					adb_handler[i].original_address;				while (highFree > 0 &&				       adb_handler[highFree].original_address)					highFree--;				if (highFree <= 0)					break;				noMovement = 0;			}			else {				/*				 * No devices left at address i; move the				 * one(s) we moved to `highFree' back to i.				 */				adb_request(&req, NULL, ADBREQ_SYNC, 3,					    (highFree << 4) | 0xb,					    (i | 0x60), 0xfe);			}		}		}	/* Now fill in the handler_id field of the adb_handler entries. */	printk(KERN_DEBUG "adb devices:");	for (i = 1; i < 16; i++) {		if (adb_handler[i].original_address == 0)			continue;		adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,			    (i << 4) | 0xf);		adb_handler[i].handler_id = req.reply[2];		printk(" [%d]: %d %x", i, adb_handler[i].original_address,		       adb_handler[i].handler_id);		devmask |= 1 << i;	}	printk("\n");	return devmask;}int __init adb_init(void){	struct adb_driver *driver;	int i;#ifdef CONFIG_PPC	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )		return 0;#endif#ifdef CONFIG_MAC	if (!MACH_IS_MAC)		return 0;#endif	/* xmon may do early-init */	if (adb_inited)		return 0;	adb_inited = 1;			adb_controller = NULL;	i = 0;	while ((driver = adb_driver_list[i++]) != NULL) {		if (!driver->probe()) {			adb_controller = driver;			break;		}	}	if ((adb_controller == NULL) || adb_controller->init()) {		printk(KERN_WARNING "Warning: no ADB interface detected\n");	} else {#ifdef CONFIG_PMAC_PBOOK		pmu_register_sleep_notifier(&adb_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */		adb_reset_bus();	}	return 0;}__initcall(adb_init);#ifdef CONFIG_PMAC_PBOOK/* * notify clients before sleep and reset bus afterwards */intadb_notify_sleep(struct pmu_sleep_notifier *self, int when){	int ret;		switch (when) {	case PBOOK_SLEEP_REQUEST:		adb_got_sleep = 1;		if (adb_controller->autopoll)			adb_controller->autopoll(0);		ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);		if (ret & NOTIFY_STOP_MASK)			return PBOOK_SLEEP_REFUSE;		break;	case PBOOK_SLEEP_REJECT:		if (adb_got_sleep) {			adb_got_sleep = 0;			adb_reset_bus();		}		break;			case PBOOK_SLEEP_NOW:		break;	case PBOOK_WAKE:		adb_reset_bus();		adb_got_sleep = 0;		break;	}	return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK */intadb_reset_bus(void){	int ret, nret, devs;	unsigned long flags;		if (adb_controller == NULL)		return -ENXIO;			if (adb_controller->autopoll)		adb_controller->autopoll(0);	nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);	if (nret & NOTIFY_STOP_MASK) {		if (adb_controller->autopoll)			adb_controller->autopoll(devs);		return -EBUSY;	}	save_flags(flags);	cli();	memset(adb_handler, 0, sizeof(adb_handler));	restore_flags(flags);		if (adb_controller->reset_bus)		ret = adb_controller->reset_bus();	else		ret = 0;	if (!ret) {		devs = adb_scan_bus();		if (adb_controller->autopoll)			adb_controller->autopoll(devs);	}	nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);	if (nret & NOTIFY_STOP_MASK)		return -EBUSY;		return ret;}voidadb_poll(void){	if ((adb_controller == NULL)||(adb_controller->poll == NULL))		return;	adb_controller->poll();}intadb_request(struct adb_request *req, void (*done)(struct adb_request *),	    int flags, int nbytes, ...){	va_list list;	int i;	struct adb_request sreq;	if ((adb_controller == NULL) || (adb_controller->send_request == NULL))		return -ENXIO;	if (nbytes < 1)		return -EINVAL;		if (req == NULL) {		req = &sreq;

⌨️ 快捷键说明

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