diff options
Diffstat (limited to 'drivers/macintosh/adb.c')
-rw-r--r-- | drivers/macintosh/adb.c | 144 |
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); } |