|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24: *
25: * IONetworkData.cpp
26: */
27:
28: #include <libkern/c++/OSDictionary.h>
29: #include <libkern/c++/OSNumber.h>
30: #include <IOKit/assert.h>
31: #include <IOKit/IOLib.h>
32: #include <IOKit/network/IONetworkData.h>
33:
34: #define super OSData
35: OSDefineMetaClassAndStructors( IONetworkData, OSData )
36:
37: #define TAP_IS_VALID (_tapTarget && _tapAction)
38:
39: // All access method are serialized by a single global lock,
40: // shared among all IONetworkData instances.
41: //
42: static IOLock * gIONDLock = 0;
43: #define LOCK IOTakeLock(gIONDLock)
44: #define UNLOCK IOUnlock(gIONDLock)
45:
46: static const OSSymbol * gIONDDataKey;
47: static const OSSymbol * gIONDAccessKey;
48: static const OSSymbol * gIONDCapacityKey;
49:
50: //---------------------------------------------------------------------------
51: // IONetworkData class initializer.
52:
53: void IONetworkData::initialize()
54: {
55: // Allocates the global data lock.
56: //
57: gIONDLock = IOLockAlloc();
58: assert(gIONDLock);
59: IOLockInitWithState(gIONDLock, kIOLockStateUnlocked);
60:
61: gIONDDataKey = OSSymbol::withCStringNoCopy("Data");
62: gIONDAccessKey = OSSymbol::withCStringNoCopy("Access Flags");
63: gIONDCapacityKey = OSSymbol::withCStringNoCopy("Capacity");
64:
65: assert(gIONDDataKey && gIONDAccessKey && gIONDCapacityKey);
66: }
67:
68: //---------------------------------------------------------------------------
69: // Initialize an IONetworkData instance. A target/action may be
70: // registered to receive a notification when the read(), write(),
71: // reset(), or serialize() methods are called.
72: //
73: // name: A name assigned to this object.
74: //
75: // buffer: Pointer to an external data buffer. If 0,
76: // then an internal buffer shall be allocated.
77: //
78: // capacity: Capacity of the data buffer.
79: //
80: // accessFlags: Access flags.
81: // Can be later modified by calling setAccessFlags().
82: //
83: // target: Notification target. The target will be notified
84: // when IONetworkData receives a call to one of its
85: // access methods. If 0, then notification is disabled.
86: //
87: // action: Notification action. If 0, then notification is
88: // disabled.
89: //
90: // arg: An argument to passed to the notification action.
91: //
92: // Returns true if initialized successfully, false otherwise.
93:
94: bool
95: IONetworkData::initWithName(const char * name,
96: UInt32 inCapacity,
97: void * buffer = 0,
98: UInt32 accessFlags = kIONDBasicAccessTypes,
99: OSObject * target = 0,
100: Action action = 0,
101: void * arg = 0)
102: {
103: if ( ((buffer == 0) ?
104: super::initWithCapacity(inCapacity) :
105: super::initWithBytesNoCopy(buffer, inCapacity)) == false )
106: {
107: return false;
108: }
109:
110: _access = accessFlags;
111: _tapTarget = target;
112: _tapAction = action;
113: _tapArg = arg;
114: _capacity = inCapacity;
115: length = inCapacity; // (ivar in OSData) force length to maximum
116:
117: // Generate a key for this object based on its assigned name.
118: //
119: if ((_key = OSSymbol::withCString(name)) == 0)
120: return false;
121:
122: // Clear the data buffer.
123: //
124: clearBytes();
125:
126: return true;
127: }
128:
129: //---------------------------------------------------------------------------
130: // Factory method that will construct and initialize an IONetworkData
131: // instance.
132: //
133: // Returns an IONetworkData instance on success, or 0 otherwise.
134:
135: IONetworkData *
136: IONetworkData::withName(const char * name,
137: UInt32 inCapacity,
138: void * buffer = 0,
139: UInt32 accessFlags = kIONDBasicAccessTypes,
140: OSObject * target = 0,
141: Action action = 0,
142: void * arg = 0)
143: {
144: IONetworkData * aData = new IONetworkData;
145:
146: if (aData && !aData->initWithName(name, inCapacity, buffer, accessFlags,
147: target, action, arg))
148: {
149: aData->release();
150: aData = 0;
151: }
152: return aData;
153: }
154:
155: //---------------------------------------------------------------------------
156: // Free the IONetworkData instance.
157:
158: void IONetworkData::free()
159: {
160: if (_key)
161: _key->release();
162:
163: // Superclass will free the internal data buffer.
164:
165: super::free();
166: }
167:
168: //---------------------------------------------------------------------------
169: // Change the access flags.
170: //
171: // accessFlags: A bitfield of access flag bits.
172: // See IONDAccessFlags enum.
173:
174: void IONetworkData::setAccessFlags(UInt32 accessFlags)
175: {
176: LOCK;
177: _access = (_access & kIONDImmutableAccessFlags) |
178: (accessFlags & ~kIONDImmutableAccessFlags);
179: UNLOCK;
180: }
181:
182: //---------------------------------------------------------------------------
183: // Register a target/action to handle access notification.
184: // A notification is sent by an IONetworkData to the registered
185: // notification handler when an access method is called.
186: //
187: // target: The target object that implements the notification action.
188: // If 0, then notification will be disabled.
189: //
190: // action: The notification action. If 0, then notification will be disabled.
191: //
192: // arg: An optional argument passed to the notification handler.
193:
194: void IONetworkData::setNotificationTarget(OSObject * target,
195: Action action,
196: void * arg = 0)
197: {
198: LOCK;
199: _tapTarget = target;
200: _tapAction = action;
201: _tapArg = arg;
202: UNLOCK;
203: }
204:
205: //---------------------------------------------------------------------------
206: // Return a pointer to the data buffer.
207:
208: const void * IONetworkData::getBuffer() const
209: {
210: return getBytesNoCopy();
211: }
212:
213: //---------------------------------------------------------------------------
214: // Return the access flags.
215:
216: UInt32 IONetworkData::getAccessFlags() const
217: {
218: return _access;
219: }
220:
221: //---------------------------------------------------------------------------
222: // Return the notification target.
223:
224: OSObject * IONetworkData::getTarget() const
225: {
226: return _tapTarget;
227: }
228:
229: //---------------------------------------------------------------------------
230: // Return the notification action.
231:
232: IONetworkData::Action IONetworkData::getAction() const
233: {
234: return _tapAction;
235: }
236:
237: //---------------------------------------------------------------------------
238: // Return the notification argument.
239:
240: void * IONetworkData::getArgument() const
241: {
242: return _tapArg;
243: }
244:
245: //---------------------------------------------------------------------------
246: // Get an OSSymbol key associated with this IONetworkData instance.
247: // During initialization, IONetworkData will create an OSSymbol
248: // key based on its assigned name.
249: //
250: // Return an OSSymbol key generated from the assigned name.
251:
252: const OSSymbol * IONetworkData::getKey() const
253: {
254: return _key;
255: }
256:
257: //---------------------------------------------------------------------------
258: // Override the getCapacity() method inherited from OSData.
259: // This method overrides the implementation in OSData in
260: // order to report the capacity for both internal or external
261: // data buffers.
262: //
263: // Return the capacity of the data buffer in bytes.
264:
265: UInt IONetworkData::getCapacity() const
266: {
267: return _capacity;
268: }
269:
270: //---------------------------------------------------------------------------
271: // Update the data buffer from a source buffer provided by the
272: // caller.
273: //
274: // bytes: Pointer to a source buffer provided by the caller.
275: //
276: // inLength: Length of the source buffer, or the amount of data
277: // to copy to the data buffer. The length provided must
278: // be smaller than or equal to the capacity of the object.
279: //
280: // Returns true if the length of the source buffer is within limits, and
281: // the source buffer was copied, false otherwise.
282:
283: bool IONetworkData::setBytes(const void * bytes, UInt inLength)
284: {
285: if (inLength > _capacity)
286: return false; // specified buffer is too large.
287:
288: if (inLength == 0)
289: return true;
290:
291: bcopy(bytes, data, inLength);
292:
293: length = inLength; // set the new data length.
294:
295: return true;
296: }
297:
298: //---------------------------------------------------------------------------
299: // Set a new data buffer length to indicate the amount of
300: // valid data in the data buffer.
301: //
302: // inLength: Length of the data buffer in bytes. The length provided must
303: // be smaller than or equal to the capacity of the data object.
304: //
305: // Returns true if the length provided was accepted.
306:
307: bool IONetworkData::setLength(UInt inLength)
308: {
309: if (inLength > _capacity)
310: return false; // Length cannot exceed capacity.
311:
312: length = inLength;
313:
314: return true;
315: }
316:
317: //---------------------------------------------------------------------------
318: // Copy the data buffer (with length bytes) to a destination buffer
319: // provided by the caller.
320: //
321: // bytes: Pointer to a destination buffer.
322: //
323: // inOutLength: The caller must initialize the integer value pointed
324: // by inOutLength with the size of the destination buffer
325: // before the call. This method will overwrite it with the
326: // number of bytes copied.
327: //
328: // Returns true if the destination buffer is larger than or equal to the
329: // length of the data buffer, false otherwise.
330:
331: bool IONetworkData::copyBytes(void * bytes, UInt * inOutLength) const
332: {
333: if (length > *inOutLength)
334: return false; // specified buffer is too small.
335:
336: *inOutLength = length; // return the number of bytes copied.
337:
338: if (length)
339: bcopy(data, bytes, length);
340:
341: return true;
342: }
343:
344: //---------------------------------------------------------------------------
345: // Clear the entire data buffer and fill it with zeroes.
346: //
347: // Return true if the buffer was cleared, false otherwise.
348:
349: bool IONetworkData::clearBytes()
350: {
351: if (_capacity)
352: bzero(data, _capacity);
353:
354: return true;
355: }
356:
357: //---------------------------------------------------------------------------
358: // Handle a user space request to reset the data buffer. If notication
359: // is enabled, then the notification handler is called after the data
360: // buffer has been cleared
361: //
362: // Returns kIOReturnNotWritable if reset access is not allowed,
363: // kIOReturnSuccess otherwise. If a notification handler is called,
364: // and it returns an error code, then that error is returned.
365:
366: IOReturn IONetworkData::reset()
367: {
368: IOReturn ret = kIOReturnUnsupported;
369:
370: LOCK;
371:
372: do {
373: // Check access.
374: //
375: if ((_access & kIONDAccessTypeReset) == 0)
376: {
377: ret = kIOReturnNotWritable;
378: break;
379: }
380:
381: // Default action is to bzero the entire buffer.
382: //
383: if ((_access & kIONDAccessNoBufferAccess) == 0)
384: {
385: clearBytes();
386: ret = kIOReturnSuccess;
387: }
388:
389: // Notify our target.
390: //
391: if (TAP_IS_VALID)
392: {
393: ret = (_tapTarget->*_tapAction)(this,
394: (UInt32) kIONDAccessTypeReset,
395: _tapArg, 0, 0);
396: }
397: }
398: while (0);
399:
400: UNLOCK;
401:
402: return ret;
403: }
404:
405: //---------------------------------------------------------------------------
406: // Handle a user space request to read from the data buffer and copy it
407: // to the destination buffer provided. If notification is enabled,
408: // then the notification handler is called before the data buffer
409: // is copied to the destination buffer. The notification handler may
410: // use this opportunity to update the contents of the data buffer.
411: //
412: // inBuffer: Pointer to the destination buffer.
413: //
414: // inOutSize: Pointer to an integer containing the size of the destination
415: // buffer before the call. Overwritten by this method to the
416: // actual number of bytes copied to the destination buffer.
417: //
418: // Returns kIOReturnSuccess if success,
419: // kIOReturnBadArgument if an argument provided is invalid,
420: // kIOReturnNoSpace if the destination buffer is too small,
421: // kIOReturnNotReadable if read access is not permitted,
422: // or an error from the notification handler.
423:
424: IOReturn IONetworkData::read(void * inBuffer, UInt * inOutSize)
425: {
426: IOReturn ret = kIOReturnUnsupported;
427:
428: LOCK;
429:
430: do {
431: // Check the arguments.
432: //
433: if (!inBuffer || !inOutSize)
434: {
435: ret = kIOReturnBadArgument;
436: break;
437: }
438:
439: // Check access.
440: //
441: if ((_access & kIONDAccessTypeRead) == 0)
442: {
443: ret = kIOReturnNotReadable;
444: break;
445: }
446:
447: // Notify the target before the read operation.
448: // The target can take this opportunity to update the
449: // data buffer. If the target returns an error,
450: // abort and return the error.
451: //
452: if (TAP_IS_VALID)
453: {
454: ret = (_tapTarget->*_tapAction)(this,
455: (UInt32) kIONDAccessTypeRead,
456: _tapArg,
457: inBuffer,
458: (UInt32 *) inOutSize);
459: if (ret != kIOReturnSuccess)
460: break;
461: }
462:
463: if ((_access & kIONDAccessNoBufferAccess) == 0)
464: {
465: ret = (copyBytes(inBuffer, inOutSize) ?
466: kIOReturnSuccess : kIOReturnNoSpace);
467: }
468: }
469: while (0);
470:
471: UNLOCK;
472:
473: return ret;
474: }
475:
476: //---------------------------------------------------------------------------
477: // Handle a request to write to the data buffer from a source buffer provided.
478: // If notification is enabled, then the notification handler is called after
479: // the source buffer has been copied to the data buffer.
480: //
481: // inBuffer: Pointer to the source buffer.
482: //
483: // size: Size of the source buffer in bytes.
484: //
485: // Returns kIOReturnSuccess on success,
486: // kIOReturnBadArgument if an argument provided is invalid,
487: // kIOReturnNoSpace if the source buffer is too big,
488: // kIOReturnNotWritable if write access is not permitted,
489: // or an error from the notification handler.
490:
491: IOReturn IONetworkData::write(void * inBuffer, UInt size)
492: {
493: IOReturn ret = kIOReturnUnsupported;
494:
495: LOCK;
496:
497: do {
498: // Check the arguments.
499: //
500: if (!inBuffer)
501: {
502: ret = kIOReturnBadArgument;
503: break;
504: }
505:
506: // Check access.
507: //
508: if ((_access & kIONDAccessTypeWrite) == 0)
509: {
510: ret = kIOReturnNotWritable;
511: break;
512: }
513:
514: // Update the data buffer.
515: //
516: if ((_access & kIONDAccessNoBufferAccess) == 0)
517: {
518: ret = (setBytes(inBuffer, size)) ?
519: kIOReturnSuccess : kIOReturnNoSpace;
520:
521: if (ret != kIOReturnSuccess)
522: break;
523: }
524:
525: // Notify the target after a successful write operation.
526: //
527: if (TAP_IS_VALID)
528: {
529: ret = (_tapTarget->*_tapAction)(this,
530: (UInt32) kIONDAccessTypeWrite,
531: _tapArg,
532: inBuffer,
533: (UInt32 *) &size);
534: }
535: }
536: while (0);
537:
538: UNLOCK;
539:
540: return ret;
541: }
542:
543: //---------------------------------------------------------------------------
544: // Serialize the IONetworkData object. If notification is enabled,
545: // then the notification handler is called before the data buffer is
546: // serialized.
547: //
548: // s: An OSSerialize object.
549:
550: bool IONetworkData::serialize(OSSerialize * s) const
551: {
552: bool ok;
553: OSDictionary * dictToSerialize;
554: OSData * dataEntry;
555: OSNumber * numberEntry;
556:
557: dictToSerialize = OSDictionary::withCapacity(3);
558: if (!dictToSerialize)
559: return false;
560:
561: dataEntry = OSData::withBytesNoCopy((void *) &_access, sizeof(_access));
562: if (dataEntry) {
563: dictToSerialize->setObject(gIONDAccessKey, dataEntry);
564: dataEntry->release();
565: }
566:
567: numberEntry = OSNumber::withNumber(_capacity, sizeof(_capacity) * 8);
568: if (numberEntry) {
569: dictToSerialize->setObject(gIONDCapacityKey, numberEntry);
570: numberEntry->release();
571: }
572:
573: LOCK;
574:
575: do {
576: // Check access.
577: //
578: if ((_access & kIONDAccessTypeSerialize) == 0)
579: break;
580:
581: if (_access & kIONDAccessNoBufferAccess)
582: break;
583:
584: // Notify the target before the read operation.
585: // The target can take this opportunity to update the
586: // data buffer. If the target returns an error,
587: // then the data buffer is not serialized.
588: //
589: if (TAP_IS_VALID &&
590: ((_tapTarget->*_tapAction)((IONetworkData *) this,
591: kIONDAccessTypeSerialize,
592: _tapArg, 0, 0) != kIOReturnSuccess))
593: {
594: break;
595: }
596:
597: dataEntry = OSData::withBytesNoCopy(data, length);
598: if (dataEntry) {
599: dictToSerialize->setObject(gIONDDataKey, dataEntry);
600: dataEntry->release();
601: }
602: }
603: while (0);
604:
605: ok = dictToSerialize->serialize(s);
606: dictToSerialize->release();
607:
608: UNLOCK;
609:
610: return ok;
611: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.