OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [macintosh/] [adb-iop.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * I/O Processor (IOP) ADB Driver
3
 * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
4
 * Based on via-cuda.c by Paul Mackerras.
5
 *
6
 * 1999-07-01 (jmt) - First implementation for new driver architecture.
7
 *
8
 * 1999-07-31 (jmt) - First working version.
9
 *
10
 * TODO:
11
 *
12
 * o Implement SRQ handling.
13
 */
14
 
15
#include <linux/types.h>
16
#include <linux/kernel.h>
17
#include <linux/mm.h>
18
#include <linux/delay.h>
19
#include <linux/init.h>
20
#include <linux/proc_fs.h>
21
 
22
#include <asm/bootinfo.h> 
23
#include <asm/macintosh.h> 
24
#include <asm/macints.h> 
25
#include <asm/mac_iop.h>
26
#include <asm/mac_oss.h>
27
#include <asm/adb_iop.h>
28
 
29
#include <linux/adb.h> 
30
 
31
/*#define DEBUG_ADB_IOP*/
32
 
33
extern void iop_ism_irq(int, void *, struct pt_regs *);
34
 
35
static struct adb_request *current_req;
36
static struct adb_request *last_req;
37
#if 0
38
static unsigned char reply_buff[16];
39
static unsigned char *reply_ptr;
40
#endif
41
 
42
static enum adb_iop_state {
43
    idle,
44
    sending,
45
    awaiting_reply
46
} adb_iop_state;
47
 
48
static void adb_iop_start(void);
49
static int adb_iop_probe(void);
50
static int adb_iop_init(void);
51
static int adb_iop_send_request(struct adb_request *, int);
52
static int adb_iop_write(struct adb_request *);
53
static int adb_iop_autopoll(int);
54
static void adb_iop_poll(void);
55
static int adb_iop_reset_bus(void);
56
 
57
struct adb_driver adb_iop_driver = {
58
        "ISM IOP",
59
        adb_iop_probe,
60
        adb_iop_init,
61
        adb_iop_send_request,
62
        adb_iop_autopoll,
63
        adb_iop_poll,
64
        adb_iop_reset_bus
65
};
66
 
67
static void adb_iop_end_req(struct adb_request *req, int state)
68
{
69
        req->complete = 1;
70
        current_req = req->next;
71
        if (req->done) (*req->done)(req);
72
        adb_iop_state = state;
73
}
74
 
75
/*
76
 * Completion routine for ADB commands sent to the IOP.
77
 *
78
 * This will be called when a packet has been successfully sent.
79
 */
80
 
81
static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
82
{
83
        struct adb_request *req;
84
        uint flags;
85
 
86
        save_flags(flags);
87
        cli();
88
 
89
        req = current_req;
90
        if ((adb_iop_state == sending) && req && req->reply_expected) {
91
                adb_iop_state = awaiting_reply;
92
        }
93
 
94
        restore_flags(flags);
95
}
96
 
97
/*
98
 * Listen for ADB messages from the IOP.
99
 *
100
 * This will be called when unsolicited messages (usually replies to TALK
101
 * commands or autopoll packets) are received.
102
 */
103
 
104
static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
105
{
106
        struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
107
        struct adb_request *req;
108
        uint flags;
109
#ifdef DEBUG_ADB_IOP
110
        int i;
111
#endif
112
 
113
        save_flags(flags);
114
        cli();
115
 
116
        req = current_req;
117
 
118
#ifdef DEBUG_ADB_IOP
119
        printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req,
120
                (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
121
        for (i = 0; i < amsg->count; i++)
122
                printk(" %02X", (uint) amsg->data[i]);
123
        printk("\n");
124
#endif
125
 
126
        /* Handle a timeout. Timeout packets seem to occur even after */
127
        /* we've gotten a valid reply to a TALK, so I'm assuming that */
128
        /* a "timeout" is actually more like an "end-of-data" signal. */
129
        /* We need to send back a timeout packet to the IOP to shut   */
130
        /* it up, plus complete the current request, if any.          */
131
 
132
        if (amsg->flags & ADB_IOP_TIMEOUT) {
133
                msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL;
134
                msg->reply[1] = 0;
135
                msg->reply[2] = 0;
136
                if (req && (adb_iop_state != idle)) {
137
                        adb_iop_end_req(req, idle);
138
                }
139
        } else {
140
                /* TODO: is it possible for more than one chunk of data  */
141
                /*       to arrive before the timeout? If so we need to */
142
                /*       use reply_ptr here like the other drivers do.  */
143
                if ((adb_iop_state == awaiting_reply) &&
144
                    (amsg->flags & ADB_IOP_EXPLICIT)) {
145
                        req->reply_len = amsg->count + 1;
146
                        memcpy(req->reply, &amsg->cmd, req->reply_len);
147
                } else {
148
                        adb_input(&amsg->cmd, amsg->count + 1, regs,
149
                                  amsg->flags & ADB_IOP_AUTOPOLL);
150
                }
151
                memcpy(msg->reply, msg->message, IOP_MSG_LEN);
152
        }
153
        iop_complete_message(msg);
154
        restore_flags(flags);
155
}
156
 
157
/*
158
 * Start sending an ADB packet, IOP style
159
 *
160
 * There isn't much to do other than hand the packet over to the IOP
161
 * after encapsulating it in an adb_iopmsg.
162
 */
163
 
164
static void adb_iop_start(void)
165
{
166
        unsigned long flags;
167
        struct adb_request *req;
168
        struct adb_iopmsg amsg;
169
#ifdef DEBUG_ADB_IOP
170
        int i;
171
#endif
172
 
173
        /* get the packet to send */
174
        req = current_req;
175
        if (!req) return;
176
 
177
        save_flags(flags);
178
        cli();
179
 
180
#ifdef DEBUG_ADB_IOP
181
        printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes);
182
        for (i = 0 ; i < req->nbytes ; i++)
183
                printk(" %02X", (uint) req->data[i]);
184
        printk("\n");
185
#endif
186
 
187
        /* The IOP takes MacII-style packets, so */
188
        /* strip the initial ADB_PACKET byte.    */
189
 
190
        amsg.flags = ADB_IOP_EXPLICIT;
191
        amsg.count = req->nbytes - 2;
192
 
193
        /* amsg.data immediately follows amsg.cmd, effectively making */
194
        /* amsg.cmd a pointer to the beginning of a full ADB packet.  */
195
        memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
196
 
197
        req->sent = 1;
198
        adb_iop_state = sending;
199
        restore_flags(flags);
200
 
201
        /* Now send it. The IOP manager will call adb_iop_complete */
202
        /* when the packet has been sent.                          */
203
 
204
        iop_send_message(ADB_IOP, ADB_CHAN, req,
205
                         sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
206
}
207
 
208
int adb_iop_probe(void)
209
{
210
        if (!iop_ism_present) return -ENODEV;
211
        return 0;
212
}
213
 
214
int adb_iop_init(void)
215
{
216
        printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
217
        iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
218
        return 0;
219
}
220
 
221
int adb_iop_send_request(struct adb_request *req, int sync)
222
{
223
        int err;
224
 
225
        err = adb_iop_write(req);
226
        if (err) return err;
227
 
228
        if (sync) {
229
                while (!req->complete) adb_iop_poll();
230
        }
231
        return 0;
232
}
233
 
234
static int adb_iop_write(struct adb_request *req)
235
{
236
        unsigned long flags;
237
 
238
        if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
239
                req->complete = 1;
240
                return -EINVAL;
241
        }
242
 
243
        save_flags(flags);
244
        cli();
245
 
246
        req->next = 0;
247
        req->sent = 0;
248
        req->complete = 0;
249
        req->reply_len = 0;
250
 
251
        if (current_req != 0) {
252
                last_req->next = req;
253
                last_req = req;
254
        } else {
255
                current_req = req;
256
                last_req = req;
257
        }
258
 
259
        restore_flags(flags);
260
        if (adb_iop_state == idle) adb_iop_start();
261
        return 0;
262
}
263
 
264
int adb_iop_autopoll(int devs)
265
{
266
        /* TODO: how do we enable/disable autopoll? */
267
        return 0;
268
}
269
 
270
void adb_iop_poll(void)
271
{
272
        if (adb_iop_state == idle) adb_iop_start();
273
        iop_ism_irq(0, (void *) ADB_IOP, NULL);
274
}
275
 
276
int adb_iop_reset_bus(void)
277
{
278
        struct adb_request req = {
279
                .reply_expected = 0,
280
                .nbytes = 2,
281
                .data = { ADB_PACKET, 0 },
282
        };
283
 
284
        adb_iop_write(&req);
285
        while (!req.complete) {
286
                adb_iop_poll();
287
                schedule();
288
        }
289
 
290
        return 0;
291
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.