| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Implements a low-level gnubby driver based on chrome.hid. | 6 * @fileoverview Implements a low-level gnubby driver based on chrome.hid. |
| 7 */ | 7 */ |
| 8 'use strict'; | 8 'use strict'; |
| 9 | 9 |
| 10 /** | 10 /** |
| 11 * Low level gnubby 'driver'. One per physical USB device. | 11 * Low level gnubby 'driver'. One per physical USB device. |
| 12 * @param {Gnubbies} gnubbies The gnubbies instances this device is enumerated | 12 * @param {Gnubbies} gnubbies The gnubbies instances this device is enumerated |
| 13 * in. | 13 * in. |
| 14 * @param {!chrome.hid.HidConnectInfo} dev The connection to the device. | 14 * @param {!chrome.hid.HidConnectInfo} dev The connection to the device. |
| 15 * @param {number} id The device's id. | 15 * @param {number} id The device's id. |
| 16 * @constructor | 16 * @constructor |
| 17 * @implements {GnubbyDevice} | 17 * @implements {GnubbyDevice} |
| 18 */ | 18 */ |
| 19 function HidGnubbyDevice(gnubbies, dev, id) { | 19 function HidGnubbyDevice(gnubbies, dev, id) { |
| 20 /** @private {Gnubbies} */ | 20 /** @private {Gnubbies} */ |
| 21 this.gnubbies_ = gnubbies; | 21 this.gnubbies_ = gnubbies; |
| 22 this.dev = dev; | 22 this.dev = dev; |
| 23 this.id = id; | 23 this.id = id; |
| 24 this.txqueue = []; | 24 this.txqueue = []; |
| 25 this.clients = []; | 25 this.clients = []; |
| 26 this.lockCID = 0; // channel ID of client holding a lock, if != 0. | 26 this.lockCID = 0; // channel ID of client holding a lock, if != 0. |
| 27 this.lockMillis = 0; // current lock period. | 27 this.lockMillis = 0; // current lock period. |
| 28 this.lockTID = null; // timer id of lock timeout. | 28 this.lockTID = null; // timer id of lock timeout. |
| 29 this.closing = false; // device to be closed by receive loop. | 29 this.closing = false; // device to be closed by receive loop. |
| 30 this.updating = false; // device firmware is in final stage of updating. | 30 this.updating = false; // device firmware is in final stage of updating. |
| 31 } | 31 } |
| 32 | 32 |
| 33 /** | 33 /** |
| 34 * Namespace for the HidGnubbyDevice implementation. | 34 * Namespace for the HidGnubbyDevice implementation. |
| 35 * @const | 35 * @const |
| 36 */ | 36 */ |
| 37 HidGnubbyDevice.NAMESPACE = 'hid'; | 37 HidGnubbyDevice.NAMESPACE = 'hid'; |
| 38 | 38 |
| 39 /** Destroys this low-level device instance. */ | 39 /** Destroys this low-level device instance. */ |
| 40 HidGnubbyDevice.prototype.destroy = function() { | 40 HidGnubbyDevice.prototype.destroy = function() { |
| 41 if (!this.dev) return; // Already dead. | 41 if (!this.dev) |
| 42 return; // Already dead. |
| 42 | 43 |
| 43 function closeLowLevelDevice(dev) { | 44 function closeLowLevelDevice(dev) { |
| 44 chrome.hid.disconnect(dev.connectionId, function() { | 45 chrome.hid.disconnect(dev.connectionId, function() { |
| 45 if (chrome.runtime.lastError) { | 46 if (chrome.runtime.lastError) { |
| 46 console.warn(UTIL_fmt('Device ' + dev.connectionId + | 47 console.warn(UTIL_fmt( |
| 47 ' couldn\'t be disconnected:')); | 48 'Device ' + dev.connectionId + ' couldn\'t be disconnected:')); |
| 48 console.warn(UTIL_fmt(chrome.runtime.lastError.message)); | 49 console.warn(UTIL_fmt(chrome.runtime.lastError.message)); |
| 49 return; | 50 return; |
| 50 } | 51 } |
| 51 console.log(UTIL_fmt('Device ' + dev.connectionId + ' closed')); | 52 console.log(UTIL_fmt('Device ' + dev.connectionId + ' closed')); |
| 52 }); | 53 }); |
| 53 } | 54 } |
| 54 | 55 |
| 55 this.gnubbies_.removeOpenDevice( | 56 this.gnubbies_.removeOpenDevice( |
| 56 {namespace: HidGnubbyDevice.NAMESPACE, device: this.id}); | 57 {namespace: HidGnubbyDevice.NAMESPACE, device: this.id}); |
| 57 this.closing = true; | 58 this.closing = true; |
| 58 | 59 |
| 59 console.log(UTIL_fmt('HidGnubbyDevice.destroy()')); | 60 console.log(UTIL_fmt('HidGnubbyDevice.destroy()')); |
| 60 | 61 |
| 61 // Synthesize a close error frame to alert all clients, | 62 // Synthesize a close error frame to alert all clients, |
| 62 // some of which might be in read state. | 63 // some of which might be in read state. |
| 63 // | 64 // |
| 64 // Use magic CID 0 to address all. | 65 // Use magic CID 0 to address all. |
| 65 this.publishFrame_(new Uint8Array([ | 66 this.publishFrame_(new Uint8Array([ |
| 66 0, 0, 0, 0, // broadcast CID | 67 0, 0, 0, 0, // broadcast CID |
| 67 GnubbyDevice.CMD_ERROR, | 68 GnubbyDevice.CMD_ERROR, 0, 1, // length |
| 68 0, 1, // length | 69 GnubbyDevice.GONE |
| 69 GnubbyDevice.GONE]).buffer); | 70 ]).buffer); |
| 70 | 71 |
| 71 // Set all clients to closed status and remove them. | 72 // Set all clients to closed status and remove them. |
| 72 while (this.clients.length != 0) { | 73 while (this.clients.length != 0) { |
| 73 var client = this.clients.shift(); | 74 var client = this.clients.shift(); |
| 74 if (client) client.closed = true; | 75 if (client) |
| 76 client.closed = true; |
| 75 } | 77 } |
| 76 | 78 |
| 77 if (this.lockTID) { | 79 if (this.lockTID) { |
| 78 window.clearTimeout(this.lockTID); | 80 window.clearTimeout(this.lockTID); |
| 79 this.lockTID = null; | 81 this.lockTID = null; |
| 80 } | 82 } |
| 81 | 83 |
| 82 var dev = this.dev; | 84 var dev = this.dev; |
| 83 this.dev = null; | 85 this.dev = null; |
| 84 var reallyCloseDevice = closeLowLevelDevice.bind(null, dev); | 86 var reallyCloseDevice = closeLowLevelDevice.bind(null, dev); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 118 |
| 117 var remaining = []; | 119 var remaining = []; |
| 118 var changes = false; | 120 var changes = false; |
| 119 for (var i = 0; i < old.length; ++i) { | 121 for (var i = 0; i < old.length; ++i) { |
| 120 var client = old[i]; | 122 var client = old[i]; |
| 121 if (client.receivedFrame(f)) { | 123 if (client.receivedFrame(f)) { |
| 122 // Client still alive; keep on list. | 124 // Client still alive; keep on list. |
| 123 remaining.push(client); | 125 remaining.push(client); |
| 124 } else { | 126 } else { |
| 125 changes = true; | 127 changes = true; |
| 126 console.log(UTIL_fmt( | 128 console.log(UTIL_fmt('[' + Gnubby.hexCid(client.cid) + '] left?')); |
| 127 '[' + Gnubby.hexCid(client.cid) + '] left?')); | |
| 128 } | 129 } |
| 129 } | 130 } |
| 130 if (changes) this.clients = remaining; | 131 if (changes) |
| 132 this.clients = remaining; |
| 131 }; | 133 }; |
| 132 | 134 |
| 133 /** | 135 /** |
| 134 * Register a client for this gnubby. | 136 * Register a client for this gnubby. |
| 135 * @param {*} who The client. | 137 * @param {*} who The client. |
| 136 */ | 138 */ |
| 137 HidGnubbyDevice.prototype.registerClient = function(who) { | 139 HidGnubbyDevice.prototype.registerClient = function(who) { |
| 138 for (var i = 0; i < this.clients.length; ++i) { | 140 for (var i = 0; i < this.clients.length; ++i) { |
| 139 if (this.clients[i] === who) return; // Already registered. | 141 if (this.clients[i] === who) |
| 142 return; // Already registered. |
| 140 } | 143 } |
| 141 this.clients.push(who); | 144 this.clients.push(who); |
| 142 if (this.clients.length == 1) { | 145 if (this.clients.length == 1) { |
| 143 // First client? Kick off read loop. | 146 // First client? Kick off read loop. |
| 144 this.readLoop_(); | 147 this.readLoop_(); |
| 145 } | 148 } |
| 146 }; | 149 }; |
| 147 | 150 |
| 148 /** | 151 /** |
| 149 * De-register a client. | 152 * De-register a client. |
| 150 * @param {*} who The client. | 153 * @param {*} who The client. |
| 151 * @return {number} The number of remaining listeners for this device, or -1 | 154 * @return {number} The number of remaining listeners for this device, or -1 |
| 152 * Returns number of remaining listeners for this device. | 155 * Returns number of remaining listeners for this device. |
| 153 * if this had no clients to start with. | 156 * if this had no clients to start with. |
| 154 */ | 157 */ |
| 155 HidGnubbyDevice.prototype.deregisterClient = function(who) { | 158 HidGnubbyDevice.prototype.deregisterClient = function(who) { |
| 156 var current = this.clients; | 159 var current = this.clients; |
| 157 if (current.length == 0) return -1; | 160 if (current.length == 0) |
| 161 return -1; |
| 158 this.clients = []; | 162 this.clients = []; |
| 159 for (var i = 0; i < current.length; ++i) { | 163 for (var i = 0; i < current.length; ++i) { |
| 160 var client = current[i]; | 164 var client = current[i]; |
| 161 if (client !== who) this.clients.push(client); | 165 if (client !== who) |
| 166 this.clients.push(client); |
| 162 } | 167 } |
| 163 return this.clients.length; | 168 return this.clients.length; |
| 164 }; | 169 }; |
| 165 | 170 |
| 166 /** | 171 /** |
| 167 * @param {*} who The client. | 172 * @param {*} who The client. |
| 168 * @return {boolean} Whether this device has who as a client. | 173 * @return {boolean} Whether this device has who as a client. |
| 169 */ | 174 */ |
| 170 HidGnubbyDevice.prototype.hasClient = function(who) { | 175 HidGnubbyDevice.prototype.hasClient = function(who) { |
| 171 if (this.clients.length == 0) return false; | 176 if (this.clients.length == 0) |
| 177 return false; |
| 172 for (var i = 0; i < this.clients.length; ++i) { | 178 for (var i = 0; i < this.clients.length; ++i) { |
| 173 if (who === this.clients[i]) | 179 if (who === this.clients[i]) |
| 174 return true; | 180 return true; |
| 175 } | 181 } |
| 176 return false; | 182 return false; |
| 177 }; | 183 }; |
| 178 | 184 |
| 179 /** | 185 /** |
| 180 * Reads all incoming frames and notifies clients of their receipt. | 186 * Reads all incoming frames and notifies clients of their receipt. |
| 181 * @private | 187 * @private |
| 182 */ | 188 */ |
| 183 HidGnubbyDevice.prototype.readLoop_ = function() { | 189 HidGnubbyDevice.prototype.readLoop_ = function() { |
| 184 //console.log(UTIL_fmt('entering readLoop')); | 190 // console.log(UTIL_fmt('entering readLoop')); |
| 185 if (!this.dev) return; | 191 if (!this.dev) |
| 192 return; |
| 186 | 193 |
| 187 if (this.closing) { | 194 if (this.closing) { |
| 188 this.destroy(); | 195 this.destroy(); |
| 189 return; | 196 return; |
| 190 } | 197 } |
| 191 | 198 |
| 192 // No interested listeners, yet we hit readLoop(). | 199 // No interested listeners, yet we hit readLoop(). |
| 193 // Must be clean-up. We do this here to make sure no transfer is pending. | 200 // Must be clean-up. We do this here to make sure no transfer is pending. |
| 194 if (!this.clients.length) { | 201 if (!this.clients.length) { |
| 195 this.closing = true; | 202 this.closing = true; |
| 196 this.destroy(); | 203 this.destroy(); |
| 197 return; | 204 return; |
| 198 } | 205 } |
| 199 | 206 |
| 200 // firmwareUpdate() sets this.updating when writing the last block before | 207 // firmwareUpdate() sets this.updating when writing the last block before |
| 201 // the signature. We process that reply with the already pending | 208 // the signature. We process that reply with the already pending |
| 202 // read transfer but we do not want to start another read transfer for the | 209 // read transfer but we do not want to start another read transfer for the |
| 203 // signature block, since that request will have no reply. | 210 // signature block, since that request will have no reply. |
| 204 // Instead we will see the device drop and re-appear on the bus. | 211 // Instead we will see the device drop and re-appear on the bus. |
| 205 // Current libusb on some platforms gets unhappy when transfer are pending | 212 // Current libusb on some platforms gets unhappy when transfer are pending |
| 206 // when that happens. | 213 // when that happens. |
| 207 // TODO: revisit once Chrome stabilizes its behavior. | 214 // TODO: revisit once Chrome stabilizes its behavior. |
| 208 if (this.updating) { | 215 if (this.updating) { |
| 209 console.log(UTIL_fmt('device updating. Ending readLoop()')); | 216 console.log(UTIL_fmt('device updating. Ending readLoop()')); |
| 210 return; | 217 return; |
| 211 } | 218 } |
| 212 | 219 |
| 213 var self = this; | 220 var self = this; |
| 214 chrome.hid.receive( | 221 chrome.hid.receive(this.dev.connectionId, function(report_id, data) { |
| 215 this.dev.connectionId, | 222 if (chrome.runtime.lastError || !data) { |
| 216 function(report_id, data) { | 223 console.log(UTIL_fmt('receive got lastError:')); |
| 217 if (chrome.runtime.lastError || !data) { | 224 console.log(UTIL_fmt(chrome.runtime.lastError.message)); |
| 218 console.log(UTIL_fmt('receive got lastError:')); | 225 window.setTimeout(function() { |
| 219 console.log(UTIL_fmt(chrome.runtime.lastError.message)); | 226 self.destroy(); |
| 220 window.setTimeout(function() { self.destroy(); }, 0); | 227 }, 0); |
| 221 return; | 228 return; |
| 222 } | 229 } |
| 223 var u8 = new Uint8Array(data); | 230 var u8 = new Uint8Array(data); |
| 224 console.log(UTIL_fmt('<' + UTIL_BytesToHex(u8))); | 231 console.log(UTIL_fmt('<' + UTIL_BytesToHex(u8))); |
| 225 | 232 |
| 226 self.publishFrame_(data); | 233 self.publishFrame_(data); |
| 227 | 234 |
| 228 // Read more. | 235 // Read more. |
| 229 window.setTimeout(function() { self.readLoop_(); }, 0); | 236 window.setTimeout(function() { |
| 230 } | 237 self.readLoop_(); |
| 231 ); | 238 }, 0); |
| 239 }); |
| 232 }; | 240 }; |
| 233 | 241 |
| 234 /** | 242 /** |
| 235 * Check whether channel is locked for this request or not. | 243 * Check whether channel is locked for this request or not. |
| 236 * @param {number} cid Channel id | 244 * @param {number} cid Channel id |
| 237 * @param {number} cmd Request command | 245 * @param {number} cmd Request command |
| 238 * @return {boolean} true if not locked for this request. | 246 * @return {boolean} true if not locked for this request. |
| 239 * @private | 247 * @private |
| 240 */ | 248 */ |
| 241 HidGnubbyDevice.prototype.checkLock_ = function(cid, cmd) { | 249 HidGnubbyDevice.prototype.checkLock_ = function(cid, cmd) { |
| 242 if (this.lockCID) { | 250 if (this.lockCID) { |
| 243 // We have an active lock. | 251 // We have an active lock. |
| 244 if (this.lockCID != cid) { | 252 if (this.lockCID != cid) { |
| 245 // Some other channel has active lock. | 253 // Some other channel has active lock. |
| 246 | 254 |
| 247 if (cmd != GnubbyDevice.CMD_SYNC && | 255 if (cmd != GnubbyDevice.CMD_SYNC && cmd != GnubbyDevice.CMD_INIT) { |
| 248 cmd != GnubbyDevice.CMD_INIT) { | |
| 249 // Anything but SYNC|INIT gets an immediate busy. | 256 // Anything but SYNC|INIT gets an immediate busy. |
| 250 var busy = new Uint8Array( | 257 var busy = new Uint8Array([ |
| 251 [(cid >> 24) & 255, | 258 (cid >> 24) & 255, (cid >> 16) & 255, (cid >> 8) & 255, cid & 255, |
| 252 (cid >> 16) & 255, | 259 GnubbyDevice.CMD_ERROR, 0, 1, // length |
| 253 (cid >> 8) & 255, | 260 GnubbyDevice.BUSY |
| 254 cid & 255, | 261 ]); |
| 255 GnubbyDevice.CMD_ERROR, | |
| 256 0, 1, // length | |
| 257 GnubbyDevice.BUSY]); | |
| 258 // Log the synthetic busy too. | 262 // Log the synthetic busy too. |
| 259 console.log(UTIL_fmt('<' + UTIL_BytesToHex(busy))); | 263 console.log(UTIL_fmt('<' + UTIL_BytesToHex(busy))); |
| 260 this.publishFrame_(busy.buffer); | 264 this.publishFrame_(busy.buffer); |
| 261 return false; | 265 return false; |
| 262 } | 266 } |
| 263 | 267 |
| 264 // SYNC|INIT gets to go to the device to flush OS tx/rx queues. | 268 // SYNC|INIT gets to go to the device to flush OS tx/rx queues. |
| 265 // The usb firmware is to alway respond to SYNC/INIT, | 269 // The usb firmware is to alway respond to SYNC/INIT, |
| 266 // regardless of lock status. | 270 // regardless of lock status. |
| 267 } | 271 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 292 this.lockMillis = nseconds * 1000 + 100; | 296 this.lockMillis = nseconds * 1000 + 100; |
| 293 } else { | 297 } else { |
| 294 // Releasing lock voluntarily. | 298 // Releasing lock voluntarily. |
| 295 this.lockCID = 0; | 299 this.lockCID = 0; |
| 296 } | 300 } |
| 297 } | 301 } |
| 298 | 302 |
| 299 // (re)set the lock timeout if we still hold it. | 303 // (re)set the lock timeout if we still hold it. |
| 300 if (this.lockCID) { | 304 if (this.lockCID) { |
| 301 var self = this; | 305 var self = this; |
| 302 this.lockTID = window.setTimeout( | 306 this.lockTID = window.setTimeout(function() { |
| 303 function() { | 307 console.warn( |
| 304 console.warn(UTIL_fmt( | 308 UTIL_fmt('lock for CID ' + Gnubby.hexCid(cid) + ' expired!')); |
| 305 'lock for CID ' + Gnubby.hexCid(cid) + ' expired!')); | 309 self.lockTID = null; |
| 306 self.lockTID = null; | 310 self.lockCID = 0; |
| 307 self.lockCID = 0; | 311 }, this.lockMillis); |
| 308 }, | |
| 309 this.lockMillis); | |
| 310 } | 312 } |
| 311 } | 313 } |
| 312 }; | 314 }; |
| 313 | 315 |
| 314 /** | 316 /** |
| 315 * Queue command to be sent. | 317 * Queue command to be sent. |
| 316 * If queue was empty, initiate the write. | 318 * If queue was empty, initiate the write. |
| 317 * @param {number} cid The client's channel ID. | 319 * @param {number} cid The client's channel ID. |
| 318 * @param {number} cmd The command to send. | 320 * @param {number} cmd The command to send. |
| 319 * @param {ArrayBuffer|Uint8Array} data Command arguments | 321 * @param {ArrayBuffer|Uint8Array} data Command arguments |
| 320 */ | 322 */ |
| 321 HidGnubbyDevice.prototype.queueCommand = function(cid, cmd, data) { | 323 HidGnubbyDevice.prototype.queueCommand = function(cid, cmd, data) { |
| 322 if (!this.dev) return; | 324 if (!this.dev) |
| 323 if (!this.checkLock_(cid, cmd)) return; | 325 return; |
| 326 if (!this.checkLock_(cid, cmd)) |
| 327 return; |
| 324 | 328 |
| 325 var u8 = new Uint8Array(data); | 329 var u8 = new Uint8Array(data); |
| 326 var f = new Uint8Array(64); | 330 var f = new Uint8Array(64); |
| 327 | 331 |
| 328 HidGnubbyDevice.setCid_(f, cid); | 332 HidGnubbyDevice.setCid_(f, cid); |
| 329 f[4] = cmd; | 333 f[4] = cmd; |
| 330 f[5] = (u8.length >> 8); | 334 f[5] = (u8.length >> 8); |
| 331 f[6] = (u8.length & 255); | 335 f[6] = (u8.length & 255); |
| 332 | 336 |
| 333 var lockArg = (u8.length > 0) ? u8[0] : 0; | 337 var lockArg = (u8.length > 0) ? u8[0] : 0; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 * @param {ArrayBuffer} frame Data frame | 374 * @param {ArrayBuffer} frame Data frame |
| 371 * @param {number} cid The client's channel ID. | 375 * @param {number} cid The client's channel ID. |
| 372 * @param {number} cmd The command to send. | 376 * @param {number} cmd The command to send. |
| 373 * @param {number} arg Command argument | 377 * @param {number} arg Command argument |
| 374 * @private | 378 * @private |
| 375 */ | 379 */ |
| 376 HidGnubbyDevice.prototype.queueFrame_ = function(frame, cid, cmd, arg) { | 380 HidGnubbyDevice.prototype.queueFrame_ = function(frame, cid, cmd, arg) { |
| 377 this.updateLock_(cid, cmd, arg); | 381 this.updateLock_(cid, cmd, arg); |
| 378 var wasEmpty = (this.txqueue.length == 0); | 382 var wasEmpty = (this.txqueue.length == 0); |
| 379 this.txqueue.push(frame); | 383 this.txqueue.push(frame); |
| 380 if (wasEmpty) this.writePump_(); | 384 if (wasEmpty) |
| 385 this.writePump_(); |
| 381 }; | 386 }; |
| 382 | 387 |
| 383 /** | 388 /** |
| 384 * Stuff queued frames from txqueue[] to device, one by one. | 389 * Stuff queued frames from txqueue[] to device, one by one. |
| 385 * @private | 390 * @private |
| 386 */ | 391 */ |
| 387 HidGnubbyDevice.prototype.writePump_ = function() { | 392 HidGnubbyDevice.prototype.writePump_ = function() { |
| 388 if (!this.dev) return; // Ignore. | 393 if (!this.dev) |
| 394 return; // Ignore. |
| 389 | 395 |
| 390 if (this.txqueue.length == 0) return; // Done with current queue. | 396 if (this.txqueue.length == 0) |
| 397 return; // Done with current queue. |
| 391 | 398 |
| 392 var frame = this.txqueue[0]; | 399 var frame = this.txqueue[0]; |
| 393 | 400 |
| 394 var self = this; | 401 var self = this; |
| 395 function transferComplete() { | 402 function transferComplete() { |
| 396 if (chrome.runtime.lastError) { | 403 if (chrome.runtime.lastError) { |
| 397 console.log(UTIL_fmt('send got lastError:')); | 404 console.log(UTIL_fmt('send got lastError:')); |
| 398 console.log(UTIL_fmt(chrome.runtime.lastError.message)); | 405 console.log(UTIL_fmt(chrome.runtime.lastError.message)); |
| 399 window.setTimeout(function() { self.destroy(); }, 0); | 406 window.setTimeout(function() { |
| 407 self.destroy(); |
| 408 }, 0); |
| 400 return; | 409 return; |
| 401 } | 410 } |
| 402 self.txqueue.shift(); // drop sent frame from queue. | 411 self.txqueue.shift(); // drop sent frame from queue. |
| 403 if (self.txqueue.length != 0) { | 412 if (self.txqueue.length != 0) { |
| 404 window.setTimeout(function() { self.writePump_(); }, 0); | 413 window.setTimeout(function() { |
| 414 self.writePump_(); |
| 415 }, 0); |
| 405 } | 416 } |
| 406 }; | 417 }; |
| 407 | 418 |
| 408 var u8 = new Uint8Array(frame); | 419 var u8 = new Uint8Array(frame); |
| 409 | 420 |
| 410 // See whether this requires scrubbing before logging. | 421 // See whether this requires scrubbing before logging. |
| 411 var alternateLog = Gnubby.hasOwnProperty('redactRequestLog') && | 422 var alternateLog = Gnubby.hasOwnProperty('redactRequestLog') && |
| 412 Gnubby['redactRequestLog'](u8); | 423 Gnubby['redactRequestLog'](u8); |
| 413 if (alternateLog) { | 424 if (alternateLog) { |
| 414 console.log(UTIL_fmt('>' + alternateLog)); | 425 console.log(UTIL_fmt('>' + alternateLog)); |
| 415 } else { | 426 } else { |
| 416 console.log(UTIL_fmt('>' + UTIL_BytesToHex(u8))); | 427 console.log(UTIL_fmt('>' + UTIL_BytesToHex(u8))); |
| 417 } | 428 } |
| 418 | 429 |
| 419 var u8f = new Uint8Array(64); | 430 var u8f = new Uint8Array(64); |
| 420 for (var i = 0; i < u8.length; ++i) { | 431 for (var i = 0; i < u8.length; ++i) { |
| 421 u8f[i] = u8[i]; | 432 u8f[i] = u8[i]; |
| 422 } | 433 } |
| 423 | 434 |
| 424 chrome.hid.send( | 435 chrome.hid.send( |
| 425 this.dev.connectionId, | 436 this.dev.connectionId, |
| 426 0, // report Id. Must be 0 for our use. | 437 0, // report Id. Must be 0 for our use. |
| 427 u8f.buffer, | 438 u8f.buffer, transferComplete); |
| 428 transferComplete | |
| 429 ); | |
| 430 }; | 439 }; |
| 431 | 440 |
| 432 /** | 441 /** |
| 433 * List of legacy HID devices that do not support the F1D0 usage page as | 442 * List of legacy HID devices that do not support the F1D0 usage page as |
| 434 * mandated by the spec, but still need to be supported. | 443 * mandated by the spec, but still need to be supported. |
| 435 * TODO: remove when these devices no longer need to be supported. | 444 * TODO: remove when these devices no longer need to be supported. |
| 436 * @const | 445 * @const |
| 437 */ | 446 */ |
| 438 HidGnubbyDevice.HID_VID_PIDS = [ | 447 HidGnubbyDevice.HID_VID_PIDS = [ |
| 439 {'vendorId': 4176, 'productId': 512} // Google-specific Yubico HID | 448 {'vendorId': 4176, 'productId': 512} // Google-specific Yubico HID |
| 440 ]; | 449 ]; |
| 441 | 450 |
| 442 /** | 451 /** |
| 443 * @param {function(Array)} cb Enumeration callback | 452 * @param {function(Array)} cb Enumeration callback |
| 444 * @param {GnubbyEnumerationTypes=} opt_type Which type of enumeration to do. | 453 * @param {GnubbyEnumerationTypes=} opt_type Which type of enumeration to do. |
| 445 */ | 454 */ |
| 446 HidGnubbyDevice.enumerate = function(cb, opt_type) { | 455 HidGnubbyDevice.enumerate = function(cb, opt_type) { |
| 447 /** | 456 /** |
| 448 * One pass using getDevices, and one for each of the hardcoded vid/pids. | 457 * One pass using getDevices, and one for each of the hardcoded vid/pids. |
| 449 * @const | 458 * @const |
| (...skipping 28 matching lines...) Expand all Loading... |
| 478 } | 487 } |
| 479 } | 488 } |
| 480 | 489 |
| 481 // Pass 1: usagePage-based enumeration, for FIDO U2F devices. If non-FIDO | 490 // Pass 1: usagePage-based enumeration, for FIDO U2F devices. If non-FIDO |
| 482 // devices are asked for, "implement" this pass by providing it the empty | 491 // devices are asked for, "implement" this pass by providing it the empty |
| 483 // list. (enumerated requires that it's called once per pass.) | 492 // list. (enumerated requires that it's called once per pass.) |
| 484 var f1d0Filter = {usagePage: 0xf1d0}; | 493 var f1d0Filter = {usagePage: 0xf1d0}; |
| 485 if (opt_type == GnubbyEnumerationTypes.VID_PID) { | 494 if (opt_type == GnubbyEnumerationTypes.VID_PID) { |
| 486 enumerated(f1d0Filter, []); | 495 enumerated(f1d0Filter, []); |
| 487 } else { | 496 } else { |
| 488 chrome.hid.getDevices({filters: [f1d0Filter]}, | 497 chrome.hid.getDevices( |
| 489 enumerated.bind(null, f1d0Filter)); | 498 {filters: [f1d0Filter]}, enumerated.bind(null, f1d0Filter)); |
| 490 } | 499 } |
| 491 // Pass 2: vid/pid-based enumeration, for legacy devices. If FIDO devices | 500 // Pass 2: vid/pid-based enumeration, for legacy devices. If FIDO devices |
| 492 // are asked for, "implement" this pass by providing it the empty list. | 501 // are asked for, "implement" this pass by providing it the empty list. |
| 493 if (opt_type == GnubbyEnumerationTypes.FIDO_U2F) { | 502 if (opt_type == GnubbyEnumerationTypes.FIDO_U2F) { |
| 494 enumerated(false, []); | 503 enumerated(false, []); |
| 495 } else { | 504 } else { |
| 496 for (var i = 0; i < HidGnubbyDevice.HID_VID_PIDS.length; i++) { | 505 for (var i = 0; i < HidGnubbyDevice.HID_VID_PIDS.length; i++) { |
| 497 var vidPid = HidGnubbyDevice.HID_VID_PIDS[i]; | 506 var vidPid = HidGnubbyDevice.HID_VID_PIDS[i]; |
| 498 chrome.hid.getDevices({filters: [vidPid]}, enumerated.bind(null, vidPid)); | 507 chrome.hid.getDevices({filters: [vidPid]}, enumerated.bind(null, vidPid)); |
| 499 } | 508 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 */ | 554 */ |
| 546 HidGnubbyDevice.register = function(gnubbies) { | 555 HidGnubbyDevice.register = function(gnubbies) { |
| 547 var HID_GNUBBY_IMPL = { | 556 var HID_GNUBBY_IMPL = { |
| 548 isSharedAccess: true, | 557 isSharedAccess: true, |
| 549 enumerate: HidGnubbyDevice.enumerate, | 558 enumerate: HidGnubbyDevice.enumerate, |
| 550 deviceToDeviceId: HidGnubbyDevice.deviceToDeviceId, | 559 deviceToDeviceId: HidGnubbyDevice.deviceToDeviceId, |
| 551 open: HidGnubbyDevice.open | 560 open: HidGnubbyDevice.open |
| 552 }; | 561 }; |
| 553 gnubbies.registerNamespace(HidGnubbyDevice.NAMESPACE, HID_GNUBBY_IMPL); | 562 gnubbies.registerNamespace(HidGnubbyDevice.NAMESPACE, HID_GNUBBY_IMPL); |
| 554 }; | 563 }; |
| OLD | NEW |