summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/adb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macintosh/adb.c')
-rw-r--r--drivers/macintosh/adb.c144
1 files changed, 109 insertions, 35 deletions
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index be5c45a6c..73a53a6f4 100644
--- a/drivers/macintosh/adb.c
+++ b/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 @@ static int adb_scan_bus(void)
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 @@ static int adb_scan_bus(void)
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 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
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 @@ static int adb_open(struct inode *inode, struct file *file)
{
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 @@ static ssize_t adb_write(struct file *file, const char *buf,
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 @@ static struct file_operations adb_fops = {
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);
}