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
- Lines: 282
- Date:
Thu Apr 29 12:53:48 1999
- Orig file:
v2.2.7/linux/drivers/macintosh/adb.c
- Orig date:
Fri Apr 16 14:47:30 1999
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)