- added item to gui's todo list
[barry.git] / src / probe.cc
blob9bd3b11202aba0a82d34a6cda628302db8ea63d8
1 ///
2 /// \file probe.cc
3 /// USB Blackberry detection routines
4 ///
6 /*
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.
22 #include "common.h"
23 #include "probe.h"
24 #include "usbwrap.h"
25 #include "data.h"
26 #include "endian.h"
27 #include "error.h"
28 #include "debug.h"
29 #include "packet.h"
30 #include "socket.h"
31 #include "protocol.h"
32 #include <iomanip>
34 using namespace Usb;
36 namespace Barry {
38 unsigned char Intro_Sends[][32] = {
39 // packet #1
40 { 0x00, 0x00, 0x10, 0x00, 0x01, 0xff, 0x00, 0x00,
41 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
45 unsigned char Intro_Receives[][32] = {
46 // response to packet #1
47 { 0x00, 0x00, 0x10, 0x00, 0x02, 0xff, 0x00, 0x00,
48 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 }
51 namespace {
53 unsigned int GetSize(const unsigned char *packet)
55 uint16_t size = *((uint16_t *)&packet[2]);
56 return btohs(size);
59 bool Intro(int IntroIndex, const EndpointPair &ep, Device &dev, Data &response)
61 dev.BulkWrite(ep.write, Intro_Sends[IntroIndex],
62 GetSize(Intro_Sends[IntroIndex]));
63 dev.BulkRead(ep.read, response);
64 ddout("BulkRead (" << (unsigned int)ep.read << "):\n" << response);
65 return true;
68 } // anonymous namespace
71 bool Probe::Parse(const Data &data, ProbeResult &result)
73 // validate response data
74 const unsigned char *pd = data.GetData();
76 if( GetSize(pd) != (unsigned int) data.GetSize() ||
77 data.GetSize() < 0x14 ||
78 pd[4] != 0x06 )
80 dout("Probe: Parse data failure: GetSize(pd): " << GetSize(pd)
81 << ", data.GetSize(): " << data.GetSize()
82 << ", pd[4]: " << (unsigned int) pd[4]);
83 return false;
86 // capture the PIN
87 result.m_pin = btohl(*((uint32_t *) &pd[16]));
89 return true;
92 Probe::Probe()
94 Usb::DeviceIDType devid;
96 // Search for standard product ID first
98 Match match(VENDOR_RIM, PRODUCT_RIM_BLACKBERRY);
99 while( match.next_device(&devid) )
100 ProbeDevice(devid);
103 // Search for Pearl devices second
105 // productID 6 devices (PRODUCT_RIM_PEARL) do not expose
106 // the USB class 255 interface we need, but only the
107 // Mass Storage one. Here we search for PRODUCT_RIM_PEARL_DUAL,
108 // (ID 4) which has both enabled.
109 Match match(VENDOR_RIM, PRODUCT_RIM_PEARL_DUAL);
110 while( match.next_device(&devid) )
111 ProbeDevice(devid);
115 void Probe::ProbeDevice(Usb::DeviceIDType devid)
117 // skip if we can't properly discover device config
118 DeviceDiscovery discover(devid);
119 ConfigDesc &config = discover.configs[BLACKBERRY_CONFIGURATION];
121 // search for interface class
122 InterfaceDiscovery::base_type::iterator i = config.interfaces.begin();
123 for( ; i != config.interfaces.end(); i++ ) {
124 if( i->second.desc.bInterfaceClass == BLACKBERRY_DB_CLASS )
125 break;
127 if( i == config.interfaces.end() ) {
128 dout("Probe: Interface with BLACKBERRY_DB_CLASS ("
129 << BLACKBERRY_DB_CLASS << ") not found.");
130 return; // not found
133 unsigned char InterfaceNumber = i->second.desc.bInterfaceNumber;
134 dout("Probe: using InterfaceNumber: " << (unsigned int) InterfaceNumber);
136 // check endpoint validity
137 EndpointDiscovery &ed = config.interfaces[InterfaceNumber].endpoints;
138 if( !ed.IsValid() || ed.GetEndpointPairs().size() == 0 ) {
139 dout("Probe: endpoint invalid. ed.IsValud() == "
140 << (ed.IsValid() ? "true" : "false")
141 << ", ed.GetEndpointPairs().size() == "
142 << ed.GetEndpointPairs().size());
143 return;
146 ProbeResult result;
147 result.m_dev = devid;
148 result.m_interface = InterfaceNumber;
149 result.m_zeroSocketSequence = 0;
151 // find the first bulk read/write endpoint pair that answers
152 // to our probe commands
153 // Start with second pair, since evidence indicates the later pairs
154 // are the ones we need.
155 for(size_t i = ed.GetEndpointPairs().size() > 1 ? 1 : 0;
156 i < ed.GetEndpointPairs().size();
157 i++ )
159 const EndpointPair &ep = ed.GetEndpointPairs()[i];
160 if( ep.type == USB_ENDPOINT_TYPE_BULK ) {
161 result.m_ep = ep;
163 Device dev(devid);
164 // dev.Reset();
165 // sleep(5);
167 if( !dev.SetConfiguration(BLACKBERRY_CONFIGURATION) )
168 throw Error(dev.GetLastError(),
169 "Probe: SetConfiguration failed");
171 Interface iface(dev, InterfaceNumber);
173 Data data;
174 dev.BulkDrain(ep.read);
175 if( !Intro(0, ep, dev, data) ) {
176 dout("Probe: Intro(0) failed");
177 continue;
180 Socket socket(dev, ep.write, ep.read);
182 Data send, receive;
183 ZeroPacket packet(send, receive);
185 // unknown attribute: 0x14 / 0x01
186 packet.GetAttribute(SB_OBJECT_INITIAL_UNKNOWN,
187 SB_ATTR_INITIAL_UNKNOWN);
188 socket.Send(packet);
190 // fetch PIN
191 packet.GetAttribute(SB_OBJECT_PROFILE, SB_ATTR_PROFILE_PIN);
192 socket.Send(packet);
193 if( packet.ObjectID() != SB_OBJECT_PROFILE ||
194 packet.AttributeID() != SB_ATTR_PROFILE_PIN ||
195 !Parse(receive, result) )
197 dout("Probe: unable to fetch PIN");
198 continue;
201 // more unknowns:
202 for( uint16_t attr = 5; attr < 9; attr++ ) {
203 packet.GetAttribute(SB_OBJECT_SOCKET_UNKNOWN, attr);
204 socket.Send(packet);
205 // FIXME parse these responses, if they turn
206 // out to be important
210 // all info obtained, add to list
211 result.m_zeroSocketSequence = socket.GetZeroSocketSequence();
212 m_results.push_back(result);
213 ddout("Using ReadEndpoint: " << (unsigned int)result.m_ep.read);
214 ddout(" WriteEndpoint: " << (unsigned int)result.m_ep.write);
215 break;
217 else {
218 dout("Probe: Skipping non-bulk endpoint pair (offset: "
219 << i-1 << ") ");
223 if( !result.m_ep.IsComplete() )
224 ddout("Unable to discover endpoint pair for one device.");
227 int Probe::FindActive(uint32_t pin) const
229 for( int i = 0; i < GetCount(); i++ ) {
230 if( Get(i).m_pin == pin )
231 return i;
233 if( pin == 0 ) {
234 // can we default to a single device?
235 if( GetCount() == 1 )
236 return 0; // yes!
239 // PIN not found
240 return -1;
243 std::ostream& operator<< (std::ostream &os, const ProbeResult &pr)
245 os << "Device ID: " << pr.m_dev << std::setbase(16) << ". PIN: "
246 << pr.m_pin;
247 return os;
250 } // namespace Barry