3 Copyright (C) 2000-2011 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <exec/types.h>
24 #include <utility/tagitem.h>
25 #include <utility/hooks.h>
26 #include <libraries/poseidon.h>
27 #include <devices/usb.h>
29 #include <proto/exec.h>
30 #include <proto/utility.h>
31 #include <proto/poseidon.h>
32 #include <proto/alib.h>
35 #include "realtek8187.h"
37 #include "usb_protos.h"
38 #include "device_protos.h"
39 #include "unit_protos.h"
45 struct DevBase
*device
;
47 struct Hook unbind_hook
;
49 struct MsgPort
*msg_port
;
50 struct MsgPort
*tx_pipe_port
;
51 struct MsgPort
*rx_pipe_port
;
53 APTR tx_pipes
[TX_SLOT_COUNT
];
54 APTR rx_pipes
[RX_SLOT_COUNT
];
55 struct Interrupt tx_pipe_int
;
56 struct Interrupt rx_pipe_int
;
60 /* Private prototypes */
62 static struct DevUnit
*FindUSBUnit(ULONG index
, struct DevBase
*base
);
63 static struct DevUnit
*CreateUSBUnit(ULONG index
,
64 struct DevBase
*base
);
65 static VOID
DeleteUSBUnitInternal(struct BusContext
*context
,
66 struct DevBase
*base
);
67 static struct BusContext
*AllocDevice(ULONG index
, struct DevBase
*base
);
68 static VOID
FreeDevice(struct BusContext
*context
, struct DevBase
*base
);
69 static BOOL
IsDeviceCompatible(UWORD vendor_id
, UWORD product_id
,
70 struct DevBase
*base
);
71 static VOID
ReleaseBindingHook(struct Hook
*hook
, APTR object
,
73 static VOID
TXPipeInt(REG(a1
, struct BusContext
*context
),
74 REG(a5
, APTR int_code
));
75 static VOID
RXPipeInt(REG(a1
, struct BusContext
*context
),
76 REG(a5
, APTR int_code
));
77 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
);
78 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
80 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
);
81 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
);
82 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
84 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
86 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
88 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
);
89 static VOID
SendFrameHook(struct BusContext
*context
, APTR data
,
91 static VOID
ReceiveFrameHook(struct BusContext
*context
, APTR buffer
,
95 static const UWORD product_codes
[] =
97 // 0x03f0, 0xca02 // L
99 // 0x0769, 0x11f2, // L
100 // 0x0789, 0x010c, // L
102 // 0x0846, 0x6100, // L
103 // 0x0846, 0x6a00, // L
104 // 0x0b05, 0x171d, // L
105 // 0x0bda, 0x8187, // L
109 // 0x0df6, 0x000d, // L
112 // 0x114b, 0x0150, // L
113 // 0x1371, 0x9401, // L
114 // 0x13d1, 0xabe6, // L
116 // 0x18e8, 0x6232, // L
117 // 0x1b75, 0x8187 // L
122 static const struct TagItem unit_tags
[] =
124 {IOTAG_ByteIn
, (UPINT
)ByteInHook
},
125 {IOTAG_ByteOut
, (UPINT
)ByteOutHook
},
126 {IOTAG_LEWordIn
, (UPINT
)LEWordInHook
},
127 {IOTAG_LELongIn
, (UPINT
)LELongInHook
},
128 {IOTAG_LEWordOut
, (UPINT
)LEWordOutHook
},
129 {IOTAG_LELongOut
, (UPINT
)LELongOutHook
},
130 {IOTAG_AllocDMAMem
, (UPINT
)AllocDMAMemHook
},
131 {IOTAG_FreeDMAMem
, (UPINT
)FreeDMAMemHook
},
132 {IOTAG_SendFrame
, (UPINT
)SendFrameHook
},
133 {IOTAG_ReceiveFrame
, (UPINT
)ReceiveFrameHook
},
138 /****i* realtek8180.device/GetUSBCount *************************************
141 * GetUSBCount -- Get the number of compatible USB devices.
144 * count = GetUSBCount()
146 * ULONG GetUSBCount();
148 ****************************************************************************
152 ULONG
GetUSBCount(struct DevBase
*base
)
156 UPINT vendor_id
, product_id
;
159 while((device
= psdGetNextDevice(device
)) != NULL
)
161 psdGetAttrs(PGA_DEVICE
, device
, DA_VendorID
, (UPINT
)&vendor_id
,
162 DA_ProductID
, (UPINT
)&product_id
, TAG_END
);
163 if(IsDeviceCompatible(vendor_id
, product_id
, base
))
173 /****i* realtek8180.device/GetUSBUnit **************************************
176 * GetUSBUnit -- Get a unit by number.
179 * unit = GetUSBUnit(index)
181 * struct DevUnit *GetUSBUnit(ULONG);
183 ****************************************************************************
187 struct DevUnit
*GetUSBUnit(ULONG index
, struct DevBase
*base
)
189 struct DevUnit
*unit
;
191 unit
= FindUSBUnit(index
, base
);
195 unit
= CreateUSBUnit(index
, base
);
197 AddTail((APTR
)&base
->usb_units
, (APTR
)unit
);
205 /****i* realtek8180.device/FindUSBUnit *************************************
208 * FindUSBUnit -- Find a unit by number.
211 * unit = FindUSBUnit(index)
213 * struct DevUnit *FindUSBUnit(ULONG);
215 ****************************************************************************
219 static struct DevUnit
*FindUSBUnit(ULONG index
, struct DevBase
*base
)
221 struct DevUnit
*unit
, *tail
;
223 unit
= (APTR
)base
->usb_units
.mlh_Head
;
224 tail
= (APTR
)&base
->usb_units
.mlh_Tail
;
233 /****i* realtek8180.device/CreateUSBUnit ***********************************
236 * CreateUSBUnit -- Create a unit.
239 * unit = CreateUSBUnit(index)
241 * struct DevUnit *CreateUSBUnit(ULONG);
244 * Creates a new unit.
246 ****************************************************************************
250 static struct DevUnit
*CreateUSBUnit(ULONG index
,
251 struct DevBase
*base
)
254 struct BusContext
*context
;
255 struct DevUnit
*unit
;
258 /* Get device from system */
260 context
= AllocDevice(index
, base
);
264 /* Create device driver unit */
268 context
->device
= base
;
269 context
->unit
= unit
=
270 CreateUnit(index
, context
, unit_tags
, USB_BUS
, base
);
277 if(!(WrapInt(&unit
->tx_int
, base
)
278 && WrapInt(&unit
->mgmt_int
, base
)
279 && WrapInt(&context
->tx_pipe_int
, base
)
280 && WrapInt(&context
->rx_pipe_int
, base
)))
284 /* Send out RX pipes */
288 for(i
= 0; i
< RX_SLOT_COUNT
; i
++)
289 psdSendPipe(context
->rx_pipes
[i
], unit
->rx_buffers
[i
],
290 FRAME_BUFFER_SIZE
+ R8180_MAXDESCSIZE
);
296 DeleteUSBUnitInternal(context
, base
);
305 /****i* realtek8180.device/DeleteUSBUnit ***********************************
308 * DeleteUSBUnit -- Delete a unit.
311 * DeleteUSBUnit(unit)
313 * VOID DeleteUSBUnit(struct DevUnit *);
319 * unit - Device unit (may be NULL).
324 ****************************************************************************
328 VOID
DeleteUSBUnit(struct DevUnit
*unit
, struct DevBase
*base
)
331 DeleteUSBUnitInternal(unit
->card
, base
);
338 /****i* realtek8180.device/DeleteUSBUnitInternal ***************************
341 * DeleteUSBUnitInternal -- Delete a unit.
344 * DeleteUSBUnitInternal(context)
346 * VOID DeleteUSBUnitInternal(struct BusContext *);
357 ****************************************************************************
361 static VOID
DeleteUSBUnitInternal(struct BusContext
*context
,
362 struct DevBase
*base
)
364 struct DevUnit
*unit
;
368 unit
= context
->unit
;
373 context
->tx_pipe_port
->mp_Flags
= PA_SIGNAL
;
374 context
->tx_pipe_port
->mp_SigTask
= FindTask(NULL
);
375 for(i
= 0; i
< TX_SLOT_COUNT
; i
++)
377 pipe
= context
->tx_pipes
[i
];
385 context
->rx_pipe_port
->mp_Flags
= PA_SIGNAL
;
386 context
->rx_pipe_port
->mp_SigTask
= FindTask(NULL
);
387 for(i
= 0; i
< RX_SLOT_COUNT
; i
++)
389 pipe
= context
->rx_pipes
[i
];
397 /* Remove interrupt wrapper code */
399 UnwrapInt(&context
->rx_pipe_int
, base
);
400 UnwrapInt(&context
->tx_pipe_int
, base
);
401 UnwrapInt(&unit
->mgmt_int
, base
);
402 UnwrapInt(&unit
->tx_int
, base
);
404 /* Shut down unit and release hardware */
406 DeleteUnit(unit
, base
);
407 context
->unit
= NULL
;
409 FreeDevice(context
, base
);
416 /****i* realtek8180.device/AllocDevice *************************************
419 * AllocDevice -- Take control of a device.
422 * context = AllocDevice(index)
424 * struct BusContext *AllocDevice(ULONG);
426 ****************************************************************************
430 static struct BusContext
*AllocDevice(ULONG index
, struct DevBase
*base
)
433 struct BusContext
*context
;
434 APTR device
= NULL
, interface
= NULL
, endpoint
;
436 UPINT vendor_id
, product_id
;
439 /* Allocate context */
441 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
447 context
->tx_pipe_port
= AllocVec(sizeof(struct MsgPort
),
448 MEMF_PUBLIC
| MEMF_CLEAR
);
449 context
->rx_pipe_port
= AllocVec(sizeof(struct MsgPort
),
450 MEMF_PUBLIC
| MEMF_CLEAR
);
451 if(context
->tx_pipe_port
== NULL
|| context
->rx_pipe_port
== NULL
)
457 NewList(&context
->tx_pipe_port
->mp_MsgList
);
458 context
->tx_pipe_port
->mp_Flags
= PA_SOFTINT
;
459 context
->tx_pipe_port
->mp_SigTask
= &context
->tx_pipe_int
;
461 context
->tx_pipe_int
.is_Node
.ln_Name
=
462 base
->device
.dd_Library
.lib_Node
.ln_Name
;
463 context
->tx_pipe_int
.is_Code
= (APTR
)TXPipeInt
;
464 context
->tx_pipe_int
.is_Data
= context
;
466 NewList(&context
->rx_pipe_port
->mp_MsgList
);
467 context
->rx_pipe_port
->mp_Flags
= PA_SOFTINT
;
468 context
->rx_pipe_port
->mp_SigTask
= &context
->rx_pipe_int
;
470 context
->rx_pipe_int
.is_Node
.ln_Name
=
471 base
->device
.dd_Library
.lib_Node
.ln_Name
;
472 context
->rx_pipe_int
.is_Code
= (APTR
)RXPipeInt
;
473 context
->rx_pipe_int
.is_Data
= context
;
475 context
->msg_port
= CreateMsgPort();
476 if(context
->msg_port
== NULL
)
482 /* Prepare unbinding hook */
484 hook
= &context
->unbind_hook
;
485 hook
->h_Entry
= HookEntry
;
486 hook
->h_SubEntry
= (APTR
)ReleaseBindingHook
;
487 hook
->h_Data
= context
;
489 /* Find a compatible device */
492 device
= psdGetNextDevice(NULL
);
493 while(i
<= index
&& device
!= NULL
)
495 psdGetAttrs(PGA_DEVICE
, device
, DA_VendorID
, (UPINT
)&vendor_id
,
496 DA_ProductID
, (UPINT
)&product_id
, TAG_END
);
497 if(IsDeviceCompatible(vendor_id
, product_id
, base
))
500 device
= psdGetNextDevice(device
);
503 /* Create binding to device */
506 context
->binding
= psdClaimAppBinding(ABA_ReleaseHook
, hook
,
507 ABA_Device
, device
, TAG_END
);
510 context
->usb_device
= device
;
511 if(device
== NULL
|| context
->binding
== NULL
)
519 interface
= psdFindInterface(device
, NULL
, TAG_END
);
520 if(interface
== NULL
)
526 /* Allocate endpoint pipes */
528 context
->control_pipe
= psdAllocPipe(device
, context
->msg_port
, NULL
);
529 if(context
->control_pipe
== NULL
)
532 endpoint
= psdFindEndpoint(interface
, NULL
, EA_IsIn
, FALSE
,
533 EA_TransferType
, USEAF_BULK
, EA_EndpointNum
, 4, TAG_END
);
534 for(i
= 0; i
< TX_SLOT_COUNT
; i
++)
536 context
->tx_pipes
[i
] =
537 psdAllocPipe(device
, context
->tx_pipe_port
, endpoint
);
538 if(context
->tx_pipes
[i
] == NULL
)
542 endpoint
= psdFindEndpoint(interface
, NULL
, EA_IsIn
, TRUE
,
543 EA_TransferType
, USEAF_BULK
, EA_EndpointNum
, 3, TAG_END
);
544 for(i
= 0; i
< RX_SLOT_COUNT
; i
++)
546 context
->rx_pipes
[i
] =
547 psdAllocPipe(device
, context
->rx_pipe_port
, endpoint
);
548 if(context
->rx_pipes
[i
] == NULL
)
555 FreeDevice(context
, base
);
564 /****i* realtek8180.device/FreeDevice **************************************
567 * FreeDevice -- Release a device.
570 * FreeDevice(context)
572 * VOID FreeDevice(struct BusContext *);
574 ****************************************************************************
578 static VOID
FreeDevice(struct BusContext
*context
, struct DevBase
*base
)
585 psdReleaseAppBinding(context
->binding
);
589 if(context
->control_pipe
!= NULL
)
590 psdFreePipe(context
->control_pipe
);
592 for(i
= 0; i
< TX_SLOT_COUNT
; i
++)
594 pipe
= context
->tx_pipes
[i
];
599 for(i
= 0; i
< RX_SLOT_COUNT
; i
++)
601 pipe
= context
->rx_pipes
[i
];
606 /* Free message ports */
608 FreeVec(context
->tx_pipe_port
);
609 FreeVec(context
->rx_pipe_port
);
610 DeleteMsgPort(context
->msg_port
);
614 FreeMem(context
, sizeof(struct BusContext
));
622 /****i* realtek8180.device/IsDeviceCompatible ******************************
628 * compatible = IsDeviceCompatible(vendor_id, product_id)
630 * BOOL IsDeviceCompatible(UWORD, UWORD);
632 ****************************************************************************
636 static BOOL
IsDeviceCompatible(UWORD vendor_id
, UWORD product_id
,
637 struct DevBase
*base
)
639 BOOL compatible
= FALSE
;
642 for(p
= product_codes
; p
[0] != 0; p
+= 2)
644 if(p
[0] == vendor_id
&& p
[1] == product_id
)
653 /****i* realtek8180.device/ReleaseBindingHook ******************************
659 * ReleaseBindingHook(hook, object, message)
661 * VOID ReleaseBindingHook(struct Hook *, APTR, APTR);
663 ****************************************************************************
667 static VOID
ReleaseBindingHook(struct Hook
*hook
, APTR object
, APTR message
)
669 struct DevBase
*base
;
670 struct DevUnit
*unit
;
671 struct BusContext
*context
;
673 /* Record loss of device and inform unit's task */
675 context
= hook
->h_Data
;
676 unit
= context
->unit
;
680 if((unit
->flags
& UNITF_ONLINE
) != 0)
681 unit
->flags
|= UNITF_WASONLINE
;
682 unit
->flags
&= ~(UNITF_HAVEADAPTER
| UNITF_ONLINE
);
683 Signal(unit
->task
, unit
->card_removed_signal
);
691 /****i* realtek8180.device/TXPipeInt ***************************************
697 * TXPipeInt(context, int_code)
699 * VOID TXPipeInt(struct BusContext *, APTR);
701 ****************************************************************************
705 static VOID
TXPipeInt(REG(a1
, struct BusContext
*context
),
706 REG(a5
, APTR int_code
))
708 struct DevBase
*base
;
709 struct DevUnit
*unit
;
712 unit
= context
->unit
;
715 while((pipe
= GetMsg(context
->tx_pipe_port
)) != NULL
)
716 RetireTXSlot(unit
, base
);
723 /****i* realtek8180.device/RXPipeInt ***************************************
729 * RXPipeInt(context, int_code)
731 * VOID RXPipeInt(struct BusContext *, APTR);
733 ****************************************************************************
737 static VOID
RXPipeInt(REG(a1
, struct BusContext
*context
),
738 REG(a5
, APTR int_code
))
740 struct DevBase
*base
;
741 struct DevUnit
*unit
;
745 unit
= context
->unit
;
748 while((pipe
= GetMsg(context
->rx_pipe_port
)) != NULL
)
750 if((unit
->flags
& UNITF_ONLINE
) != 0)
752 /* Find slot number for the pipe */
754 for(i
= 0; context
->rx_pipes
[i
] != pipe
&& i
< RX_SLOT_COUNT
; i
++);
755 unit
->rx_slot
= slot
= i
;
757 unit
->rx_descs
[slot
] = unit
->rx_buffers
[slot
]
758 + psdGetPipeActual(pipe
) - unit
->rx_desc_size
;
759 RXInt(context
->unit
, RXInt
);
768 /****i* realtek8180.device/ReadControlPipe *********************************
774 * mask = ReadControlPipe(context, )
776 * UBYTE ReadControlPipe(struct BusContext *, );
778 ****************************************************************************
782 static LONG
ReadControlPipe(struct BusContext
*context
, ULONG offset
,
783 APTR data
, ULONG length
, struct DevBase
*base
)
787 /* Patch pipe's message port to signal this task when finished */
789 context
->msg_port
->mp_SigTask
= FindTask(NULL
);
791 psdPipeSetup(context
->control_pipe
, URTF_IN
| URTF_DEVICE
| URTF_VENDOR
,
792 R8180UCMD_REG
, 0xfe00 + (0xffff & offset
), offset
>> 16);
793 ioerr
= psdDoPipe(context
->control_pipe
, data
, length
);
800 /****i* realtek8180.device/WriteControlPipe ********************************
806 * mask = WriteControlPipe(context, )
808 * UBYTE WriteControlPipe(struct BusContext *, );
810 ****************************************************************************
814 static LONG
WriteControlPipe(struct BusContext
*context
, ULONG offset
,
815 APTR data
, ULONG length
, struct DevBase
*base
)
819 /* Patch pipe's message port to signal this task when finished */
821 context
->msg_port
->mp_SigTask
= FindTask(NULL
);
823 psdPipeSetup(context
->control_pipe
, URTF_OUT
| URTF_DEVICE
| URTF_VENDOR
,
824 R8180UCMD_REG
, 0xfe00 + (offset
& 0xffff), offset
>> 16);
825 ioerr
= psdDoPipe(context
->control_pipe
, data
, length
);
832 /****i* realtek8180.device/ByteInHook **************************************
838 * value = ByteInHook(context, offset)
840 * UBYTE ByteInHook(struct BusContext *, ULONG);
842 ****************************************************************************
846 static UBYTE
ByteInHook(struct BusContext
*context
, ULONG offset
)
848 struct DevBase
*base
;
851 base
= context
->device
;
852 ReadControlPipe(context
, offset
, &value
, sizeof(value
), base
);
859 /****i* realtek8180.device/ByteOutHook *************************************
865 * ByteOutHook(context, offset, value)
867 * VOID ByteOutHook(struct BusContext *, ULONG, UBYTE);
869 ****************************************************************************
873 static VOID
ByteOutHook(struct BusContext
*context
, ULONG offset
,
876 struct DevBase
*base
;
878 base
= context
->device
;
879 WriteControlPipe(context
, offset
, &value
, sizeof(value
), base
);
886 /****i* realtek8180.device/LEWordInHook ************************************
892 * value = LEWordInHook(context, offset)
894 * UWORD LEWordInHook(struct BusContext *, ULONG);
896 ****************************************************************************
900 static UWORD
LEWordInHook(struct BusContext
*context
, ULONG offset
)
902 struct DevBase
*base
;
905 base
= context
->device
;
906 ReadControlPipe(context
, offset
, &value
, sizeof(value
), base
);
908 return LEWord(value
);
913 /****i* realtek8180.device/LELongInHook ************************************
919 * value = LELongInHook(context, offset)
921 * ULONG LELongInHook(struct BusContext *, ULONG);
923 ****************************************************************************
927 static ULONG
LELongInHook(struct BusContext
*context
, ULONG offset
)
929 struct DevBase
*base
;
932 base
= context
->device
;
933 ReadControlPipe(context
, offset
, &value
, sizeof(value
), base
);
935 return LELong(value
);
940 /****i* realtek8180.device/LEWordOutHook ***********************************
946 * LEWordOutHook(context, offset, value)
948 * VOID LEWordOutHook(struct BusContext *, ULONG, UWORD);
950 ****************************************************************************
954 static VOID
LEWordOutHook(struct BusContext
*context
, ULONG offset
,
957 struct DevBase
*base
;
959 base
= context
->device
;
960 value
= MakeLEWord(value
);
961 WriteControlPipe(context
, offset
, &value
, sizeof(value
), base
);
968 /****i* realtek8180.device/LELongOutHook ***********************************
974 * LELongOutHook(context, offset, value)
976 * VOID LELongOutHook(struct BusContext *, ULONG, ULONG);
978 ****************************************************************************
982 static VOID
LELongOutHook(struct BusContext
*context
, ULONG offset
,
985 struct DevBase
*base
;
987 base
= context
->device
;
988 value
= MakeLELong(value
);
989 WriteControlPipe(context
, offset
, &value
, sizeof(value
), base
);
996 /****i* realtek8180.device/AllocDMAMemHook *********************************
1002 * mem = AllocDMAMemHook(context, size, alignment)
1004 * APTR AllocDMAMemHook(struct BusContext *, UPINT, UWORD);
1006 ****************************************************************************
1010 static APTR
AllocDMAMemHook(struct BusContext
*context
, UPINT size
,
1013 struct DevBase
*base
;
1016 base
= context
->device
;
1017 mem
= AllocVec(size
, MEMF_PUBLIC
);
1024 /****i* realtek8180.device/FreeDMAMemHook **********************************
1030 * FreeDMAMemHook(context, mem)
1032 * VOID FreeDMAMemHook(struct BusContext *, APTR);
1034 ****************************************************************************
1038 static VOID
FreeDMAMemHook(struct BusContext
*context
, APTR mem
)
1040 struct DevBase
*base
;
1042 base
= context
->device
;
1050 /****i* realtek8180.device/SendFrameHook ***********************************
1056 * mask = SendFrameHook(context, frame, length) ???
1058 * UBYTE SendFrameHook(struct BusContext *, UBYTE *, ULONG); ???
1060 ****************************************************************************
1064 static VOID
SendFrameHook(struct BusContext
*context
, APTR data
,
1067 struct DevBase
*base
;
1068 struct DevUnit
*unit
;
1070 unit
= context
->unit
;
1071 base
= unit
->device
;
1073 psdSendPipe(context
->tx_pipes
[unit
->tx_in_slot
], data
, length
);
1080 /****i* realtek8180.device/ReceiveFrameHook ********************************
1086 * mask = ReceiveFrameHook(context, buffer, length) ???
1088 * UBYTE ReceiveFrameHook(struct BusContext *, UBYTE *, ULONG); ???
1090 ****************************************************************************
1094 static VOID
ReceiveFrameHook(struct BusContext
*context
, APTR buffer
,
1097 struct DevBase
*base
;
1098 struct DevUnit
*unit
;
1100 unit
= context
->unit
;
1101 base
= unit
->device
;
1103 psdSendPipe(context
->rx_pipes
[unit
->rx_slot
], buffer
, length
);