`
dato0123
  • 浏览: 916806 次
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是UHCI(18)Root Hub的控制传输(二)

 
阅读更多

医生,请把孩子取出来之后,顺便给我吸吸脂.

——广州一妇女在剖腹产手术前对医生说.

对于控制传输,rh_call_control会被调用.我也特别希望能有人给这个函数吸吸脂,我们的上下文是为了获取设备描述符,即当初那个usb_get_device_descriptor领着我们来到了这个函数,为了完成这件事情,实际上只需要很少的代码,但是rh_call_control这个函数涉及了所有的Root Hub相关的控制传输,以至于我们除了把孩子取出来之外,还不得不顺便看看其它的代码.当然了,既然是顺便,那么我们也就不会详细的去讲解每一行.这个函数定义于drivers/usb/core/hcd.c:

343 /* Root hub control transfers execute synchronously */

344 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)

345 {

346 struct usb_ctrlrequest *cmd;

347 u16 typeReq, wValue, wIndex, wLength;

348 u8 *ubuf = urb->transfer_buffer;

349 u8 tbuf [sizeof (struct usb_hub_descriptor)]

350 __attribute__((aligned(4)));

351 const u8 *bufp = tbuf;

352 int len = 0;

353 int patch_wakeup = 0;

354 unsigned long flags;

355 int status = 0;

356 int n;

357

358 cmd = (struct usb_ctrlrequest *) urb->setup_packet;

359 typeReq = (cmd->bRequestType << 8) | cmd->bRequest;

360 wValue = le16_to_cpu (cmd->wValue);

361 wIndex = le16_to_cpu (cmd->wIndex);

362 wLength = le16_to_cpu (cmd->wLength);

363

364 if (wLength > urb->transfer_buffer_length)

365 goto error;

366

367 urb->actual_length = 0;

368 switch (typeReq) {

369

370 /* DEVICE REQUESTS */

371

372 /* The root hub's remote wakeup enable bit is implemented using

373 * driver model wakeup flags. If this system supports wakeup

374 * through USB, userspace may change the default "allow wakeup"

375 * policy through sysfs or these calls.

376 *

377 * Most root hubs support wakeup from downstream devices, for

378 * runtime power management (disabling USB clocks and reducing

379 * VBUS power usage). However, not all of them do so; silicon,

380 * board, and BIOS bugs here are not uncommon, so these can't

381 * be treated quite like external hubs.

382 *

383 * Likewise, not all root hubs will pass wakeup events upstream,

384 * to wake up the whole system. So don't assume root hub and

385 * controller capabilities are identical.

386 */

387

388 case DeviceRequest | USB_REQ_GET_STATUS:

389 tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)

390 << USB_DEVICE_REMOTE_WAKEUP)

391 | (1 << USB_DEVICE_SELF_POWERED);

392 tbuf [1] = 0;

393 len = 2;

394 break;

395 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:

396 if (wValue == USB_DEVICE_REMOTE_WAKEUP)

397 device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);

398 else

399 goto error;

400 break;

401 case DeviceOutRequest | USB_REQ_SET_FEATURE:

402 if (device_can_wakeup(&hcd->self.root_hub->dev)

403 && wValue == USB_DEVICE_REMOTE_WAKEUP)

404 device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);

405 else

406 goto error;

407 break;

408 case DeviceRequest | USB_REQ_GET_CONFIGURATION:

409 tbuf [0] = 1;

410 len = 1;

411 /* FALLTHROUGH */

412 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:

413 break;

414 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:

415 switch (wValue & 0xff00) {

416 case USB_DT_DEVICE << 8:

417 if (hcd->driver->flags & HCD_USB2)

418 bufp = usb2_rh_dev_descriptor;

419 else if (hcd->driver->flags & HCD_USB11)

420 bufp = usb11_rh_dev_descriptor;

421 else

422 goto error;

423 len = 18;

424 break;

425 case USB_DT_CONFIG << 8:

426 if (hcd->driver->flags & HCD_USB2) {

427 bufp = hs_rh_config_descriptor;

428 len = sizeof hs_rh_config_descriptor;

429 } else {

430 bufp = fs_rh_config_descriptor;

431 len = sizeof fs_rh_config_descriptor;

432 }

433 if (device_can_wakeup(&hcd->self.root_hub->dev))

434 patch_wakeup = 1;

435 break;

436 case USB_DT_STRING << 8:

437 n = rh_string (wValue & 0xff, hcd, ubuf, wLength);

438 if (n < 0)

439 goto error;

440 urb->actual_length = n;

441 break;

442 default:

443 goto error;

444 }

445 break;

446 case DeviceRequest | USB_REQ_GET_INTERFACE:

447 tbuf [0] = 0;

448 len = 1;

449 /* FALLTHROUGH */

450 case DeviceOutRequest | USB_REQ_SET_INTERFACE:

451 break;

452 case DeviceOutRequest | USB_REQ_SET_ADDRESS:

453 // wValue == urb->dev->devaddr

454 dev_dbg (hcd->self.controller, "root hub device address %d/n",

455 wValue);

456 break;

457

458 /* INTERFACE REQUESTS (no defined feature/status flags) */

459

460 /* ENDPOINT REQUESTS */

461

462 case EndpointRequest | USB_REQ_GET_STATUS:

463 // ENDPOINT_HALT flag

464 tbuf [0] = 0;

465 tbuf [1] = 0;

466 len = 2;

467 /* FALLTHROUGH */

468 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:

469 case EndpointOutRequest | USB_REQ_SET_FEATURE:

470 dev_dbg (hcd->self.controller, "no endpoint features yet/n");

471 break;

472

473 /* CLASS REQUESTS (and errors) */

474

475 default:

476 /* non-generic request */

477 switch (typeReq) {

478 case GetHubStatus:

479 case GetPortStatus:

480 len = 4;

481 break;

482 case GetHubDescriptor:

483 len = sizeof (struct usb_hub_descriptor);

484 break;

485 }

486 status = hcd->driver->hub_control (hcd,

487 typeReq, wValue, wIndex,

488 tbuf, wLength);

489 break;

490 error:

491 /* "protocol stall" on error */

492 status = -EPIPE;

493 }

494

495 if (status) {

496 len = 0;

497 if (status != -EPIPE) {

498 dev_dbg (hcd->self.controller,

499 "CTRL: TypeReq=0x%x val=0x%x "

500 "idx=0x%x len=%d ==> %d/n",

501 typeReq, wValue, wIndex,

502 wLength, status);

503 }

504 }

505 if (len) {

506 if (urb->transfer_buffer_length < len)

507 len = urb->transfer_buffer_length;

508 urb->actual_length = len;

509 // always USB_DIR_IN, toward host

510 memcpy (ubuf, bufp, len);

511

512 /* report whether RH hardware supports remote wakeup */

513 if (patch_wakeup &&

514 len > offsetof (struct usb_config_descriptor,

515 bmAttributes))

516 ((struct usb_config_descriptor *)ubuf)->bmAttributes

517 |= USB_CONFIG_ATT_WAKEUP;

518 }

519

520 /* any errors get returned through the urb completion */

521 local_irq_save (flags);

522 spin_lock (&urb->lock);

523 if (urb->status == -EINPROGRESS)

524 urb->status = status;

525 spin_unlock (&urb->lock);

526 usb_hcd_giveback_urb (hcd, urb);

527 local_irq_restore (flags);

528 return 0;

529 }

看到这样近200行的函数,真是有一种叫天天不灵叫地地不应的感觉.不幸中的万幸,这个函数的结构还是很清晰的.自上而下的看过来就可以了.

对于控制传输,首先要获得它的setup_packet,来自urb结构体,正如我们当初在usb-storage中看到的那样.这里把这个setup_packet赋给cmd指针.然后把其中的各个成员都给取出来,分别放在临时变量typeReq,wValue,wIndex,wLength,然后来判断这个typeReq.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_STATUS,,设置len2.

如果是设备请求并且方向是OUT,而且是USB_REQ_CLEAR_FEATURE,则如何如何.

如果是设备请求并且方向是OUT,而且是USB_REQ_SET_FEATURE,则如何如何.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_CONFIGURATION,则设置len1.

如果是设备请求并且方向是OUT,而且是USB_REQ_SET_CONFIGURATION,则啥也不做.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_DESCRIPTOR,则继续判断,wValue到底是什么来决定究竟是要获得什么描述符.如果是USB_DT_DEVICE,则说明要获得的是设备描述符,这正是咱们的上下文,而整个这段函数中其它的内容就只相当于顺便看看.(咱们传递给usb_get_descriptor的第二个参数就是USB_DT_DEVICE,传递给usb_control_msg的第三个参数正是USB_REQ_GET_DESCRIPTOR.)如果是USB_DT_CONFIG,则说明要获得的是配置描述符,如果是USB_DT_STRING,则说明要获得的是字符串描述符.实际上,对于Root Hub来说,这些东西都是一样的,咱们在drivers/usb/core/hcd.c中都预先定义好了,usb2_rh_dev_descriptor是针对usb 2.0,usb11_rh_dev_descriptor是针对usb 1.1,咱们的uhci driver里面设置了flagsHCD_USB11.

108 /*-------------------------------------------------------------------------*/

109

110 /*

111 * Sharable chunks of root hub code.

112 */

113

114 /*-------------------------------------------------------------------------*/

115

116 #define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)

117 #define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)

118

119 /* usb 2.0 root hub device descriptor */

120 static const u8 usb2_rh_dev_descriptor [18] = {

121 0x12, /* __u8 bLength; */

122 0x01, /* __u8 bDescriptorType; Device */

123 0x00, 0x02, /* __le16 bcdUSB; v2.0 */

124

125 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */

126 0x00, /* __u8 bDeviceSubClass; */

127 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/

128 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */

129

130 0x00, 0x00, /* __le16 idVendor; */

131 0x00, 0x00, /* __le16 idProduct; */

132 KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */

133

134 0x03, /* __u8 iManufacturer; */

135 0x02, /* __u8 iProduct; */

136 0x01, /* __u8 iSerialNumber; */

137 0x01 /* __u8 bNumConfigurations; */

138 };

139

140 /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */

141

142 /* usb 1.1 root hub device descriptor */

143 static const u8 usb11_rh_dev_descriptor [18] = {

144 0x12, /* __u8 bLength; */

145 0x01, /* __u8 bDescriptorType; Device */

146 0x10, 0x01, /* __le16 bcdUSB; v1.1 */

147

148 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */

149 0x00, /* __u8 bDeviceSubClass; */

150 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */

151 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */

152

153 0x00, 0x00, /* __le16 idVendor; */

154 0x00, 0x00, /* __le16 idProduct; */

155 KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */

156

157 0x03, /* __u8 iManufacturer; */

158 0x02, /* __u8 iProduct; */

159 0x01, /* __u8 iSerialNumber; */

160 0x01 /* __u8 bNumConfigurations; */

161 };

162

163

164 /*-------------------------------------------------------------------------*/

165

166 /* Configuration descriptors for our root hubs */

167

168 static const u8 fs_rh_config_descriptor [] = {

169

170 /* one configuration */

171 0x09, /* __u8 bLength; */

172 0x02, /* __u8 bDescriptorType; Configuration */

173 0x19, 0x00, /* __le16 wTotalLength; */

174 0x01, /* __u8 bNumInterfaces; (1) */

175 0x01, /* __u8 bConfigurationValue; */

176 0x00, /* __u8 iConfiguration; */

177 0xc0, /* __u8 bmAttributes;

178 Bit 7: must be set,

179 6: Self-powered,

180 5: Remote wakeup,

181 4..0: resvd */

182 0x00, /* __u8 MaxPower; */

183

184 /* USB 1.1:

185 * USB 2.0, single TT organization (mandatory):

186 * one interface, protocol 0

187 *

188 * USB 2.0, multiple TT organization (optional):

189 * two interfaces, protocols 1 (like single TT)

190 * and 2 (multiple TT mode) ... config is

191 * sometimes settable

192 * NOT IMPLEMENTED

193 */

194

195 /* one interface */

196 0x09, /* __u8 if_bLength; */

197 0x04, /* __u8 if_bDescriptorType; Interface */

198 0x00, /* __u8 if_bInterfaceNumber; */

199 0x00, /* __u8 if_bAlternateSetting; */

200 0x01, /* __u8 if_bNumEndpoints; */

201 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */

202 0x00, /* __u8 if_bInterfaceSubClass; */

203 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */

204 0x00, /* __u8 if_iInterface; */

205

206 /* one endpoint (status change endpoint) */

207 0x07, /* __u8 ep_bLength; */

208 0x05, /* __u8 ep_bDescriptorType; Endpoint */

209 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */

210 0x03, /* __u8 ep_bmAttributes; Interrupt */

211 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */

212 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */

213 };

214

215 static const u8 hs_rh_config_descriptor [] = {

216

217 /* one configuration */

218 0x09, /* __u8 bLength; */

219 0x02, /* __u8 bDescriptorType; Configuration */

220 0x19, 0x00, /* __le16 wTotalLength; */

221 0x01, /* __u8 bNumInterfaces; (1) */

222 0x01, /* __u8 bConfigurationValue; */

223 0x00, /* __u8 iConfiguration; */

224 0xc0, /* __u8 bmAttributes;

225 Bit 7: must be set,

226 6: Self-powered,

227 5: Remote wakeup,

228 4..0: resvd */

229 0x00, /* __u8 MaxPower; */

230

231 /* USB 1.1:

232 * USB 2.0, single TT organization (mandatory):

233 * one interface, protocol 0

234 *

235 * USB 2.0, multiple TT organization (optional):

236 * two interfaces, protocols 1 (like single TT)

237 * and 2 (multiple TT mode) ... config is

238 * sometimes settable

239 * NOT IMPLEMENTED

240 */

241

242 /* one interface */

243 0x09, /* __u8 if_bLength; */

244 0x04, /* __u8 if_bDescriptorType; Interface */

245 0x00, /* __u8 if_bInterfaceNumber; */

246 0x00, /* __u8 if_bAlternateSetting; */

247 0x01, /* __u8 if_bNumEndpoints; */

248 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */

249 0x00, /* __u8 if_bInterfaceSubClass; */

250 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */

251 0x00, /* __u8 if_iInterface; */

252

253 /* one endpoint (status change endpoint) */

254 0x07, /* __u8 ep_bLength; */

255 0x05, /* __u8 ep_bDescriptorType; Endpoint */

256 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */

257 0x03, /* __u8 ep_bmAttributes; Interrupt */

258 /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)

259 * see hub.c:hub_configure() for details. */

260 (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,

261 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */

262 };

如果是设备请求且方向为IN,而且是USB_REQ_GET_INTERFACE,则设置len1

如果是设备请求且方向为OUT,而且是USB_REQ_SET_INTERFACE,则如何如何.

如果是设备请求且方向为OUT,而且是USB_REQ_SET_ADDRESS,则如何如何.

如果是端点请求且方向为IN,而且是USB_REQ_GET_STATUS,则如何如何.

如果是端点请求且方向为OUT,而且是USB_REQ_CLEAR_FEATURE或者USB_REQ_SET_FEATURE,则如何如何.

以上这些设置,统统是和usb spec中规定的东西相匹配的.

如果是Hub特定的类请求,而且是GetHubStatus或者是GetPortStatus,则设置len4.

如果是Hub特定的类请求,而且是GetHubDescriptor,则设置lenusb_hub_descriptor结构体的大小.

最后对于Hub特定的类请求需要调用主机控制器驱动程序的hub_control函数,对于uhci_driver来说,这个指针被赋值为uhci_hub_control,来自drivers/usb/host/uhci-hub.c:

238 /* size of returned buffer is part of USB spec */

239 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

240 u16 wIndex, char *buf, u16 wLength)

241 {

242 struct uhci_hcd *uhci = hcd_to_uhci(hcd);

243 int status, lstatus, retval = 0, len = 0;

244 unsigned int port = wIndex - 1;

245 unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;

246 u16 wPortChange, wPortStatus;

247 unsigned long flags;

248

249 if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)

250 return -ETIMEDOUT;

251

252 spin_lock_irqsave(&uhci->lock, flags);

253 switch (typeReq) {

254

255 case GetHubStatus:

256 *(__le32 *)buf = cpu_to_le32(0);

257 OK(4); /* hub power */

258 case GetPortStatus:

259 if (port >= uhci->rh_numports)

260 goto err;

261

262 uhci_check_ports(uhci);

263 status = inw(port_addr);

264

265 /* Intel controllers report the OverCurrent bit active on.

266 * VIA controllers report it active off, so we'll adjust the

267 * bit value. (It's not standardized in the UHCI spec.)

268 */

269 if (to_pci_dev(hcd->self.controller)->vendor ==

270 PCI_VENDOR_ID_VIA)

271 status ^= USBPORTSC_OC;

272

273 /* UHCI doesn't support C_RESET (always false) */

274 wPortChange = lstatus = 0;

275 if (status & USBPORTSC_CSC)

276 wPortChange |= USB_PORT_STAT_C_CONNECTION;

277 if (status & USBPORTSC_PEC)

278 wPortChange |= USB_PORT_STAT_C_ENABLE;

279 if ((status & USBPORTSC_OCC) && !ignore_oc)

280 wPortChange |= USB_PORT_STAT_C_OVERCURRENT;

281

282 if (test_bit(port, &uhci->port_c_suspend)) {

283 wPortChange |= USB_PORT_STAT_C_SUSPEND;

284 lstatus |= 1;

285 }

286 if (test_bit(port, &uhci->resuming_ports))

287 lstatus |= 4;

288

289 /* UHCI has no power switching (always on) */

290 wPortStatus = USB_PORT_STAT_POWER;

291 if (status & USBPORTSC_CCS)

292 wPortStatus |= USB_PORT_STAT_CONNECTION;

293 if (status & USBPORTSC_PE) {

294 wPortStatus |= USB_PORT_STAT_ENABLE;

295 if (status & SUSPEND_BITS)

296 wPortStatus |= USB_PORT_STAT_SUSPEND;

297 }

298 if (status & USBPORTSC_OC)

299 wPortStatus |= USB_PORT_STAT_OVERCURRENT;

300 if (status & USBPORTSC_PR)

301 wPortStatus |= USB_PORT_STAT_RESET;

302 if (status & USBPORTSC_LSDA)

303 wPortStatus |= USB_PORT_STAT_LOW_SPEED;

304

305 if (wPortChange)

306 dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x/n",

307 wIndex, status, lstatus);

308

309 *(__le16 *)buf = cpu_to_le16(wPortStatus);

310 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);

311 OK(4);

312 case SetHubFeature: /* We don't implement these */

313 case ClearHubFeature:

314 switch (wValue) {

315 case C_HUB_OVER_CURRENT:

316 case C_HUB_LOCAL_POWER:

317 OK(0);

318 default:

319 goto err;

320 }

321 break;

322 case SetPortFeature:

323 if (port >= uhci->rh_numports)

324 goto err;

325

326 switch (wValue) {

327 case USB_PORT_FEAT_SUSPEND:

328 SET_RH_PORTSTAT(USBPORTSC_SUSP);

329 OK(0);

330 case USB_PORT_FEAT_RESET:

331 SET_RH_PORTSTAT(USBPORTSC_PR);

332

333 /* Reset terminates Resume signalling */

334 uhci_finish_suspend(uhci, port, port_addr);

335

336 /* USB v2.0 7.1.7.5 */

337 uhci->ports_timeout = jiffies + msecs_to_jiffies(50);

338 OK(0);

339 case USB_PORT_FEAT_POWER:

340 /* UHCI has no power switching */

341 OK(0);

342 default:

343 goto err;

344 }

345 break;

346 case ClearPortFeature:

347 if (port >= uhci->rh_numports)

348 goto err;

349

350 switch (wValue) {

351 case USB_PORT_FEAT_ENABLE:

352 CLR_RH_PORTSTAT(USBPORTSC_PE);

353

354 /* Disable terminates Resume signalling */

355 uhci_finish_suspend(uhci, port, port_addr);

356 OK(0);

357 case USB_PORT_FEAT_C_ENABLE:

358 CLR_RH_PORTSTAT(USBPORTSC_PEC);

359 OK(0);

360 case USB_PORT_FEAT_SUSPEND:

361 if (!(inw(port_addr) & USBPORTSC_SUSP)) {

362

363 /* Make certain the port isn't suspended */

364 uhci_finish_suspend(uhci, port, port_addr);

365 } else if (!test_and_set_bit(port,

366 &uhci->resuming_ports)) {

367 SET_RH_PORTSTAT(USBPORTSC_RD);

368

369 /* The controller won't allow RD to be set

370 * if the port is disabled. When this happens

371 * just skip the Resume signalling.

372 */

373 if (!(inw(port_addr) & USBPORTSC_RD))

374 uhci_finish_suspend(uhci, port,

375 port_addr);

376 else

377 /* USB v2.0 7.1.7.7 */

378 uhci->ports_timeout = jiffies +

379 msecs_to_jiffies(20);

380 }

381 OK(0);

382 case USB_PORT_FEAT_C_SUSPEND:

383 clear_bit(port, &uhci->port_c_suspend);

384 OK(0);

385 case USB_PORT_FEAT_POWER:

386 /* UHCI has no power switching */

387 goto err;

388 case USB_PORT_FEAT_C_CONNECTION:

389 CLR_RH_PORTSTAT(USBPORTSC_CSC);

390 OK(0);

391 case USB_PORT_FEAT_C_OVER_CURRENT:

392 CLR_RH_PORTSTAT(USBPORTSC_OCC);

393 OK(0);

394 case USB_PORT_FEAT_C_RESET:

395 /* this driver won't report these */

396 OK(0);

397 default:

398 goto err;

399 }

400 break;

401 case GetHubDescriptor:

402 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);

403 memcpy(buf, root_hub_hub_des, len);

404 if (len > 2)

405 buf[2] = uhci->rh_numports;

406 OK(len);

407 default:

408 err:

409 retval = -EPIPE;

410 }

411 spin_unlock_irqrestore(&uhci->lock, flags);

412

413 return retval;

414 }

服了,彻底服了,变态的函数一个接着一个.莫非这群混蛋写一个200行的函数就跟我写一个20行的函数一样随便?

249,struct usb_hcd结构体的成员unsigned long flags,咱们当初在usb_add_hcd中调用set_bit函数设置了这么一个flag,HCD_FLAG_HW_ACCESSIBLE,基本上这个flag在咱们的故事中是被设置了的.另外,struct uhci_hcd结构体有一个成员unsigned int dead,它如果为1就表明控制器挂了.

然后用一个switch来处理hub特定的类请求.OK居然也是一个宏,定义于drivers/usb/host/uhci-hub.c:

78 #define OK(x) len = (x); break

所以如果请求是GetHubStatus,则设置len4.

如果请求是GetPortStatus,则调用uhci_check_ports.然后读端口寄存器.USBPORTSC_CSC表示端口连接有变化,USBPORTSC_PEC表示Port Enable有变化.USBPORTSC_OCC表示Over Current有变化,struct uhci_hcd的两个成员,port_c_suspendresuming_ports都是电源管理相关的.

但无论如何,以上所做的这些都是为了获得两个东西,wPortStatuswPortChange.以此来响应GetPortStatus这个请求.

接下来,SetHubFeatureClearHubFeature咱们没啥好说的,不需要做什么.

但是SetPortFeature就有事情要做了.wValue表明具体是什么特征.

SET_RH_PORTSTAT这个宏就是专门用于设置Root Hub的端口特征的.

80 #define CLR_RH_PORTSTAT(x) /

81 status = inw(port_addr); /

82 status &= ~(RWC_BITS|WZ_BITS); /

83 status &= ~(x); /

84 status |= RWC_BITS & (x); /

85 outw(status, port_addr)

86

87 #define SET_RH_PORTSTAT(x) /

88 status = inw(port_addr); /

89 status |= (x); /

90 status &= ~(RWC_BITS|WZ_BITS); /

91 outw(status, port_addr)

对于USB_PORT_FEAT_RESET,还需要调用uhci_finish_suspend.

如果是USB_PORT_FEAT_POWER,则什么也不做,因为UHCI不吃这一套.

如果请求是ClearPortFeature,基本上也是一样的做法.除了调用的宏变成了CLR_RH_PORTSTAT.

如果请求是GetHubDescriptor,那就满足它呗.root_hub_hub_des是早就在drivers/usb/host/uhci-hub.c中定义好的:

15 static __u8 root_hub_hub_des[] =

16 {

17 0x09, /* __u8 bLength; */

18 0x29, /* __u8 bDescriptorType; Hub-descriptor */

19 0x02, /* __u8 bNbrPorts; */

20 0x0a, /* __u16 wHubCharacteristics; */

21 0x00, /* (per-port OC, no power switching) */

22 0x01, /* __u8 bPwrOn2pwrGood; 2ms */

23 0x00, /* __u8 bHubContrCurrent; 0 mA */

24 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */

25 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */

26 };

回到rh_call_control,switch结束了,下面是判断statuslen.

然后调用usb_hcd_giveback_urb().来自drivers/usb/core/hcd.c:

1373 /**

1374 * usb_hcd_giveback_urb - return URB from HCD to device driver

1375 * @hcd: host controller returning the URB

1376 * @urb: urb being returned to the USB device driver.

1377 * Context: in_interrupt()

1378 *

1379 * This hands the URB from HCD to its USB device driver, using its

1380 * completion function. The HCD has freed all per-urb resources

1381 * (and is done using urb->hcpriv). It also released all HCD locks;

1382 * the device driver won't cause problems if it frees, modifies,

1383 * or resubmits this URB.

1384 */

1385 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)

1386 {

1387 int at_root_hub;

1388

1389 at_root_hub = (urb->dev == hcd->self.root_hub);

1390 urb_unlink (urb);

1391

1392 /* lower level hcd code should use *_dma exclusively if the

1393 * host controller does DMA */

1394 if (hcd->self.uses_dma && !at_root_hub) {

1395 if (usb_pipecontrol (urb->pipe)

1396 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))

1397 dma_unmap_single (hcd->self.controller, urb->setup_dma,

1398 sizeof (struct usb_ctrlrequest),

1399 DMA_TO_DEVICE);

1400 if (urb->transfer_buffer_length != 0

1401 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))

1402 dma_unmap_single (hcd->self.controller,

1403 urb->transfer_dma,

1404 urb->transfer_buffer_length,

1405 usb_pipein (urb->pipe)

1406 ? DMA_FROM_DEVICE

1407 : DMA_TO_DEVICE);

1408 }

1409

1410 usbmon_urb_complete (&hcd->self, urb);

1411 /* pass ownership to the completion handler */

1412 urb->complete (urb);

1413 atomic_dec (&urb->use_count);

1414 if (unlikely (urb->reject))

1415 wake_up (&usb_kill_urb_queue);

1416 usb_put_urb (urb);

1417 }

1418 EXPORT_SYMBOL (usb_hcd_giveback_urb);

这里最重要最有意义的一行当然就是1412,调用urbcomplete函数,这正是我们在usb-storage里期待的那个函数.从此rh_call_control函数也该返回了,以后设备驱动又获得了控制权.事实上令人欣喜的是对于Root Hub,1394行开始的这一段if是不会被执行的,因为at_root_hub显然是为真.不过就算这段要执行也没什么可怕的,无非就是把之前为这个urb建立的dma映射给取消掉.而另一方面,对于Root Hub来说,complete函数基本上是什么也不做,只不过是让咱们再次回到usb_start_wait_urb,而控制传输需要的数据也已经copy到了urb->transfer_buffer中去了. 至此,Root Hub的控制传输就算结束了,即我们的usb_get_device_descriptor函数取得了空前绝后的圆满成功.

分享到:
评论

相关推荐

    Linux那些事儿

    Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我...

    Linux那些事儿1-9合集

    linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿...

    Linux那些事儿之我是UHCI

    写一下UHCI吧,也顺便怀念一下Intel,以及Intel的那几个女同事们,好久没联系了,你们可好? UHCI是 Intel提出来的.虽然离开 Intel一年多了,但我总觉得也许有一天我还会回到 Intel.所 以关于 Intel的东西,我多少会关注...

    linux那些事儿(EHCI Block SCSI Sysfs PCI USB U 盘 UHCI Hub)

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是USB core.pdf Linux 那些...

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    linux的那些事儿全集

    Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之...

    linux那些事全集

    Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是PCI Linux那些事儿之我是Hub Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层

    Linux那些事儿.rar

    Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...

    Linux那些事儿系列

    本人整理的fudan_abc的专栏中以完结的文章,在此向原作者表示感谢,给...内容包括:linux那些事儿之我是U盘,linux那些事儿之我是USB,linux那些事儿之我是HUB,linux那些事儿之我是UHCI,linux那些事儿之我是Sysfs。

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs,UHCI,usb core,U盘,此处,先...

    Linux那些事儿之我是XXX全集.rar

    Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析

    Linux那些事系列

    Linux那些事儿之我是Hub Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘 Linux那些事之我是HUB1

    linux那些事儿之我是USB.zip

    里面包含Linux那些事的九个文档,Block层,ECHI主机控制,HUB,PCI,SCSI硬盘,Sysfs,UHCI,USB+core,U盘等九个文档,内容详细,而且全面都有书签,适合系统学习!

    微信生活缴费商业项目标准版

    Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...

    usb那些事的全集

    2 Linux那些事儿之我是EHCI主机控制器 3 Linux那些事儿之我是HUB 4 Linux那些事儿之我是PCI 5 Linux那些事儿之我是SCSI硬盘 6 Linux那些事儿之我是Sysfs 7 Linux那些事儿之我是UHCI 8 Linux那些事儿之我是USB+core 9...

    Linux那些事儿[完整版]自己整理

    我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核

    Linux那些事儿(包括Hub, Sysfs, UHCI, USB, U盘5个部分)

    一个很经典的东东,里面的很多东西都很有启发性,值得看看

    LINUX那些事儿 linux经典之作

    我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 其中我是U盘属于基础性的.这一阶段会遇到一些问题.比如urb提交之后究竟怎么处理的?用户空间究竟是如何访问U盘的?DMA究竟怎么回事. 这之后可以开始看Hub.这一阶段你会明白一...

    linux那些事儿.rar

    linux那些事儿,Block层,EHCI主机控制器,Hub,PCI,SCSI硬盘,Sysfs,UHCI,USB core,U盘等文档。

Global site tag (gtag.js) - Google Analytics