|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <usb/usblogger.h> |
|
19 #include "AcmWriter.h" |
|
20 #include "AcmPort.h" |
|
21 #include "AcmPanic.h" |
|
22 #include "AcmUtils.h" |
|
23 |
|
24 #ifdef __FLOG_ACTIVE |
|
25 _LIT8(KLogComponent, "ECACM"); |
|
26 #endif |
|
27 |
|
28 CAcmWriter* CAcmWriter::NewL(CAcmPort& aPort, |
|
29 TUint aBufSize) |
|
30 /** |
|
31 * Factory function. |
|
32 * |
|
33 * @param aPort Owning CAcmPort object. |
|
34 * @param aBufSize Required buffer size. |
|
35 * @return Ownership of a newly created CAcmWriter object |
|
36 */ |
|
37 { |
|
38 LOG_STATIC_FUNC_ENTRY |
|
39 |
|
40 CAcmWriter* self = new(ELeave) CAcmWriter(aPort, aBufSize); |
|
41 CleanupStack::PushL(self); |
|
42 self->ConstructL(); |
|
43 CLEANUPSTACK_POP(self); |
|
44 return self; |
|
45 } |
|
46 |
|
47 CAcmWriter::~CAcmWriter() |
|
48 /** |
|
49 * Destructor. |
|
50 */ |
|
51 { |
|
52 LOG_FUNC |
|
53 |
|
54 WriteCancel(); |
|
55 |
|
56 delete iBuffer; |
|
57 } |
|
58 |
|
59 void CAcmWriter::Write(const TAny* aClientBuffer, TUint aLength) |
|
60 /** |
|
61 * Queue a write. |
|
62 * |
|
63 * @param aClientBuffer pointer to the Client's buffer |
|
64 * @param aLength Number of bytes to write |
|
65 */ |
|
66 { |
|
67 LOGTEXT3(_L8("CAcmWriter::Write aClientBuffer=0x%08x, aLength=%d"), |
|
68 aClientBuffer, aLength); |
|
69 |
|
70 // Check we're open to requests and make a note of interesting data. |
|
71 CheckNewRequest(aClientBuffer, aLength); |
|
72 |
|
73 // If the write size greater than the current buffer size then the |
|
74 // request will now complete over multiple operations. (This used to |
|
75 // simply reject the write request with KErrNoMemory) |
|
76 |
|
77 // Get as much data as we can from the client into our buffer |
|
78 ReadDataFromClient(); |
|
79 // ...and write as much as we've got to the LDD |
|
80 IssueWrite(); |
|
81 } |
|
82 |
|
83 void CAcmWriter::WriteCancel() |
|
84 /** |
|
85 * Cancel a write. |
|
86 */ |
|
87 { |
|
88 LOG_FUNC |
|
89 |
|
90 // Cancel any outstanding request on the LDD. |
|
91 if ( iPort.Acm() ) |
|
92 { |
|
93 LOGTEXT(_L8("\tiPort.Acm() exists- calling WriteCancel on it")); |
|
94 iPort.Acm()->WriteCancel(); |
|
95 } |
|
96 |
|
97 // Reset our flag to say there's no current outstanding request. What's |
|
98 // already in our buffer can stay there. |
|
99 iCurrentRequest.iClientPtr = NULL; |
|
100 } |
|
101 |
|
102 void CAcmWriter::ResetBuffer() |
|
103 /** |
|
104 * Called by the port to clear the buffer. |
|
105 */ |
|
106 { |
|
107 LOG_FUNC |
|
108 |
|
109 // A request is outstanding- C32 should protect against this. |
|
110 __ASSERT_DEBUG(!iCurrentRequest.iClientPtr, |
|
111 _USB_PANIC(KAcmPanicCat, EPanicInternalError)); |
|
112 |
|
113 // Don't have anything to do. There are no pointers to reset. This |
|
114 // function may in the future (if we support KConfigWriteBufferedComplete) |
|
115 // do work, so leave the above assertion in. |
|
116 } |
|
117 |
|
118 TInt CAcmWriter::SetBufSize(TUint aSize) |
|
119 /** |
|
120 * Called by the port to set the buffer size. Also used as a utility by us to |
|
121 * create the buffer at instantiation. |
|
122 * |
|
123 * @param aSize The required size of the buffer. |
|
124 */ |
|
125 { |
|
126 LOG_FUNC |
|
127 LOGTEXT2(_L8("\taSize=%d"), aSize); |
|
128 |
|
129 if ( iCurrentRequest.iClientPtr ) |
|
130 { |
|
131 // A request is outstanding. C32 does not protect us against this. |
|
132 LOGTEXT(_L8("\t***a request is outstanding- returning KErrInUse")); |
|
133 return KErrInUse; |
|
134 } |
|
135 |
|
136 // Create the new buffer. |
|
137 HBufC8* newBuf = HBufC8::New(static_cast<TInt>(aSize)); |
|
138 if ( !newBuf ) |
|
139 { |
|
140 LOGTEXT(_L8("\tfailed to create new buffer- returning KErrNoMemory")); |
|
141 return KErrNoMemory; |
|
142 } |
|
143 delete iBuffer; |
|
144 iBuffer = newBuf; |
|
145 iBuf.Set(iBuffer->Des()); |
|
146 iBufSize = aSize; |
|
147 |
|
148 return KErrNone; |
|
149 } |
|
150 |
|
151 CAcmWriter::CAcmWriter(CAcmPort& aPort, |
|
152 TUint aBufSize) |
|
153 /** |
|
154 * Constructor. |
|
155 * |
|
156 * @param aPort The CPort parent. |
|
157 * @param aBufSize The size of the buffer. |
|
158 */ |
|
159 : iBufSize(aBufSize), |
|
160 iBuf(NULL,0,0), |
|
161 iPort(aPort) |
|
162 { |
|
163 } |
|
164 |
|
165 void CAcmWriter::ConstructL() |
|
166 /** |
|
167 * 2nd-phase constructor. |
|
168 */ |
|
169 { |
|
170 // Create the required buffer. |
|
171 LOGTEXT(_L8("\tabout to create iBuffer")); |
|
172 LEAVEIFERRORL(SetBufSize(iBufSize)); |
|
173 } |
|
174 |
|
175 void CAcmWriter::WriteCompleted(TInt aError) |
|
176 /** |
|
177 * This function is called when a write on the LDD has completed. |
|
178 * This checks whether any data remains to be written, if so the |
|
179 * read and write requests are re-issued until there in no data |
|
180 * left or an error occurs. |
|
181 * |
|
182 * @param aError Error with which the write completed. |
|
183 */ |
|
184 { |
|
185 LOG_FUNC |
|
186 LOGTEXT2(_L8("\taError=%d"), aError); |
|
187 |
|
188 if(iLengthToGo == 0 || aError != KErrNone) |
|
189 { |
|
190 LOGTEXT2(_L8("\tcompleting request with %d"), aError); |
|
191 CompleteRequest(aError); |
|
192 } |
|
193 else |
|
194 { |
|
195 //there is some data remaining to be read so reissue the Read & Write |
|
196 //requests until there is no data left. |
|
197 ReadDataFromClient(); |
|
198 IssueWrite(); |
|
199 } |
|
200 } |
|
201 |
|
202 void CAcmWriter::ReadDataFromClient() |
|
203 /** |
|
204 * Read data from the client space into the internal buffer, prior to writing. |
|
205 */ |
|
206 { |
|
207 LOG_FUNC |
|
208 TPtr8 ptr((TUint8*)iBuf.Ptr(), |
|
209 0, |
|
210 Min(iBuf.MaxLength(), iLengthToGo)); |
|
211 |
|
212 TInt err = iPort.IPCRead(iCurrentRequest.iClientPtr, |
|
213 ptr, |
|
214 static_cast<TInt>(iOffsetIntoClientsMemory)); |
|
215 LOGTEXT2(_L8("\tIPCRead = %d"), err); |
|
216 iBuf.SetLength(ptr.Length()); |
|
217 __ASSERT_DEBUG(!err, _USB_PANIC(KAcmPanicCat, EPanicInternalError)); |
|
218 |
|
219 static_cast<void>(err); |
|
220 |
|
221 // Increase our pointer (into the client's space) of already-read data. |
|
222 iOffsetIntoClientsMemory += iBuf.Length(); |
|
223 } |
|
224 |
|
225 |
|
226 |
|
227 void CAcmWriter::CheckNewRequest(const TAny* aClientBuffer, TUint aLength) |
|
228 /** |
|
229 * Utility function to check a new request from the port. |
|
230 * Also checks that there isn't a request already outstanding. Makes a note of |
|
231 * the relevant parameters and sets up internal counters. |
|
232 * |
|
233 * @param aClientBuffer Pointer to the client's memory space. |
|
234 * @param aLength Length to write. |
|
235 */ |
|
236 { |
|
237 LOG_FUNC |
|
238 |
|
239 __ASSERT_DEBUG(aLength <= static_cast<TUint>(KMaxTInt), |
|
240 _USB_PANIC(KAcmPanicCat, EPanicInternalError)); |
|
241 |
|
242 // Check we have no outstanding request already. |
|
243 if ( iCurrentRequest.iClientPtr ) |
|
244 { |
|
245 _USB_PANIC(KAcmPanicCat, EPanicInternalError); |
|
246 } |
|
247 // Sanity check on what C32 gave us. |
|
248 __ASSERT_DEBUG(aClientBuffer, |
|
249 _USB_PANIC(KAcmPanicCat, EPanicInternalError)); |
|
250 |
|
251 // Make a note of interesting data. |
|
252 iCurrentRequest.iLength = aLength; |
|
253 iCurrentRequest.iClientPtr = aClientBuffer; |
|
254 |
|
255 iLengthToGo = aLength; |
|
256 iOffsetIntoClientsMemory = 0; |
|
257 } |
|
258 |
|
259 void CAcmWriter::CompleteRequest(TInt aError) |
|
260 /** |
|
261 * Utility to reset our 'outstanding request' flag and complete the client's |
|
262 * request back to them. |
|
263 * |
|
264 * @param aError The error code to complete with. |
|
265 */ |
|
266 { |
|
267 LOGTEXT2(_L8("CAcmWriter::CompleteRequest aError=%d"), aError); |
|
268 |
|
269 // Set our flag to say that we no longer have an outstanding request. |
|
270 iCurrentRequest.iClientPtr = NULL; |
|
271 |
|
272 LOGTEXT2(_L8("\tcalling WriteCompleted with %d"), aError); |
|
273 iPort.WriteCompleted(aError); |
|
274 } |
|
275 |
|
276 void CAcmWriter::IssueWrite() |
|
277 /** |
|
278 * Writes a batch of data from our buffer to the LDD. Currently writes the |
|
279 * entire load of buffered data in one go. |
|
280 */ |
|
281 { |
|
282 LOG_FUNC |
|
283 |
|
284 LOGTEXT2(_L8("\tissuing Write of %d bytes"), iBuf.Length()); |
|
285 __ASSERT_DEBUG(iPort.Acm(), |
|
286 _USB_PANIC(KAcmPanicCat, EPanicInternalError)); |
|
287 iPort.Acm()->Write(*this, |
|
288 iBuf, |
|
289 iBuf.Length()); |
|
290 |
|
291 #ifdef DEBUG |
|
292 // A Zero Length Packet is an acceptable packet so iBuf.Length == 0 is acceptable, |
|
293 // if we receive this and the request length > 0 then we may have a problem so check |
|
294 // that the LengthToGo is also 0, if it is not then we may end up looping through this |
|
295 // code until a driver write error occurs which may never happen. |
|
296 // This is not expected to occur but the test is in here just to be safe. |
|
297 if(iBuf.Length() == 0 && iCurrentRequest.Length() != 0 && iLengthToGo != 0) |
|
298 { |
|
299 _USB_PANIC(KAcmPanicCat, EPanicInternalError); |
|
300 } |
|
301 #endif |
|
302 // Update our counter of remaining data to write. |
|
303 iLengthToGo -= iBuf.Length(); |
|
304 } |
|
305 |
|
306 // |
|
307 // End of file |