]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/SnpDxe/Transmit.c
rename
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Transmit.c
1 /** @file
2 Copyright (c) 2004 - 2007, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 Module name:
12
13 transmit.c
14
15 Abstract:
16
17 Revision history:
18 2000-Feb-03 M(f)J Genesis.
19
20 **/
21
22 #include "Snp.h"
23
24
25 /**
26 This routine calls undi to create the meadia header for the given data buffer.
27
28 @param snp pointer to SNP driver structure
29 @param MacHeaderPtr address where the media header will be filled in.
30 @param MacHeaderSize size of the memory at MacHeaderPtr
31 @param BufferPtr data buffer pointer
32 @param BufferLength Size of data in the BufferPtr
33 @param DestinationAddrPtr address of the destination mac address buffer
34 @param SourceAddrPtr address of the source mac address buffer
35 @param ProtocolPtr address of the protocol type
36
37 @retval EFI_SUCCESS if successfully completed the undi call
38 @retval Other error return from undi call.
39
40 **/
41 STATIC
42 EFI_STATUS
43 pxe_fillheader (
44 SNP_DRIVER *snp,
45 VOID *MacHeaderPtr,
46 UINTN MacHeaderSize,
47 VOID *BufferPtr,
48 UINTN BufferLength,
49 EFI_MAC_ADDRESS *DestinationAddrPtr,
50 EFI_MAC_ADDRESS *SourceAddrPtr,
51 UINT16 *ProtocolPtr
52 )
53 {
54 PXE_CPB_FILL_HEADER_FRAGMENTED *cpb;
55
56 cpb = snp->cpb;
57 if (SourceAddrPtr) {
58 CopyMem (
59 (VOID *) cpb->SrcAddr,
60 (VOID *) SourceAddrPtr,
61 snp->mode.HwAddressSize
62 );
63 } else {
64 CopyMem (
65 (VOID *) cpb->SrcAddr,
66 (VOID *) &(snp->mode.CurrentAddress),
67 snp->mode.HwAddressSize
68 );
69 }
70
71 CopyMem (
72 (VOID *) cpb->DestAddr,
73 (VOID *) DestinationAddrPtr,
74 snp->mode.HwAddressSize
75 );
76
77 //
78 // we need to do the byte swapping
79 //
80 cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
81
82 cpb->PacketLen = (UINT32) (BufferLength);
83 cpb->MediaHeaderLen = (UINT16) MacHeaderSize;
84
85 cpb->FragCnt = 2;
86 cpb->reserved = 0;
87
88 cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;
89 cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize;
90 cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;
91 cpb->FragDesc[1].FragLen = (UINT32) BufferLength;
92
93 cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;
94
95 snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER;
96 snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
97
98 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
99 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
100
101 snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
102 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
103
104 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
105 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
106 snp->cdb.IFnum = snp->if_num;
107 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
108
109 //
110 // Issue UNDI command and check result.
111 //
112 DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() "));
113
114 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
115
116 switch (snp->cdb.StatCode) {
117 case PXE_STATCODE_SUCCESS:
118 return EFI_SUCCESS;
119
120 case PXE_STATCODE_INVALID_PARAMETER:
121 DEBUG (
122 (EFI_D_ERROR,
123 "\nsnp->undi.fill_header() %xh:%xh\n",
124 snp->cdb.StatFlags,
125 snp->cdb.StatCode)
126 );
127
128 return EFI_INVALID_PARAMETER;
129
130 default:
131 DEBUG (
132 (EFI_D_ERROR,
133 "\nsnp->undi.fill_header() %xh:%xh\n",
134 snp->cdb.StatFlags,
135 snp->cdb.StatCode)
136 );
137
138 return EFI_DEVICE_ERROR;
139 }
140 }
141
142
143 /**
144 This routine calls undi to transmit the given data buffer
145
146 @param snp pointer to SNP driver structure
147 @param BufferPtr data buffer pointer
148 @param BufferLength Size of data in the BufferPtr
149
150 @retval EFI_SUCCESS if successfully completed the undi call
151 @retval Other error return from undi call.
152
153 **/
154 STATIC
155 EFI_STATUS
156 pxe_transmit (
157 SNP_DRIVER *snp,
158 VOID *BufferPtr,
159 UINTN BufferLength
160 )
161 {
162 PXE_CPB_TRANSMIT *cpb;
163 EFI_STATUS Status;
164
165 cpb = snp->cpb;
166 cpb->FrameAddr = (UINT64) (UINTN) BufferPtr;
167 cpb->DataLen = (UINT32) BufferLength;
168
169 cpb->MediaheaderLen = 0;
170 cpb->reserved = 0;
171
172 snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
173
174 snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT);
175 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
176
177 snp->cdb.OpCode = PXE_OPCODE_TRANSMIT;
178 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
179 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
180
181 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
182 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
183 snp->cdb.IFnum = snp->if_num;
184 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
185
186 //
187 // Issue UNDI command and check result.
188 //
189 DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() "));
190 DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode));
191 DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));
192 DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr));
193 DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr));
194
195 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
196
197 DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() "));
198 DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));
199
200 //
201 // we will unmap the buffers in get_status call, not here
202 //
203 switch (snp->cdb.StatCode) {
204 case PXE_STATCODE_SUCCESS:
205 return EFI_SUCCESS;
206
207 case PXE_STATCODE_QUEUE_FULL:
208 case PXE_STATCODE_BUSY:
209 Status = EFI_NOT_READY;
210 break;
211
212 default:
213 Status = EFI_DEVICE_ERROR;
214 }
215
216 DEBUG (
217 (EFI_D_ERROR,
218 "\nsnp->undi.transmit() %xh:%xh\n",
219 snp->cdb.StatFlags,
220 snp->cdb.StatCode)
221 );
222
223 return Status;
224 }
225
226
227 /**
228 This is the snp interface routine for transmitting a packet. this routine
229 basically retrieves the snp structure, checks the snp state and calls
230 pxe_fill_header and pxe_transmit calls to complete the transmission.
231
232 @param this pointer to SNP driver context
233 @param MacHeaderSize size of the memory at MacHeaderPtr
234 @param BufferLength Size of data in the BufferPtr
235 @param BufferPtr data buffer pointer
236 @param SourceAddrPtr address of the source mac address buffer
237 @param DestinationAddrPtr address of the destination mac address buffer
238 @param ProtocolPtr address of the protocol type
239
240 @retval EFI_SUCCESS if successfully completed the undi call
241 @retval Other error return from undi call.
242
243 **/
244 EFI_STATUS
245 EFIAPI
246 snp_undi32_transmit (
247 IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
248 IN UINTN MacHeaderSize,
249 IN UINTN BufferLength,
250 IN VOID *BufferPtr,
251 IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
252 IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
253 IN UINT16 *ProtocolPtr OPTIONAL
254 )
255 {
256 SNP_DRIVER *snp;
257 EFI_STATUS Status;
258 EFI_TPL OldTpl;
259
260 if (this == NULL) {
261 return EFI_INVALID_PARAMETER;
262 }
263
264 snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
265
266 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
267
268 if (snp == NULL) {
269 return EFI_DEVICE_ERROR;
270 }
271
272 switch (snp->mode.State) {
273 case EfiSimpleNetworkInitialized:
274 break;
275
276 case EfiSimpleNetworkStopped:
277 Status = EFI_NOT_STARTED;
278 goto ON_EXIT;
279
280 default:
281 Status = EFI_DEVICE_ERROR;
282 goto ON_EXIT;
283 }
284
285 if (BufferPtr == NULL) {
286 Status = EFI_INVALID_PARAMETER;
287 goto ON_EXIT;
288 }
289
290 if (BufferLength < snp->mode.MediaHeaderSize) {
291 Status = EFI_BUFFER_TOO_SMALL;
292 goto ON_EXIT;
293 }
294
295 //
296 // if the MacHeaderSize is non-zero, we need to fill up the header and for that
297 // we need the destination address and the protocol
298 //
299 if (MacHeaderSize != 0) {
300 if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {
301 Status = EFI_INVALID_PARAMETER;
302 goto ON_EXIT;
303 }
304
305 Status = pxe_fillheader (
306 snp,
307 BufferPtr,
308 MacHeaderSize,
309 (UINT8 *) BufferPtr + MacHeaderSize,
310 BufferLength - MacHeaderSize,
311 DestinationAddrPtr,
312 SourceAddrPtr,
313 ProtocolPtr
314 );
315
316 if (EFI_ERROR (Status)) {
317 goto ON_EXIT;
318 }
319 }
320
321 Status = pxe_transmit (snp, BufferPtr, BufferLength);
322
323 ON_EXIT:
324 gBS->RestoreTPL (OldTpl);
325
326 return Status;
327 }