lib: added WIN32 check for usb_set_configuration()
[barry.git] / src / controller.cc
blobb66cec3a9be0ffd59545da5e767bed051530c0a2
1 ///
2 /// \file controller.cc
3 /// High level Barry API class
4 ///
6 /*
7 Copyright (C) 2005-2010, 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 "controller.h"
23 #include "probe.h"
24 #include "common.h"
25 #include "protocol.h"
26 #include "protostructs.h"
27 #include "data.h"
28 #include "endian.h"
29 #include "platform.h"
30 #include <string.h>
32 #define __DEBUG_MODE__
33 #include "debug.h"
35 namespace Barry {
38 // Controller constructor
40 /// Constructor for the Controller class. Requires a valid ProbeResult
41 /// object to find the USB device to talk to.
42 ///
43 /// \param[in] device One of the ProbeResult objects from the
44 /// Probe class.
45 /// \param[in] default_timeout Override Usb::Device's default timeout
46 ///
47 Controller::Controller(const ProbeResult &device,
48 int default_timeout)
49 : m_result(device)
50 , m_dev(device.m_dev, default_timeout)
51 , m_iface(0)
52 , m_pin(device.m_pin)
53 , m_zero(m_dev, device.m_ep.write, device.m_ep.read, device.m_zeroSocketSequence)
54 , m_queue(0)
56 dout("Controller: Using non-threaded sockets");
57 SetupUsb(device);
61 // Controller constructor
63 /// Constructor for the Controller class. Requires a valid ProbeResult
64 /// object to find the USB device to talk to.
65 ///
66 /// \param[in] device One of the ProbeResult objects from the
67 /// Probe class.
68 /// \param[in] queue Plugin router object for reading data
69 /// from sockets.
70 /// \param[in] default_timeout Override Usb::Device's default timeout
71 ///
72 Controller::Controller(const ProbeResult &device,
73 SocketRoutingQueue &queue,
74 int default_timeout)
75 : m_result(device)
76 , m_dev(device.m_dev, default_timeout)
77 , m_iface(0)
78 , m_pin(device.m_pin)
79 , m_zero(queue, device.m_ep.write, device.m_zeroSocketSequence)
80 , m_queue(&queue)
82 dout("Controller: Using threaded socket router");
84 SetupUsb(device);
86 // set the queue to use our device
87 queue.SetUsbDevice(&m_dev, device.m_ep.write, device.m_ep.read);
90 void Controller::SetupUsb(const ProbeResult &device)
92 unsigned char cfg;
93 if( !m_dev.GetConfiguration(cfg) )
94 throw Usb::Error(m_dev.GetLastError(),
95 "Controller: GetConfiguration failed");
97 if( cfg != BLACKBERRY_CONFIGURATION || MUST_SET_CONFIGURATION ) {
98 if( !m_dev.SetConfiguration(BLACKBERRY_CONFIGURATION) )
99 throw Usb::Error(m_dev.GetLastError(),
100 "Controller: SetConfiguration failed");
103 m_iface = new Usb::Interface(m_dev, device.m_interface);
105 if( device.m_needSetAltInterface ) {
106 m_dev.SetAltInterface(device.m_interface);
109 if( device.m_needClearHalt ) {
110 m_dev.ClearHalt(device.m_ep.read);
111 m_dev.ClearHalt(device.m_ep.write);
115 Controller::~Controller()
117 // // trap exceptions in the destructor
118 // try {
119 // // a non-default socket has been opened, close it
120 // m_socket.Close();
121 // }
122 // catch( std::runtime_error &re ) {
123 // // do nothing... log it?
124 // dout("Exception caught in ~Socket: " << re.what());
125 // }
127 // detach the router from our device
128 if( m_queue ) {
129 m_queue->ClearUsbDevice();
130 m_queue = 0;
133 // cleanup the interface
134 delete m_iface;
136 // this happens when for some reason the Desktop mode
137 // is not fully opened, but the device has already recommended
138 // a socket to open... in this case, reset the device
139 // in the hopes that on next open, it will be in a
140 // recognizable state.
142 // FIXME - this should not be necessary, and someday we
143 // we should figure out how to handle the "already open"
144 // response we get for the Desktop
146 // FIXME - halfOpen now seems to be handled in the Socket class...
147 // perhaps move this there if needed
150 if( m_halfOpen ) {
151 dout("Controller object destroyed in halfopen state, resetting device");
152 m_dev.Reset();
157 ///////////////////////////////////////////////////////////////////////////////
158 // protected members
161 // Tells device which mode is desired, and returns the suggested
162 // socket ID to use for that mode.
164 uint16_t Controller::SelectMode(ModeType mode)
166 return SelectMode(mode, NULL);
169 // Tells device which mode is desired, and returns the suggested
170 // socket ID to use for that mode.
172 // If explicitModeName is not NULL then it will be used as the mode name.
173 // Otherwise the default mode name for the given mode will be used.
174 // It should be a nul terminated string if it is provided.
176 // The RawChannel mode requires an explicitModeName to be specified.
178 uint16_t Controller::SelectMode(ModeType mode, const char *explicitModeName)
180 // select mode
181 Protocol::Packet packet;
182 packet.socket = 0;
183 packet.size = htobs(SB_MODE_PACKET_COMMAND_SIZE);
184 packet.command = SB_COMMAND_SELECT_MODE;
185 packet.u.socket.socket = htobs(SB_MODE_REQUEST_SOCKET);
186 packet.u.socket.sequence = 0; // updated by Socket::Send()
187 memset(packet.u.socket.u.mode.name, 0, sizeof(packet.u.socket.u.mode.name));
189 char *modeName = (char *) packet.u.socket.u.mode.name;
191 if( explicitModeName ) {
192 if( strlen(explicitModeName) >= sizeof(packet.u.socket.u.mode.name) ) {
193 throw std::logic_error("Controller: explicit mode name too long");
195 strcpy(modeName, explicitModeName);
197 else {
198 // No modeName given, use the default
199 switch( mode )
201 case Bypass:
202 strcpy(modeName, "RIM Bypass");
203 break;
205 case Desktop:
206 strcpy(modeName, "RIM Desktop");
207 break;
209 case JavaLoader:
210 strcpy(modeName, "RIM_JavaLoader");
211 break;
213 case JVMDebug:
214 strcpy(modeName, "RIM_JVMDebug");
215 break;
217 case UsbSerData:
218 strcpy(modeName, "RIM_UsbSerData");
219 break;
221 case UsbSerCtrl:
222 strcpy(modeName, "RIM_UsbSerCtrl");
223 break;
225 case RawChannel:
226 throw std::logic_error("Controller: No channel name given with RawChannel mode");
227 break;
229 default:
230 throw std::logic_error("Controller: Invalid mode in SelectMode");
231 break;
235 // send mode command before we open, as a default socket is socket 0
236 Data command(&packet, btohs(packet.size));
237 Data response;
239 try {
240 m_zero.Send(command, response);
242 // get the data socket number
243 // indicates the socket number that
244 // should be used below in the Open() call
245 MAKE_PACKET(modepack, response);
246 if( modepack->command == SB_COMMAND_MODE_NOT_SELECTED ) {
247 throw Error("Controller: requested mode not supported");
249 if( modepack->command != SB_COMMAND_MODE_SELECTED ) {
250 eeout(command, response);
251 throw Error("Controller: mode not selected");
254 if( mode == Desktop ) {
255 // On the BlackBerry Storm, I have to read a packet
256 // after opening a socket. (only for Desktop mode)
257 // Otherwise, barrybackup and opensync-plugin can crash (timeout)
258 // I don't know why ! Maybe a bug on the handheld.
259 m_zero.HideSequencePacket(false);
260 m_zero.Receive(response);
261 m_zero.HideSequencePacket(true);
263 // return the socket that the device is expecting us to use
264 return btohs(modepack->u.socket.socket);
266 catch( Usb::Error & ) {
267 eout("Controller: error setting desktop mode");
268 eeout(command, response);
269 throw;
274 ///////////////////////////////////////////////////////////////////////////////
275 // public API
278 } // namespace Barry