patch-2.2.8 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.2.7/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
@@ -3,8 +3,19 @@
  * 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>
@@ -21,12 +32,23 @@
 #include <asm/hydra.h>
 #include <asm/init.h>
 
+EXPORT_SYMBOL(adb_controller);
+EXPORT_SYMBOL(adb_client_list);
 EXPORT_SYMBOL(adb_hardware);
 
+struct adb_controller *adb_controller = NULL;
+struct notifier_block *adb_client_list = NULL;
 enum adb_hw adb_hardware = ADB_NONE;
-int (*adb_send_request)(struct adb_request *req, int sync);
-int (*adb_autopoll)(int devs);
-int (*adb_reset_bus)(void);
+
+#ifdef CONFIG_PMAC_PBOOK
+static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adb_sleep_notifier = {
+	adb_notify_sleep,
+	NULL,
+	0
+};
+#endif
+
 static int adb_scan_bus(void);
 
 static struct adb_handler {
@@ -35,13 +57,6 @@
 	int handler_id;
 } adb_handler[16];
 
-__openfirmware
-
-static int adb_nodev(void)
-{
-	return -1;
-}
-
 #if 0
 static void printADBreply(struct adb_request *req)
 {
@@ -61,8 +76,6 @@
 	int devmask = 0;
 	struct adb_request req;
 	
-	adb_reset_bus();	/* reset ADB bus */
-
 	/* assumes adb_handler[] is all zeroes at this point */
 	for (i = 1; i < 16; i++) {
 		/* see if there is anything at address i */
@@ -147,22 +160,96 @@
 
 void adb_init(void)
 {
-	adb_send_request = (void *) adb_nodev;
-	adb_autopoll = (void *) adb_nodev;
-	adb_reset_bus = adb_nodev;
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 		return;
+
 	via_cuda_init();
 	via_pmu_init();
 	macio_adb_init();
-	if (adb_hardware == ADB_NONE)
+	
+	if (adb_controller == NULL)
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
-	else {
-		int devs = adb_scan_bus();
-		adb_autopoll(devs);
+	else
+	{
+		adb_hardware = adb_controller->kind;
+#ifdef CONFIG_PMAC_PBOOK
+		notifier_chain_register(&sleep_notifier_list,
+					&adb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+		adb_reset_bus();
+	}
+}
+
+
+#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)
+{
+	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:
+			adb_reset_bus();
+			break;
+	}
+	return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+int
+adb_reset_bus(void)
+{
+	int ret, devs;
+	unsigned long flags;
+	
+	if (adb_controller == NULL)
+		return -ENXIO;
+		
+	ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		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);
 	}
+
+	ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		return -EBUSY;
+	
+	return 1;
+}
+
+void
+adb_poll(void)
+{
+	if ((adb_controller == NULL)||(adb_controller->poll == NULL))
+		return;
+	adb_controller->poll();
 }
 
+
 int
 adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 	    int flags, int nbytes, ...)
@@ -171,18 +258,25 @@
 	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;
 		flags |= ADBREQ_SYNC;
 	}
-	req->nbytes = nbytes;
+	req->nbytes = nbytes+1;
 	req->done = done;
 	req->reply_expected = flags & ADBREQ_REPLY;
+	req->data[0] = ADB_PACKET;
 	va_start(list, nbytes);
 	for (i = 0; i < nbytes; ++i)
-		req->data[i] = va_arg(list, int);
+		req->data[i+1] = va_arg(list, int);
 	va_end(list);
-	return adb_send_request(req, flags & ADBREQ_SYNC);
+
+	return adb_controller->send_request(req, flags & ADBREQ_SYNC);
 }
 
  /* Ultimately this should return the number of devices with
@@ -247,7 +341,7 @@
 	if (req.reply_len < 2)
 	    return 0;
 	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(address, 3), req.reply[1], new_id);	
+	    ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);	
 	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
 	    ADB_READREG(address, 3));
 	if (req.reply_len < 2)
@@ -318,7 +412,7 @@
 {
 	struct adbdev_state *state;
 
-	if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE)
+	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
 		return -ENXIO;
 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
 	if (state == 0)
@@ -420,7 +514,7 @@
 static ssize_t adb_write(struct file *file, const char *buf,
 			 size_t count, loff_t *ppos)
 {
-	int ret, i;
+	int ret/*, i*/;
 	struct adbdev_state *state = file->private_data;
 	struct adb_request *req;
 
@@ -439,36 +533,26 @@
 	req->done = adb_write_done;
 	req->arg = (void *) state;
 	req->complete = 0;
-
+	
 	ret = -EFAULT;
 	if (copy_from_user(req->data, buf, count))
 		goto out;
 
 	atomic_inc(&state->n_pending);
-	switch (adb_hardware) {
-	case ADB_NONE:
-		ret = -ENXIO;
-		break;
-	case ADB_VIACUDA:
-		req->reply_expected = 1;
-		ret = cuda_send_request(req);
-		break;
-	case ADB_VIAPMU:
-		if (req->data[0] != ADB_PACKET) {
-			ret = pmu_send_request(req);
-			break;
-		}
-		/* else fall through */
-	default:
-		ret = -EINVAL;
-		if (req->data[0] != ADB_PACKET)
-			break;
-		for (i = 0; i < req->nbytes-1; ++i)
-			req->data[i] = req->data[i+1];
-		req->nbytes--;
-		req->reply_expected = ((req->data[0] & 0xc) == 0xc);
-		ret = adb_send_request(req, 0);
-		break;
+
+	/* Special case for ADB_BUSRESET request, all others are sent to
+	   the controller */
+	if ((req->data[0] == ADB_PACKET)&&(count > 1)
+		&&(req->data[1] == ADB_BUSRESET))
+		ret = adb_reset_bus();
+	else
+	{	
+		req->reply_expected = ((req->data[1] & 0xc) == 0xc);
+
+		if (adb_controller && adb_controller->send_request)
+			ret = adb_controller->send_request(req, 0);
+		else
+			ret = -ENXIO;
 	}
 
 	if (ret != 0) {

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