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
);
272 AdpErrs
DevSW_Read(const DeviceDescr
*device
, const DevChanID type
,
273 Packet
**packet
, bool block
)
276 DevSWState
*ds
= device
->SwitcherState
;
279 * To try to get information out of the device driver as
280 * quickly as possible, we try and read more packets, even
281 * if a completed packet is already available.
285 * have we got a packet currently pending?
287 if (ds
->ds_nextreadpacket
== NULL
)
291 if (initialise_read(ds
) < 0) {
293 * we failed to initialise the next packet, but can
294 * still return a packet that has already arrived.
296 *packet
= Adp_removeFromQueue(&ds
->ds_readqueue
[type
]);
299 read_err
= device
->DeviceRead(&ds
->ds_activeread
, block
);
303 * driver has pulled in a complete packet, queue it up
306 printf("got a complete packet\n");
309 *packet
= Adp_removeFromQueue(&ds
->ds_readqueue
[type
]);
313 * OK, return the head of the read queue for the given type
315 /* enqueue_packet(ds); */
316 *packet
= Adp_removeFromQueue(&ds
->ds_readqueue
[type
]);
320 printf("got a bad packet\n");
324 return adp_bad_packet
;
326 panic("DevSW_Read: bad read status %d", read_err
);
328 return 0; /* get rid of a potential compiler warning */
332 AdpErrs
DevSW_FlushPendingWrite(const DeviceDescr
*device
)
334 struct DriverCall
*dc
;
335 struct data_packet
*dp
;
337 dc
= &((DevSWState
*)(device
->SwitcherState
))->ds_activewrite
;
341 * try to flush any packet that is still being written
343 if (dp
->data
!= NULL
)
345 flush_packet(device
, dc
);
347 /* see if it has gone */
348 if (dp
->data
!= NULL
)
349 return adp_write_busy
;
358 AdpErrs
DevSW_Write(const DeviceDescr
*device
, Packet
*packet
, DevChanID type
)
360 struct DriverCall
*dc
;
361 struct data_packet
*dp
;
363 dc
= &((DevSWState
*)(device
->SwitcherState
))->ds_activewrite
;
366 if (illegalDevChanID(type
))
367 return adp_illegal_args
;
370 * try to flush any packet that is still being written
372 if (DevSW_FlushPendingWrite(device
) != adp_ok
)
373 return adp_write_busy
;
376 * we can take this packet - set things up, then try to get rid of it
378 initialise_write(dc
, packet
, type
);
379 flush_packet(device
, dc
);
384 AdpErrs
DevSW_Ioctl(const DeviceDescr
*device
, const int opcode
, void *args
)
386 return (device
->DeviceIoctl(opcode
, args
) < 0) ? adp_failed
: adp_ok
;
389 bool DevSW_WriteFinished(const DeviceDescr
*device
)
391 struct DriverCall
*dc
;
392 struct data_packet
*dp
;
394 dc
= &((DevSWState
*)(device
->SwitcherState
))->ds_activewrite
;
397 return (dp
== NULL
|| dp
->data
== NULL
);
This page took 0.037904 seconds and 5 git commands to generate.