patch-2.1.79 linux/drivers/macintosh/adb.c
Next file: linux/drivers/macintosh/ati-gt.h
Previous file: linux/drivers/macintosh/Makefile
Back to the patch index
Back to the overall index
- Lines: 233
- Date:
Mon Jan 12 15:18:13 1998
- Orig file:
v2.1.78/linux/drivers/macintosh/adb.c
- Orig date:
Wed Sep 24 20:05:47 1997
diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
@@ -1,5 +1,6 @@
/*
- * Device driver for the /dev/adb device on macintoshes.
+ * Device driver for the Apple Desktop Bus
+ * and the /dev/adb device on macintoshes.
*
* Copyright (C) 1996 Paul Mackerras.
*/
@@ -10,15 +11,99 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/prom.h>
+#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/uaccess.h>
+#include <asm/hydra.h>
+
+enum adb_hw adb_hardware;
+int (*adb_send_request)(struct adb_request *req, int sync);
+int (*adb_autopoll)(int on);
+
+static struct adb_handler {
+ void (*handler)(unsigned char *, int, struct pt_regs *, int);
+} adb_handler[16];
+
+static int adb_nodev(void)
+{
+ return -1;
+}
+
+void adb_init(void)
+{
+ adb_hardware = ADB_NONE;
+ adb_send_request = (void *) adb_nodev;
+ adb_autopoll = (void *) adb_nodev;
+ via_cuda_init();
+ macio_adb_init();
+ if (adb_hardware == ADB_NONE)
+ printk(KERN_WARNING "Warning: no ADB interface detected\n");
+ else
+ adb_autopoll(1);
+}
+
+int
+adb_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int flags, int nbytes, ...)
+{
+ va_list list;
+ int i;
+ struct adb_request sreq;
+
+ if (req == NULL) {
+ req = &sreq;
+ flags |= ADBREQ_SYNC;
+ }
+ req->nbytes = nbytes;
+ req->done = done;
+ req->reply_expected = flags & ADBREQ_REPLY;
+ va_start(list, nbytes);
+ for (i = 0; i < nbytes; ++i)
+ req->data[i] = va_arg(list, int);
+ va_end(list);
+ return adb_send_request(req, flags & ADBREQ_SYNC);
+}
+
+/* Ultimately this should return the number of devices with
+ the given default id. */
+int
+adb_register(int default_id,
+ void (*handler)(unsigned char *, int, struct pt_regs *, int))
+{
+ if (adb_handler[default_id].handler != 0)
+ panic("Two handlers for ADB device %d\n", default_id);
+ adb_handler[default_id].handler = handler;
+ return 1;
+}
+
+void
+adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
+{
+ int i, id;
+ static int dump_adb_input = 0;
+
+ id = buf[0] >> 4;
+ if (dump_adb_input) {
+ printk(KERN_INFO "adb packet: ");
+ for (i = 0; i < nb; ++i)
+ printk(" %x", buf[i]);
+ printk(", id = %d\n", id);
+ }
+ if (adb_handler[id].handler != 0) {
+ (*adb_handler[id].handler)(buf, nb, regs, autopoll);
+ }
+}
+
+/*
+ * /dev/adb device driver.
+ */
#define ADB_MAJOR 56 /* major number for /dev/adb */
extern void adbdev_init(void);
struct adbdev_state {
- struct cuda_request req;
+ struct adb_request req;
};
static struct wait_queue *adb_wait;
@@ -31,7 +116,7 @@
add_wait_queue(&adb_wait, &wait);
current->state = TASK_INTERRUPTIBLE;
- while (!state->req.got_reply) {
+ while (!state->req.complete) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
@@ -49,11 +134,11 @@
return ret;
}
-static void adb_write_done(struct cuda_request *req)
+static void adb_write_done(struct adb_request *req)
{
- if (!req->got_reply) {
+ if (!req->complete) {
req->reply_len = 0;
- req->got_reply = 1;
+ req->complete = 1;
}
wake_up_interruptible(&adb_wait);
}
@@ -62,7 +147,7 @@
{
struct adbdev_state *state;
- if (MINOR(inode->i_rdev) > 0)
+ if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE)
return -ENXIO;
state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
if (state == 0)
@@ -78,7 +163,7 @@
if (state) {
file->private_data = NULL;
- if (state->req.reply_expected && !state->req.got_reply)
+ if (state->req.reply_expected && !state->req.complete)
if (adb_wait_reply(state, file))
return 0;
kfree(state);
@@ -86,13 +171,13 @@
return 0;
}
-static long long adb_lseek(struct file *file, long long offset, int origin)
+static long long adb_lseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static long adb_read(struct inode *inode, struct file *file,
- char *buf, unsigned long count)
+static ssize_t adb_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
{
int ret;
struct adbdev_state *state = file->private_data;
@@ -112,17 +197,18 @@
if (ret)
return ret;
- ret = state->req.reply_len;
- copy_to_user(buf, state->req.reply, ret);
state->req.reply_expected = 0;
+ ret = state->req.reply_len;
+ if (copy_to_user(buf, state->req.reply, ret))
+ return -EFAULT;
return ret;
}
-static long adb_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t adb_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
{
- int ret;
+ int ret, i;
struct adbdev_state *state = file->private_data;
if (count < 2 || count > sizeof(state->req.data))
@@ -131,7 +217,7 @@
if (ret)
return ret;
- if (state->req.reply_expected && !state->req.got_reply) {
+ if (state->req.reply_expected && !state->req.complete) {
/* A previous request is still being processed.
Wait for it to finish. */
ret = adb_wait_reply(state, file);
@@ -141,10 +227,27 @@
state->req.nbytes = count;
state->req.done = adb_write_done;
- copy_from_user(state->req.data, buf, count);
- state->req.reply_expected = 1;
- state->req.got_reply = 0;
- cuda_send_request(&state->req);
+ state->req.complete = 0;
+ if (copy_from_user(state->req.data, buf, count))
+ return -EFAULT;
+
+ switch (adb_hardware) {
+ case ADB_NONE:
+ return -ENXIO;
+ case ADB_VIACUDA:
+ state->req.reply_expected = 1;
+ cuda_send_request(&state->req);
+ break;
+ default:
+ if (state->req.data[0] != ADB_PACKET)
+ return -EINVAL;
+ for (i = 1; i < state->req.nbytes; ++i)
+ state->req.data[i] = state->req.data[i+1];
+ state->req.reply_expected =
+ ((state->req.data[0] & 0xc) == 0xc);
+ adb_send_request(&state->req, 0);
+ break;
+ }
return count;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov