sbWindowsUSBDeviceUtils.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2010 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
27 //------------------------------------------------------------------------------
28 //
29 // Songbird Windows USB device utilities services.
30 //
31 //------------------------------------------------------------------------------
32 
38 //------------------------------------------------------------------------------
39 //
40 // Songbird Windows USB device utilities imported services.
41 //
42 //------------------------------------------------------------------------------
43 
44 // Self import.
46 
47 // Local imports.
48 #include "sbWindowsDeviceUtils.h"
49 
50 // Songbird imports.
51 #include <sbWindowsUtils.h>
52 
53 // Windows imports.
54 #include <devioctl.h>
55 
56 
57 // Disable warning about non-standard extensions used in this header file.
58 #pragma warning (push)
59 #pragma warning (disable: 4200)
60 
61 #include <usbioctl.h>
62 
63 #pragma warning (pop)
64 
65 
66 //------------------------------------------------------------------------------
67 //
68 // Songbird Windows USB device utilities defs.
69 //
70 //------------------------------------------------------------------------------
71 
72 //
73 // Win32 device GUID defs.
74 //
75 // These are defined here to avoid DDK library dependencies.
76 //
77 
78 static const GUID GUID_DEVINTERFACE_USB_HUB =
79 {
80  0xF18A0E88,
81  0xC30C,
82  0x11D0,
83  { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 }
84 };
85 
86 
87 //------------------------------------------------------------------------------
88 //
89 // Songbird USB device system services.
90 //
91 //------------------------------------------------------------------------------
92 
108 nsresult
110  PRUint8 aDescriptorType,
111  PRUint8 aDescriptorIndex,
112  PRUint16 aDescriptorIndex2,
113  PRUint16 aDescriptorLength,
114  sbUSBDescriptor** aDescriptor)
115 {
116  // Validate arguments.
117  NS_ENSURE_ARG_POINTER(aDeviceRef);
118  NS_ENSURE_ARG_POINTER(aDescriptor);
119 
120  // Function variables.
121  sbWinUSBDeviceRef* deviceRef = static_cast<sbWinUSBDeviceRef*>(aDeviceRef);
122  DEVINST devInst = deviceRef->devInst;
123  HANDLE hubFile = deviceRef->hubFile;
124  sbAutoHANDLE autoHubFile;
125  ULONG portIndex = deviceRef->portIndex;
126  BOOL success;
127  nsresult rv;
128 
129  // Ensure a hub file and port index are available.
130  if (hubFile == INVALID_HANDLE_VALUE) {
131  // Get the hub file and port index and set up for auto-disposal.
132  rv = sbWinUSBDeviceGetHubAndPort(devInst, &hubFile, &portIndex);
133  NS_ENSURE_SUCCESS(rv, rv);
134  autoHubFile = hubFile;
135  }
136 
137  // Allocate a descriptor request to get the descriptor and set it up for
138  // auto-disposal.
139  DWORD requestSize = sizeof(USB_DESCRIPTOR_REQUEST) + aDescriptorLength;
140  PUSB_DESCRIPTOR_REQUEST descriptorRequest =
141  static_cast<PUSB_DESCRIPTOR_REQUEST>(NS_Alloc(requestSize));
142  NS_ENSURE_TRUE(descriptorRequest, NS_ERROR_OUT_OF_MEMORY);
143  sbAutoNSMemPtr autoDescriptorRequest(descriptorRequest);
144 
145  // Set up the descriptor request.
146  descriptorRequest->ConnectionIndex = portIndex;
147  descriptorRequest->SetupPacket.wValue =
148  (aDescriptorType << 8) | aDescriptorIndex;
149  descriptorRequest->SetupPacket.wIndex = aDescriptorIndex2;
150  descriptorRequest->SetupPacket.wLength = aDescriptorLength;
151 
152  // Issue a get descriptor request.
153  DWORD byteCount;
154  success = DeviceIoControl(hubFile,
155  IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
156  descriptorRequest,
157  requestSize,
158  descriptorRequest,
159  requestSize,
160  &byteCount,
161  NULL);
162  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
163 
164  // Get the descriptor.
165  nsRefPtr<sbUSBDescriptor> descriptor =
166  new sbUSBDescriptor(descriptorRequest->Data,
167  aDescriptorLength);
168  NS_ENSURE_TRUE(descriptor, NS_ERROR_OUT_OF_MEMORY);
169  NS_ENSURE_TRUE(descriptor->Get(), NS_ERROR_OUT_OF_MEMORY);
170 
171  // Return results.
172  descriptor.forget(aDescriptor);
173 
174  // No need to hold onto the hub file, we're done with it now.
175  rv = sbWinUSBDeviceCloseRef(deviceRef);
176  NS_ENSURE_SUCCESS(rv, rv);
177 
178  return NS_OK;
179 }
180 
181 
182 //------------------------------------------------------------------------------
183 //
184 // Songbird Windows USB device services.
185 //
186 //------------------------------------------------------------------------------
187 
196 nsresult
197 sbWinUSBDeviceOpenRef(DEVINST aDevInst,
198  sbWinUSBDeviceRef* aDeviceRef)
199 {
200  // Validate arguments.
201  NS_ENSURE_ARG_POINTER(aDeviceRef);
202 
203  // Function variables.
204  nsresult rv;
205 
206  // Get the device hub and port.
207  HANDLE hubFile;
208  ULONG portIndex;
209  rv = sbWinUSBDeviceGetHubAndPort(aDevInst, &hubFile, &portIndex);
210  NS_ENSURE_SUCCESS(rv, rv);
211 
212  // Return results.
213  aDeviceRef->devInst = aDevInst;
214  aDeviceRef->hubFile = hubFile;
215  aDeviceRef->portIndex = portIndex;
216 
217  return NS_OK;
218 }
219 
220 
227 nsresult
229 {
230  // Validate arguments.
231  NS_ENSURE_ARG_POINTER(aDeviceRef);
232 
233  // Close the hub file.
234  if (aDeviceRef->hubFile != INVALID_HANDLE_VALUE) {
235  CloseHandle(aDeviceRef->hubFile);
236  aDeviceRef->hubFile = INVALID_HANDLE_VALUE;
237  }
238 
239  return NS_OK;
240 }
241 
242 
252 nsresult
254  HANDLE* aHubFile,
255  ULONG* aPortIndex)
256 {
257  // Validate arguments.
258  NS_ENSURE_ARG_POINTER(aHubFile);
259  NS_ENSURE_ARG_POINTER(aPortIndex);
260 
261  // Function variables.
262  nsresult rv;
263 
264  // Create a file for the first hub ancestor of device and set it up for
265  // auto-disposal.
266  HANDLE hubFile;
267  GUID guid = GUID_DEVINTERFACE_USB_HUB;
268  rv = sbWinCreateAncestorDeviceFile(&hubFile,
269  aDevInst,
270  &guid,
271  GENERIC_READ,
272  FILE_SHARE_READ | FILE_SHARE_WRITE,
273  NULL,
274  OPEN_EXISTING,
275  0,
276  NULL);
277  NS_ENSURE_SUCCESS(rv, rv);
278  sbAutoHANDLE autoHubFile(hubFile);
279 
280  // Find the device hub port index.
281  ULONG portIndex;
282  rv = sbWinUSBHubFindDevicePort(hubFile, aDevInst, &portIndex);
283  NS_ENSURE_SUCCESS(rv, rv);
284 
285  // Return results.
286  *aHubFile = autoHubFile.forget();
287  *aPortIndex = portIndex;
288 
289  return NS_OK;
290 }
291 
292 
302 nsresult
304  DEVINST aDevInst,
305  ULONG* aPortIndex)
306 {
307  // Validate arguments.
308  NS_ENSURE_ARG_POINTER(aPortIndex);
309 
310  // Function variables.
311  DWORD byteCount;
312  BOOL success;
313  CONFIGRET cr;
314  nsresult rv;
315 
316  // Get the device driver key.
317  TCHAR winDriverKey[256];
318  nsAutoString driverKey;
319  ULONG len = sizeof(winDriverKey);
320  cr = CM_Get_DevNode_Registry_Property(aDevInst,
321  CM_DRP_DRIVER,
322  NULL,
323  winDriverKey,
324  &len,
325  0);
326  NS_ENSURE_TRUE(cr == CR_SUCCESS, NS_ERROR_FAILURE);
327  driverKey = winDriverKey;
328 
329  // Get the number of USB hub ports.
330  USB_NODE_INFORMATION usbNodeInformation;
331  success = DeviceIoControl(aHubFile,
332  IOCTL_USB_GET_NODE_INFORMATION,
333  NULL,
334  0,
335  &usbNodeInformation,
336  sizeof(usbNodeInformation),
337  &byteCount,
338  NULL);
339  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
340  ULONG portCount =
341  usbNodeInformation.u.HubInformation.HubDescriptor.bNumberOfPorts;
342 
343  // Check each USB hub port for a matching driver key.
344  ULONG portIndex;
345  for (portIndex = 1; portIndex <= portCount; portIndex++) {
346  // Get the port driver key.
347  nsAutoString portDriverKey;
348  rv = sbWinUSBHubGetPortDriverKey(aHubFile, portIndex, portDriverKey);
349  NS_ENSURE_SUCCESS(rv, rv);
350 
351  // Check for a match.
352  if (driverKey.Equals(portDriverKey))
353  break;
354  }
355  NS_ENSURE_TRUE(portIndex <= portCount, NS_ERROR_NOT_AVAILABLE);
356 
357  // Return results.
358  *aPortIndex = portIndex;
359 
360  return NS_OK;
361 }
362 
363 
375 nsresult
377  ULONG aPortIndex,
378  nsAString& aDriverKey)
379 {
380  USB_NODE_CONNECTION_DRIVERKEY_NAME* driverKeyName;
381  DWORD requestSize;
382  DWORD byteCount;
383  BOOL success;
384 
385  // Set default result.
386  aDriverKey.SetIsVoid(PR_TRUE);
387 
388  // Issue a get driver key request to probe the full request size. Assume port
389  // is not connected on error.
390  USB_NODE_CONNECTION_DRIVERKEY_NAME probeDriverKeyName;
391  driverKeyName = &probeDriverKeyName;
392  driverKeyName->ConnectionIndex = aPortIndex;
393  requestSize = sizeof(probeDriverKeyName);
394  success = DeviceIoControl(aHubFile,
395  IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
396  driverKeyName,
397  requestSize,
398  driverKeyName,
399  requestSize,
400  &byteCount,
401  NULL);
402  if (!success)
403  return NS_OK;
404 
405  // Allocate a get driver key request and set it up for auto-disposal.
406  requestSize = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) +
407  probeDriverKeyName.ActualLength;
408  driverKeyName =
409  static_cast<USB_NODE_CONNECTION_DRIVERKEY_NAME*>(NS_Alloc(requestSize));
410  NS_ENSURE_TRUE(driverKeyName, NS_ERROR_OUT_OF_MEMORY);
411  sbAutoNSMemPtr autoDriverKeyName(driverKeyName);
412 
413  // Issue a get driver key request to get the driver key.
414  driverKeyName->ConnectionIndex = aPortIndex;
415  success = DeviceIoControl(aHubFile,
416  IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
417  driverKeyName,
418  requestSize,
419  driverKeyName,
420  requestSize,
421  &byteCount,
422  NULL);
423  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
424 
425  // Return results.
426  aDriverKey.Assign(driverKeyName->DriverKeyName);
427 
428  return NS_OK;
429 }
430 
431 
432 //------------------------------------------------------------------------------
433 //
434 // Songbird Windows USB MSC device services.
435 //
436 //------------------------------------------------------------------------------
437 
445 nsresult
446 sbWinUSBMSCGetLUN(DEVINST aDevInst,
447  PRUint32* aLUN)
448 {
449  // Validate arguments.
450  NS_ENSURE_ARG_POINTER(aLUN);
451 
452  // Function variables.
453  nsresult rv;
454 
455  // Get the device instance ID.
456  nsAutoString deviceInstanceID;
457  rv = sbWinGetDeviceInstanceID(aDevInst, deviceInstanceID);
458  NS_ENSURE_SUCCESS(rv, rv);
459 
460  // Extract the LUN from the last number in the device instance ID.
461  // E.g., "USBSTOR\DISK&VEN_SANDISK&PROD_SANSA_FUZE_4GB&REV_V02.\"
462  // "E812EA114524B6A80000000000000000&1"
463  // for LUN = 1.
464  //XXXeps It sure would be nice to have a better way of doing this.
465  PRUint32 lun = 0;
466  PRInt32 index = deviceInstanceID.RFind(NS_LITERAL_STRING("&"));
467  if (index >= 0) {
468  // Extract the LUN. Assume a LUN of zero on any failure.
469  lun = Substring(deviceInstanceID, index + 1).ToInteger(&rv);
470  if (NS_FAILED(rv))
471  lun = 0;
472  }
473 
474  // Return results.
475  *aLUN = lun;
476 
477  return NS_OK;
478 }
479 
480 
return NS_OK
nsresult sbWinGetDeviceInstanceID(DEVINST aDevInst, nsAString &aDeviceInstanceID)
Songbird Windows Device Utilities Definitions.
static const GUID GUID_DEVINTERFACE_USB_HUB
nsresult sbWinUSBDeviceCloseRef(sbWinUSBDeviceRef *aDeviceRef)
nsresult sbWinCreateAncestorDeviceFile(HANDLE *aDevFile, DEVINST aDevInst, const GUID *aGUID, DWORD aDesiredAccess, DWORD aShareMode, LPSECURITY_ATTRIBUTES aSecurityAttributes, DWORD aCreationDisposition, DWORD aFlagsAndAttributes, HANDLE aTemplateFile)
nsresult sbWinUSBDeviceGetHubAndPort(DEVINST aDevInst, HANDLE *aHubFile, ULONG *aPortIndex)
nsresult sbWinUSBHubGetPortDriverKey(HANDLE aHubFile, ULONG aPortIndex, nsAString &aDriverKey)
Songbird Windows USB Device Utilities Definitions.
var cr
nsresult sbWinUSBDeviceOpenRef(DEVINST aDevInst, sbWinUSBDeviceRef *aDeviceRef)
nsresult sbUSBDeviceGetDescriptor(sbUSBDeviceRef *aDeviceRef, PRUint8 aDescriptorType, PRUint8 aDescriptorIndex, PRUint16 aDescriptorIndex2, PRUint16 aDescriptorLength, sbUSBDescriptor **aDescriptor)
nsresult sbWinUSBHubFindDevicePort(HANDLE aHubFile, DEVINST aDevInst, ULONG *aPortIndex)
nsresult sbWinUSBMSCGetLUN(DEVINST aDevInst, PRUint32 *aLUN)