I had a quick look at the 3c589.device source code, and it looks good to me (I'd probably rewrite the basic device I/O code to be more paranoid, though, and the cleanup procedures in case of errors should be reworked).
So I've been having fun with sashimi and MiamiDX and at some point have tracked an issue with my driver's code freezing when calling S2_CopyToBuff hook. I will have a look into buffer management the MiamiDX provides when opening the device, but here's a piece of code (borrowed from the abovementioned 3c589 sources) that puzzles me.
An opener structure is being allocated:
/* Set up buffer-management structure and get hooks */
request->ios2_BufferManagement = opener = AllocVec (sizeof (struct Opener), MEMF_PUBLIC);
And then it is being filled using GetTagData () calls. If I get it right GetTagData () returns either found tag value or default value (second param). However, the same (uninitialized) opener->rx_function var is provided as the default value:
opener->rx_function = (APTR)GetTagData (rx_tags [i], (UPINT)opener->rx_function, tag_list);
This would probably make sense if the AllocVec () call used MEMF_CLEAR in addition to MEMF_PUBLIC, but this is not the case. Even if the allocated memory has been zeroed previously why not provide NULL as the default value? The same very source uses NULL just a couple lines of code further:
opener->filter_hook = (APTR)GetTagData (S2_PacketFilter, NULL, tag_list);
opener->dma_tx_function = (APTR)GetTagData (S2_DMACopyFromBuff32, NULL, tag_list);
Or perhaps there is some reason of (not) doing so?
Looked into cnetdevice assembler sources, default value is also NULL:
; get copyfrom functions:
move.l #S2_COPYFROMBUFF,d0
moveq #0,d1
move.l a2,a0
jsr _LVOGetTagData(a6)