2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
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
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.
34 static const unsigned int allocsize = ADP_BUFFER_MIN_SIZE;
36 #define illegalDevChanID(type) ((type) >= DC_NUM_CHANNELS)
38 /**********************************************************************/
41 * Function: initialise_read
42 * Purpose: Set up a read request for another packet
45 * In/Out: ds State structure to be initialised
51 static int initialise_read(DevSWState *ds)
53 struct data_packet *dp;
56 * try to claim the structure that will
57 * eventually hold the new packet.
59 if ((ds->ds_nextreadpacket = DevSW_AllocatePacket(allocsize)) == NULL)
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.
67 dp = &ds->ds_activeread.dc_packet;
68 dp->buf_len = allocsize;
69 dp->data = ds->ds_nextreadpacket->pk_buffer;
71 ds->ds_activeread.dc_context = NULL;
77 * Function: initialise_write
78 * Purpose: Set up a write request for another packet
81 * Input: packet The packet to be written
83 * type The type of the packet
85 * In/Out: dc The structure to be intialised
89 static void initialise_write(DriverCall *dc, Packet *packet, DevChanID type)
91 struct data_packet *dp = &dc->dc_packet;
93 dp->len = packet->pk_length;
94 dp->data = packet->pk_buffer;
98 * we are required to clear the state structure for the driver
100 dc->dc_context = NULL;
104 * Function: enqueue_packet
105 * Purpose: move a newly read packet onto the appropriate queue
109 * In/Out: ds State structure with new packet
113 static void enqueue_packet(DevSWState *ds)
115 struct data_packet *dp = &ds->ds_activeread.dc_packet;
116 Packet *packet = ds->ds_nextreadpacket;
119 * transfer the length
121 packet->pk_length = dp->len;
124 * take this packet out of the incoming slot
126 ds->ds_nextreadpacket = NULL;
129 * try to put it on the correct input queue
131 if (illegalDevChanID(dp->type))
133 /* this shouldn't happen */
134 WARN("Illegal type for Rx packet");
135 DevSW_FreePacket(packet);
138 Adp_addToQueue(&ds->ds_readqueue[dp->type], packet);
142 * Function: flush_packet
143 * Purpose: Send a packet to the device driver
146 * Input: device The device to be written to
148 * In/Out: dc Describes the packet to be sent
152 * Post-conditions: If the whole packet was accepted by the device
153 * driver, then dc->dc_packet.data will be
156 static void flush_packet(const DeviceDescr *device, DriverCall *dc)
158 if (device->DeviceWrite(dc) > 0)
160 * the whole packet was swallowed
162 dc->dc_packet.data = NULL;
165 /**********************************************************************/
168 * These are the externally visible functions. They are documented in
171 Packet *DevSW_AllocatePacket(const unsigned int length)
175 if ((pk = malloc(sizeof(*pk))) == NULL)
177 WARN("malloc failure");
181 if ((pk->pk_buffer = malloc(length+CHAN_HEADER_SIZE)) == NULL)
183 WARN("malloc failure");
191 void DevSW_FreePacket(Packet *pk)
197 AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg,
198 const DevChanID type)
203 * is this the very first open call for this driver?
205 if ((ds = (DevSWState *)(device->SwitcherState)) == NULL)
208 * yes, it is: initialise state
210 if ((ds = malloc(sizeof(*ds))) == NULL)
212 return adp_malloc_failure;
214 (void)memset(ds, 0, sizeof(*ds));
215 device->SwitcherState = (void *)ds;
219 * check that we haven't already been opened for this type
221 if ((ds->ds_opendevchans & (1 << type)) != 0)
222 return adp_device_already_open;
225 * if no opens have been done for this device, then do it now
227 if (ds->ds_opendevchans == 0)
228 if (device->DeviceOpen(name, arg) < 0)
229 return adp_device_open_failed;
234 ds->ds_opendevchans |= (1 << type);
238 AdpErrs DevSW_Match(const DeviceDescr *device, const char *name,
241 return (device->DeviceMatch(name, arg) == -1) ? adp_failed : adp_ok;
244 AdpErrs DevSW_Close(const DeviceDescr *device, const DevChanID type)
246 DevSWState *ds = (DevSWState *)(device->SwitcherState);
249 if ((ds->ds_opendevchans & (1 << type)) == 0)
250 return adp_device_not_open;
252 ds->ds_opendevchans &= ~(1 << type);
255 * if this is the last close for this channel, then inform the driver
257 if (ds->ds_opendevchans == 0)
258 device->DeviceClose();
261 * release all packets of the appropriate type
263 for (pk = Adp_removeFromQueue(&(ds->ds_readqueue[type]));
265 pk = Adp_removeFromQueue(&(ds->ds_readqueue[type])))
266 DevSW_FreePacket(pk);
269 free ((char *) device->SwitcherState);
270 device->SwitcherState = 0x0;
276 AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type,
277 Packet **packet, bool block)
280 DevSWState *ds = device->SwitcherState;
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.
289 * have we got a packet currently pending?
291 if (ds->ds_nextreadpacket == NULL)
295 if (initialise_read(ds) < 0) {
297 * we failed to initialise the next packet, but can
298 * still return a packet that has already arrived.
300 *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
303 read_err = device->DeviceRead(&ds->ds_activeread, block);
307 * driver has pulled in a complete packet, queue it up
310 printf("got a complete packet\n");
313 *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
317 * OK, return the head of the read queue for the given type
319 /* enqueue_packet(ds); */
320 *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
324 printf("got a bad packet\n");
328 return adp_bad_packet;
330 panic("DevSW_Read: bad read status %d", read_err);
332 return 0; /* get rid of a potential compiler warning */
336 AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device)
338 struct DriverCall *dc;
339 struct data_packet *dp;
341 dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
345 * try to flush any packet that is still being written
347 if (dp->data != NULL)
349 flush_packet(device, dc);
351 /* see if it has gone */
352 if (dp->data != NULL)
353 return adp_write_busy;
362 AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type)
364 struct DriverCall *dc;
365 struct data_packet *dp;
367 dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
370 if (illegalDevChanID(type))
371 return adp_illegal_args;
374 * try to flush any packet that is still being written
376 if (DevSW_FlushPendingWrite(device) != adp_ok)
377 return adp_write_busy;
380 * we can take this packet - set things up, then try to get rid of it
382 initialise_write(dc, packet, type);
383 flush_packet(device, dc);
388 AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args)
390 return (device->DeviceIoctl(opcode, args) < 0) ? adp_failed : adp_ok;
393 bool DevSW_WriteFinished(const DeviceDescr *device)
395 struct DriverCall *dc;
396 struct data_packet *dp;
398 dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
401 return (dp == NULL || dp->data == NULL);