3 /// USB Blackberry detection routines
7 Copyright (C) 2005-2007, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
32 #include "record-internal.h"
40 unsigned char Intro_Sends
[][32] = {
42 { 0x00, 0x00, 0x10, 0x00, 0x01, 0xff, 0x00, 0x00,
43 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
47 unsigned char Intro_Receives
[][32] = {
48 // response to packet #1
49 { 0x00, 0x00, 0x10, 0x00, 0x02, 0xff, 0x00, 0x00,
50 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
55 unsigned int GetSize(const unsigned char *packet
)
57 uint16_t size
= *((uint16_t *)&packet
[2]);
61 bool Intro(int IntroIndex
, const EndpointPair
&ep
, Device
&dev
, Data
&response
)
63 dev
.BulkWrite(ep
.write
, Intro_Sends
[IntroIndex
],
64 GetSize(Intro_Sends
[IntroIndex
]));
65 dev
.BulkRead(ep
.read
, response
);
66 ddout("BulkRead (" << (unsigned int)ep
.read
<< "):\n" << response
);
70 } // anonymous namespace
73 bool Probe::CheckSize(const Data
&data
, unsigned int required
)
75 const unsigned char *pd
= data
.GetData();
77 if( GetSize(pd
) != (unsigned int) data
.GetSize() ||
78 data
.GetSize() < required
||
79 pd
[4] != SB_COMMAND_FETCHED_ATTRIBUTE
)
81 dout("Probe: Parse data failure: GetSize(pd): " << GetSize(pd
)
82 << ", data.GetSize(): " << data
.GetSize()
83 << ", pd[4]: " << (unsigned int) pd
[4]);
90 bool Probe::ParsePIN(const Data
&data
, ProbeResult
&result
)
92 // validate response data
93 const unsigned char *pd
= data
.GetData();
95 if( !CheckSize(data
, 0x14) )
99 result
.m_pin
= btohl(*((uint32_t *) &pd
[16]));
104 bool Probe::ParseDesc(const Data
&data
, ProbeResult
&result
)
106 if( !CheckSize(data
, 29) )
109 // capture the description
110 const char *desc
= (const char*) &data
.GetData()[28];
111 int maxlen
= data
.GetSize() - 28;
112 result
.m_description
.assign(desc
, strnlen(desc
, maxlen
));
119 Usb::DeviceIDType devid
;
121 // Search for standard product ID first
123 Match
match(VENDOR_RIM
, PRODUCT_RIM_BLACKBERRY
);
124 while( match
.next_device(&devid
) )
128 // Search for Pearl devices second
130 // productID 6 devices (PRODUCT_RIM_PEARL) do not expose
131 // the USB class 255 interface we need, but only the
132 // Mass Storage one. Here we search for PRODUCT_RIM_PEARL_DUAL,
133 // (ID 4) which has both enabled.
134 Match
match(VENDOR_RIM
, PRODUCT_RIM_PEARL_DUAL
);
135 while( match
.next_device(&devid
) )
140 void Probe::ProbeDevice(Usb::DeviceIDType devid
)
142 // skip if we can't properly discover device config
143 DeviceDiscovery
discover(devid
);
144 ConfigDesc
&config
= discover
.configs
[BLACKBERRY_CONFIGURATION
];
146 // search for interface class
147 InterfaceDiscovery::base_type::iterator i
= config
.interfaces
.begin();
148 for( ; i
!= config
.interfaces
.end(); i
++ ) {
149 if( i
->second
.desc
.bInterfaceClass
== BLACKBERRY_DB_CLASS
)
152 if( i
== config
.interfaces
.end() ) {
153 dout("Probe: Interface with BLACKBERRY_DB_CLASS ("
154 << BLACKBERRY_DB_CLASS
<< ") not found.");
158 unsigned char InterfaceNumber
= i
->second
.desc
.bInterfaceNumber
;
159 dout("Probe: using InterfaceNumber: " << (unsigned int) InterfaceNumber
);
161 // check endpoint validity
162 EndpointDiscovery
&ed
= config
.interfaces
[InterfaceNumber
].endpoints
;
163 if( !ed
.IsValid() || ed
.GetEndpointPairs().size() == 0 ) {
164 dout("Probe: endpoint invalid. ed.IsValud() == "
165 << (ed
.IsValid() ? "true" : "false")
166 << ", ed.GetEndpointPairs().size() == "
167 << ed
.GetEndpointPairs().size());
172 result
.m_dev
= devid
;
173 result
.m_interface
= InterfaceNumber
;
174 result
.m_zeroSocketSequence
= 0;
176 // find the first bulk read/write endpoint pair that answers
177 // to our probe commands
178 // Start with second pair, since evidence indicates the later pairs
179 // are the ones we need.
180 for(size_t i
= ed
.GetEndpointPairs().size() > 1 ? 1 : 0;
181 i
< ed
.GetEndpointPairs().size();
184 const EndpointPair
&ep
= ed
.GetEndpointPairs()[i
];
185 if( ep
.type
== USB_ENDPOINT_TYPE_BULK
) {
192 if( !dev
.SetConfiguration(BLACKBERRY_CONFIGURATION
) )
193 throw Usb::Error(dev
.GetLastError(),
194 "Probe: SetConfiguration failed");
196 Interface
iface(dev
, InterfaceNumber
);
199 dev
.BulkDrain(ep
.read
);
200 if( !Intro(0, ep
, dev
, data
) ) {
201 dout("Probe: Intro(0) failed");
205 Socket
socket(dev
, ep
.write
, ep
.read
);
208 ZeroPacket
packet(send
, receive
);
210 // unknown attribute: 0x14 / 0x01
211 packet
.GetAttribute(SB_OBJECT_INITIAL_UNKNOWN
,
212 SB_ATTR_INITIAL_UNKNOWN
);
216 packet
.GetAttribute(SB_OBJECT_PROFILE
, SB_ATTR_PROFILE_PIN
);
218 if( packet
.ObjectID() != SB_OBJECT_PROFILE
||
219 packet
.AttributeID() != SB_ATTR_PROFILE_PIN
||
220 !ParsePIN(receive
, result
) )
222 dout("Probe: unable to fetch PIN");
227 packet
.GetAttribute(SB_OBJECT_PROFILE
, SB_ATTR_PROFILE_DESC
);
229 // response ObjectID does not match request... :-/
230 if( // packet.ObjectID() != SB_OBJECT_PROFILE ||
231 packet
.AttributeID() != SB_ATTR_PROFILE_DESC
||
232 !ParseDesc(receive
, result
) )
234 dout("Probe: unable to fetch description");
235 // this is a relatively new feature, so don't
236 // fail here... just blank the description
237 result
.m_description
.clear();
241 for( uint16_t attr
= 5; attr
< 9; attr
++ ) {
242 packet
.GetAttribute(SB_OBJECT_SOCKET_UNKNOWN
, attr
);
244 // FIXME parse these responses, if they turn
245 // out to be important
249 // all info obtained, add to list
250 result
.m_zeroSocketSequence
= socket
.GetZeroSocketSequence();
251 m_results
.push_back(result
);
252 ddout("Using ReadEndpoint: " << (unsigned int)result
.m_ep
.read
);
253 ddout(" WriteEndpoint: " << (unsigned int)result
.m_ep
.write
);
257 dout("Probe: Skipping non-bulk endpoint pair (offset: "
262 if( !result
.m_ep
.IsComplete() )
263 ddout("Unable to discover endpoint pair for one device.");
266 int Probe::FindActive(uint32_t pin
) const
268 for( int i
= 0; i
< GetCount(); i
++ ) {
269 if( Get(i
).m_pin
== pin
)
273 // can we default to a single device?
274 if( GetCount() == 1 )
282 std::ostream
& operator<< (std::ostream
&os
, const ProbeResult
&pr
)
284 os
<< "Device ID: " << pr
.m_dev
285 << std::hex
<< ". PIN: " << pr
.m_pin
286 << ", Description: " << pr
.m_description
;