1/*
2 * Copyright (c) 1998-2008 Apple 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#include <IOKit/assert.h>
24#include <IOKit/IOLib.h>
25#include <libkern/c++/OSObject.h>
26#include <libkern/c++/OSNumber.h>
27#include <libkern/c++/OSCollectionIterator.h>
28#include <libkern/c++/OSDictionary.h>
29#include <libkern/c++/OSSerialize.h>
30#include <IOKit/network/IONetworkMedium.h>
31
32//---------------------------------------------------------------------------
33// OSMetaClass macros.
34
35#define super OSObject
36OSDefineMetaClassAndStructors( IONetworkMedium, OSObject )
37OSMetaClassDefineReservedUnused( IONetworkMedium,  0);
38OSMetaClassDefineReservedUnused( IONetworkMedium,  1);
39OSMetaClassDefineReservedUnused( IONetworkMedium,  2);
40OSMetaClassDefineReservedUnused( IONetworkMedium,  3);
41
42//---------------------------------------------------------------------------
43// Initialize an IONetworkMedium instance.
44//
45// type:  The medium type, the fields are encoded with bits defined in
46//        IONetworkMedium.h.
47//
48// speed: The maximum (or the only) link speed supported over this medium
49//        in units of bits per second.
50//
51// flags: An optional flag for the medium object.
52//        See IONetworkMedium.h for defined flags.
53//
54// index: An optional 32-bit index assigned by the caller. Drivers can use
55//        this to store an index or a pointer to a media table inside the
56//        driver, or it may map to a driver defined media type.
57//
58// name:  An name to assign to this medium object. If 0, then a name
59//        will be created based on the medium type given using nameForType().
60//
61// Returns true on success, false otherwise.
62
63bool IONetworkMedium::init(IOMediumType  type,
64                           UInt64        speed,
65                           UInt32        flags,
66                           UInt32        index,
67                           const char *  name)
68{
69    if ( super::init() == false )
70        return false;
71
72    _type  = type;
73    _flags = flags;
74    _speed = speed;
75    _index = index;
76
77    if (name)
78        _name = OSSymbol::withCString(name);
79    else
80        _name = IONetworkMedium::nameForType(type);
81
82    if (!_name)
83        return false;
84
85    return true;
86}
87
88//---------------------------------------------------------------------------
89// Factory method which performs allocation and initialization
90// of an IONetworkMedium instance.
91//
92// Returns an IONetworkMedium instance on success, or 0 otherwise.
93
94IONetworkMedium * IONetworkMedium::medium(IOMediumType  type,
95                                          UInt64        speed,
96                                          UInt32        flags,
97                                          UInt32        index,
98                                          const char *  name)
99{
100    IONetworkMedium * medium = new IONetworkMedium;
101
102    if (medium && !medium->init(type, speed, flags, index, name))
103    {
104        medium->release();
105        medium = 0;
106    }
107
108    return medium;
109}
110
111//---------------------------------------------------------------------------
112// Free the IONetworkMedium instance.
113
114void IONetworkMedium::free()
115{
116    if (_name)
117    {
118        _name->release();
119        _name = 0;
120    }
121    super::free();
122}
123
124//---------------------------------------------------------------------------
125// Return the assigned medium type.
126
127IOMediumType IONetworkMedium::getType() const
128{
129    return _type;
130}
131
132//---------------------------------------------------------------------------
133// Return the medium flags.
134
135UInt32 IONetworkMedium::getFlags() const
136{
137    return _flags;
138}
139
140//---------------------------------------------------------------------------
141// Return the maximum medium speed.
142
143UInt64 IONetworkMedium::getSpeed() const
144{
145    return _speed;
146}
147
148//---------------------------------------------------------------------------
149// Return the assigned index.
150
151UInt32 IONetworkMedium::getIndex() const
152{
153    return _index;
154}
155
156//---------------------------------------------------------------------------
157// Return the name for this instance.
158
159const OSSymbol * IONetworkMedium::getName() const
160{
161    return _name;
162}
163
164//---------------------------------------------------------------------------
165// Given a medium type, create an unique OSymbol name for the medium.
166// The caller is responsible for releasing the OSSymbol object returned.
167//
168// type: A medium type. See IONetworkMedium.h for type encoding.
169//
170// Returns an OSSymbol created based on the type provided.
171
172const OSSymbol * IONetworkMedium::nameForType(IOMediumType type)
173{
174    char  buffer[10];
175
176    snprintf(buffer, sizeof(buffer), "%08x", (uint32_t) type);
177
178    // Caller must remember to free the OSSymbol!
179    //
180    return OSSymbol::withCString(buffer);
181}
182
183//---------------------------------------------------------------------------
184// Test for equality between two IONetworkMedium objects.
185// Two IONetworkMedium objects are considered equal if
186// they have similar properties assigned to them during initialization.
187//
188// medium: An IONetworkMedium to test against the IONetworkMedium
189//         object being called.
190//
191// Returns true if equal, false otherwise.
192
193bool IONetworkMedium::isEqualTo(const IONetworkMedium * medium) const
194{
195    return ( (medium->_name  == _name)  &&
196             (medium->_type  == _type)  &&
197             (medium->_flags == _flags) &&
198             (medium->_speed == _speed) &&
199             (medium->_index == _index) );
200}
201
202//---------------------------------------------------------------------------
203// Test for equality between a IONetworkMedium object and an OSObject.
204// The OSObject is considered equal to the IONetworkMedium object if the
205// OSObject is an IONetworkMedium, and they have similar properties assigned
206// to them during initialization.
207//
208// obj: An OSObject to test against the IONetworkMedium object being called.
209//
210// Returns true if equal, false otherwise.
211
212bool IONetworkMedium::isEqualTo(const OSMetaClassBase * obj) const
213{
214    IONetworkMedium * medium;
215    if ((medium = OSDynamicCast(IONetworkMedium, obj)))
216        return isEqualTo(medium);
217    else
218        return false;
219}
220
221//---------------------------------------------------------------------------
222// Create an OSData containing an IOMediumDescriptor structure (not copied),
223// and ask the OSData to serialize.
224//
225// s: An OSSerialize object to handle the serialization.
226//
227// Returns true on success, false otherwise.
228
229static bool addNumberToDict(OSDictionary * dict,
230                            const char *   key,
231                            UInt32         val,
232                            UInt32         bits = 32)
233{
234    OSNumber * num = OSNumber::withNumber(val, bits);
235    bool       ret;
236
237    if ( num == 0 ) return false;
238    ret = dict->setObject( key, num );
239    num->release();
240    return ret;
241}
242
243bool IONetworkMedium::serialize(OSSerialize * s) const
244{
245    bool           ret;
246    OSDictionary * dict;
247
248    dict = OSDictionary::withCapacity(4);
249    if ( dict == 0 ) return false;
250
251    addNumberToDict(dict, kIOMediumType,  getType());
252    addNumberToDict(dict, kIOMediumSpeed, getSpeed(), 64);
253    addNumberToDict(dict, kIOMediumIndex, getIndex());
254    addNumberToDict(dict, kIOMediumFlags, getFlags());
255
256    ret = dict->serialize(s);
257    dict->release();
258
259    return ret;
260}
261
262//---------------------------------------------------------------------------
263// A helper function to add an IONetworkMedium object to a given dictionary.
264// The name of the medium is used as the key for the new dictionary entry.
265//
266// dict:   An OSDictionary object where the medium object should be added to.
267// medium: The IONetworkMedium object to add to the dictionary.
268//
269// Returns true on success, false otherwise.
270
271bool IONetworkMedium::addMedium(OSDictionary *          dict,
272                                const IONetworkMedium * medium)
273{
274    // Arguments type checking.
275    //
276    if (!OSDynamicCast(OSDictionary, dict) ||
277        !OSDynamicCast(IONetworkMedium, medium))
278        return false;
279
280    return dict->setObject(medium->getName(), medium);
281}
282
283//---------------------------------------------------------------------------
284// A helper function to remove an entry in a dictionary with a key that
285// matches the name of the IONetworkMedium object provided.
286//
287// dict:   An OSDictionary object where the medium object should be removed
288//         from.
289// medium: The name of this medium object is used as the removal key.
290
291void IONetworkMedium::removeMedium(OSDictionary *          dict,
292                                   const IONetworkMedium * medium)
293{
294    // Arguments type checking.
295    //
296    if (!OSDynamicCast(OSDictionary, dict) ||
297        !OSDynamicCast(IONetworkMedium, medium))
298        return;
299
300    dict->removeObject(medium->getName());
301}
302
303//---------------------------------------------------------------------------
304// Iterate through a dictionary and return an IONetworkMedium entry that
305// satisfies the matching criteria. Returns 0 if there is no match.
306
307IONetworkMedium * IONetworkMedium::getMediumWithType(
308                                      const OSDictionary * dict,
309                                      IOMediumType         type,
310                                      IOMediumType         mask)
311{
312    OSCollectionIterator *  iter;
313    OSSymbol *              key;
314    IONetworkMedium *       medium;
315    IONetworkMedium *       match = 0;
316
317    if (!dict) return 0;
318
319    // Shouldn't withCollection take an (const OSDictionary *) argument?
320
321    iter = OSCollectionIterator::withCollection((OSDictionary *) dict);
322    if (!iter)
323        return 0;
324
325    while ( (key = (OSSymbol *) iter->getNextObject()) )
326    {
327        medium = OSDynamicCast(IONetworkMedium, dict->getObject(key));
328        if (medium == 0) continue;
329
330        if ( ( (medium->getType() ^ type) & ~mask) == 0 )
331        {
332            match = medium;
333            break;
334        }
335    }
336
337    iter->release();
338
339    return match;
340}
341
342IONetworkMedium * IONetworkMedium::getMediumWithIndex(
343                                      const OSDictionary * dict,
344                                      UInt32               index,
345                                      UInt32               mask)
346{
347    OSCollectionIterator *  iter;
348    OSSymbol *              key;
349    IONetworkMedium *       medium;
350    IONetworkMedium *       match = 0;
351
352    if (!dict) return 0;
353
354    // Shouldn't withCollection take an (const OSDictionary *) argument?
355
356    iter = OSCollectionIterator::withCollection((OSDictionary *) dict);
357    if (!iter)
358        return 0;
359
360    while ( (key = (OSSymbol *) iter->getNextObject()) )
361    {
362        medium = OSDynamicCast(IONetworkMedium, dict->getObject(key));
363        if (medium == 0) continue;
364
365        if ( ( (medium->getIndex() ^ index) & ~mask) == 0 )
366        {
367            match = medium;
368            break;
369        }
370    }
371
372    iter->release();
373
374    return match;
375}
376