patch-2.3.20 linux/drivers/macintosh/adb.c

Next file: linux/drivers/macintosh/mac_keyb.c
Previous file: linux/drivers/macintosh/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.19/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
@@ -24,29 +24,59 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/notifier.h>
 #include <linux/wait.h>
-#include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_PPC
+#include <asm/prom.h>
 #include <asm/hydra.h>
-#include <linux/init.h>
+#endif
 
 EXPORT_SYMBOL(adb_controller);
 EXPORT_SYMBOL(adb_client_list);
-EXPORT_SYMBOL(adb_hardware);
 
-struct adb_controller *adb_controller = NULL;
+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;
-enum adb_hw adb_hardware = ADB_NONE;
+static int adb_got_sleep = 0;
 
 #ifdef CONFIG_PMAC_PBOOK
-static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
-static struct notifier_block adb_sleep_notifier = {
+static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier adb_sleep_notifier = {
 	adb_notify_sleep,
-	NULL,
-	0
+	SLEEP_LEVEL_ADB,
 };
 #endif
 
@@ -109,6 +139,15 @@
 			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.
 			 */
@@ -159,49 +198,73 @@
 	return devmask;
 }
 
-void adb_init(void)
+int __init adb_init(void)
 {
+	struct adb_driver *driver;
+	int i;
+
+#ifdef CONFIG_PPC
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;
+		return 0;
+#endif
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return 0;
+#endif
 
-	via_cuda_init();
-	via_pmu_init();
-	macio_adb_init();
-	
-	if (adb_controller == NULL)
+	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
-	{
-		adb_hardware = adb_controller->kind;
+	} else {
 #ifdef CONFIG_PMAC_PBOOK
-		notifier_chain_register(&sleep_notifier_list,
-					&adb_sleep_notifier);
+		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
  */
 int
-adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x)
+adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
 	int ret;
 	
-	switch (code) {
-		case PBOOK_SLEEP:
-			ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
-			if (ret & NOTIFY_STOP_MASK)
-				return -EBUSY;
-		case PBOOK_WAKE:
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		adb_got_sleep = 1;
+		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;
+		}
+		break;
+		
+	case PBOOK_SLEEP_NOW:
+		break;
+	case PBOOK_WAKE:
+		adb_reset_bus();
+		break;
 	}
-	return NOTIFY_DONE;
+	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
@@ -277,6 +340,9 @@
 		req->data[i+1] = va_arg(list, int);
 	va_end(list);
 
+	if (flags & ADBREQ_NOSEND)
+		return 0;
+
 	return adb_controller->send_request(req, flags & ADBREQ_SYNC);
 }
 
@@ -413,7 +479,7 @@
 {
 	struct adbdev_state *state;
 
-	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+	if (MINOR(inode->i_rdev) > 0 || adb_controller == NULL)
 		return -ENXIO;
 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
 	if (state == 0)
@@ -540,6 +606,7 @@
 		goto out;
 
 	atomic_inc(&state->n_pending);
+	if (adb_controller == NULL) return -ENXIO;
 
 	/* Special case for ADB_BUSRESET request, all others are sent to
 	   the controller */
@@ -582,8 +649,15 @@
 
 void adbdev_init()
 {
+#ifdef CONFIG_PPC
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;		
+		return;
+#endif
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return;
+#endif
+
 	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
 		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)