OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / gdb / rdi-share / devsw.c
1 /* 
2  * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3  * 
4  * This software may be freely used, copied, modified, and distributed
5  * provided that the above copyright notice is preserved in all copies of the
6  * software.
7  */
8
9 /* -*-C-*-
10  *
11  * $Revision$
12  *     $Date$
13  *
14  */
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include "adp.h"
19 #include "hsys.h"
20 #include "rxtx.h"
21 #include "drivers.h"
22 #include "buffers.h"
23 #include "devclnt.h"
24 #include "adperr.h"
25 #include "devsw.h"
26 #include "hostchan.h"
27 #include "logging.h"
28
29 /*
30  * TODO: this should be adjustable - it could be done by defining
31  *       a reason code for DevSW_Ioctl.  It could even be a
32  *       per-devicechannel parameter.
33  */
34 static const unsigned int allocsize = ADP_BUFFER_MIN_SIZE;
35
36 #define illegalDevChanID(type)  ((type) >= DC_NUM_CHANNELS)
37
38 /**********************************************************************/
39
40 /*
41  *  Function: initialise_read
42  *   Purpose: Set up a read request for another packet
43  *
44  *    Params:
45  *      In/Out: ds      State structure to be initialised
46  *
47  *   Returns:
48  *          OK: 0
49  *       Error: -1
50  */
51 static int initialise_read(DevSWState *ds)
52 {
53     struct data_packet *dp;
54
55     /*
56      * try to claim the structure that will
57      * eventually hold the new packet.
58      */
59     if ((ds->ds_nextreadpacket = DevSW_AllocatePacket(allocsize)) == NULL)
60         return -1;
61
62     /*
63      * Calls into the device driver use the DriverCall structure: use
64      * the buffer we have just allocated, and declare its size.  We
65      * are also obliged to clear the driver's context pointer.
66      */
67     dp = &ds->ds_activeread.dc_packet;
68     dp->buf_len = allocsize;
69     dp->data = ds->ds_nextreadpacket->pk_buffer;
70
71     ds->ds_activeread.dc_context = NULL;
72
73     return 0;
74 }
75
76 /*
77  *  Function: initialise_write
78  *   Purpose: Set up a write request for another packet
79  *
80  *    Params:
81  *       Input: packet  The packet to be written
82  *
83  *              type    The type of the packet
84  *
85  *      In/Out: dc      The structure to be intialised
86  *
87  *   Returns: Nothing
88  */
89 static void initialise_write(DriverCall *dc, Packet *packet, DevChanID type)
90 {
91     struct data_packet *dp = &dc->dc_packet;
92
93     dp->len = packet->pk_length;
94     dp->data = packet->pk_buffer;
95     dp->type = type;
96
97     /*
98      * we are required to clear the state structure for the driver
99      */
100     dc->dc_context = NULL;
101 }
102
103 /*
104  *  Function: enqueue_packet
105  *   Purpose: move a newly read packet onto the appropriate queue
106  *              of read packets
107  *
108  *    Params:
109  *      In/Out: ds      State structure with new packet
110  *
111  *   Returns: Nothing
112  */
113 static void enqueue_packet(DevSWState *ds)
114 {
115     struct data_packet *dp = &ds->ds_activeread.dc_packet;
116     Packet *packet = ds->ds_nextreadpacket;
117
118     /*
119      * transfer the length
120      */
121     packet->pk_length = dp->len;
122
123     /*
124      * take this packet out of the incoming slot
125      */
126     ds->ds_nextreadpacket = NULL;
127
128     /*
129      * try to put it on the correct input queue
130      */
131     if (illegalDevChanID(dp->type))
132     {
133         /* this shouldn't happen */
134         WARN("Illegal type for Rx packet");
135         DevSW_FreePacket(packet);
136     }
137     else
138         Adp_addToQueue(&ds->ds_readqueue[dp->type], packet);
139 }
140
141 /*
142  *  Function: flush_packet
143  *   Purpose: Send a packet to the device driver
144  *
145  *    Params:
146  *       Input: device  The device to be written to
147  *
148  *      In/Out: dc      Describes the packet to be sent
149  *
150  *   Returns: Nothing
151  *
152  * Post-conditions: If the whole packet was accepted by the device
153  *                      driver, then dc->dc_packet.data will be
154  *                      set to NULL.
155  */
156 static void flush_packet(const DeviceDescr *device, DriverCall *dc)
157 {
158     if (device->DeviceWrite(dc) > 0)
159         /*
160          * the whole packet was swallowed
161          */
162         dc->dc_packet.data = NULL;
163 }
164
165 /**********************************************************************/
166
167 /*
168  * These are the externally visible functions.  They are documented in
169  * devsw.h
170  */
171 Packet *DevSW_AllocatePacket(const unsigned int length)
172 {
173     Packet *pk;
174
175     if ((pk = malloc(sizeof(*pk))) == NULL)
176     {
177         WARN("malloc failure");
178         return NULL;
179     }
180
181     if ((pk->pk_buffer = malloc(length+CHAN_HEADER_SIZE)) == NULL)
182     {
183         WARN("malloc failure");
184         free(pk);
185         return NULL;
186     }
187
188     return pk;
189 }
190
191 void DevSW_FreePacket(Packet *pk)
192 {
193     free(pk->pk_buffer);
194     free(pk);
195 }
196
197 AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg,
198                    const DevChanID type)
199 {
200     DevSWState *ds;
201
202     /*
203      * is this the very first open call for this driver?
204      */
205     if ((ds = (DevSWState *)(device->SwitcherState)) == NULL)
206     {
207         /*
208          * yes, it is: initialise state
209          */
210         if ((ds = malloc(sizeof(*ds))) == NULL)
211             /* give up */
212             return adp_malloc_failure;
213
214         (void)memset(ds, 0, sizeof(*ds));
215         device->SwitcherState = (void *)ds;
216     }
217
218     /*
219      * check that we haven't already been opened for this type
220      */
221     if ((ds->ds_opendevchans & (1 << type)) != 0)
222         return adp_device_already_open;
223
224     /*
225      * if no opens have been done for this device, then do it now
226      */
227     if (ds->ds_opendevchans == 0)
228         if (device->DeviceOpen(name, arg) < 0)
229             return adp_device_open_failed;
230
231     /*
232      * open has finished
233      */
234     ds->ds_opendevchans |= (1 << type);
235     return adp_ok;
236 }
237
238 AdpErrs DevSW_Match(const DeviceDescr *device, const char *name,
239                     const char *arg)
240 {
241     return (device->DeviceMatch(name, arg) == -1) ? adp_failed : adp_ok;
242 }
243
244 AdpErrs DevSW_Close(const DeviceDescr *device, const DevChanID type)
245 {
246     DevSWState *ds = (DevSWState *)(device->SwitcherState);
247     Packet *pk;
248
249     if ((ds->ds_opendevchans & (1 << type)) == 0)
250         return adp_device_not_open;
251
252     ds->ds_opendevchans &= ~(1 << type);
253
254     /*
255      * if this is the last close for this channel, then inform the driver
256      */
257     if (ds->ds_opendevchans == 0)
258         device->DeviceClose();
259
260     /*
261      * release all packets of the appropriate type
262      */
263     for (pk = Adp_removeFromQueue(&(ds->ds_readqueue[type]));
264          pk != NULL;
265          pk = Adp_removeFromQueue(&(ds->ds_readqueue[type])))
266         DevSW_FreePacket(pk);
267
268     /* Free memory */
269     free ((char *) device->SwitcherState);
270     device->SwitcherState = 0x0;
271
272     /* that's all */
273     return adp_ok;
274 }
275
276 AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type,
277                    Packet **packet, bool block)
278 {
279   int read_err;
280   DevSWState *ds = device->SwitcherState;
281
282     /*
283      * To try to get information out of the device driver as
284      * quickly as possible, we try and read more packets, even
285      * if a completed packet is already available.
286      */
287
288     /*
289      * have we got a packet currently pending?
290      */
291   if (ds->ds_nextreadpacket == NULL)
292     /*
293        * no - set things up
294        */
295     if (initialise_read(ds) < 0) {
296       /*
297        * we failed to initialise the next packet, but can
298        * still return a packet that has already arrived.
299        */
300       *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]); 
301       return adp_ok;
302     }
303   read_err = device->DeviceRead(&ds->ds_activeread, block);
304   switch (read_err) {
305   case 1:
306     /*
307      * driver has pulled in a complete packet, queue it up
308      */
309 #ifdef RET_DEBUG
310     printf("got a complete packet\n");
311 #endif
312     enqueue_packet(ds);
313     *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
314     return adp_ok;
315   case 0:
316     /*
317      * OK, return the head of the read queue for the given type
318      */
319     /*    enqueue_packet(ds); */
320     *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
321     return adp_ok;
322   case -1:
323 #ifdef RET_DEBUG
324     printf("got a bad packet\n");
325 #endif
326     /* bad packet */
327     *packet = NULL;
328     return adp_bad_packet;
329   default:
330     panic("DevSW_Read: bad read status %d", read_err);
331   }
332   return 0; /* get rid of a potential compiler warning */
333 }
334
335
336 AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device)
337 {
338     struct DriverCall *dc;
339     struct data_packet *dp;
340
341     dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
342     dp = &dc->dc_packet;
343
344     /*
345      * try to flush any packet that is still being written
346      */
347     if (dp->data != NULL)
348     {
349         flush_packet(device, dc);
350
351         /* see if it has gone */
352         if (dp->data != NULL)
353            return adp_write_busy;
354         else
355            return adp_ok;
356     }
357     else
358        return adp_ok;
359 }
360
361
362 AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type)
363 {
364     struct DriverCall *dc;
365     struct data_packet *dp;
366
367     dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
368     dp = &dc->dc_packet;
369
370     if (illegalDevChanID(type))
371         return adp_illegal_args;
372
373     /*
374      * try to flush any packet that is still being written
375      */
376     if (DevSW_FlushPendingWrite(device) != adp_ok)
377        return adp_write_busy;
378
379     /*
380      * we can take this packet - set things up, then try to get rid of it
381      */
382     initialise_write(dc, packet, type);
383     flush_packet(device, dc);
384
385     return adp_ok;
386 }
387
388 AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args)
389 {
390     return (device->DeviceIoctl(opcode, args) < 0) ? adp_failed : adp_ok;
391 }
392
393 bool DevSW_WriteFinished(const DeviceDescr *device)
394 {
395     struct DriverCall *dc;
396     struct data_packet *dp;
397
398     dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
399     dp = &dc->dc_packet;
400
401     return (dp == NULL || dp->data == NULL);
402 }
403
404 /* EOF devsw.c */