1 /* 2 * Copyright (c) 2013 Gerhard Sittig <gsi@denx.de> 3 * based on the U-Boot Asix driver as well as information 4 * from the Linux Moschip driver 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 /* 10 * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices 11 */ 12 13 #include <common.h> 14 #include <errno.h> 15 #include <linux/mii.h> 16 #include <malloc.h> 17 #include <memalign.h> 18 #include <usb.h> 19 20 #include "usb_ether.h" 21 22 #define MCS7830_BASE_NAME "mcs" 23 24 #define USBCALL_TIMEOUT 1000 25 #define LINKSTATUS_TIMEOUT 5000 /* link status, connect timeout */ 26 #define LINKSTATUS_TIMEOUT_RES 50 /* link status, resolution in msec */ 27 28 #define MCS7830_RX_URB_SIZE 2048 29 30 /* command opcodes */ 31 #define MCS7830_WR_BREQ 0x0d 32 #define MCS7830_RD_BREQ 0x0e 33 34 /* register layout, numerical offset specs for USB API calls */ 35 struct mcs7830_regs { 36 uint8_t multicast_hashes[8]; 37 uint8_t packet_gap[2]; 38 uint8_t phy_data[2]; 39 uint8_t phy_command[2]; 40 uint8_t configuration; 41 uint8_t ether_address[6]; 42 uint8_t frame_drop_count; 43 uint8_t pause_threshold; 44 }; 45 #define REG_MULTICAST_HASH offsetof(struct mcs7830_regs, multicast_hashes) 46 #define REG_PHY_DATA offsetof(struct mcs7830_regs, phy_data) 47 #define REG_PHY_CMD offsetof(struct mcs7830_regs, phy_command) 48 #define REG_CONFIG offsetof(struct mcs7830_regs, configuration) 49 #define REG_ETHER_ADDR offsetof(struct mcs7830_regs, ether_address) 50 #define REG_FRAME_DROP_COUNTER offsetof(struct mcs7830_regs, frame_drop_count) 51 #define REG_PAUSE_THRESHOLD offsetof(struct mcs7830_regs, pause_threshold) 52 53 /* bit masks and default values for the above registers */ 54 #define PHY_CMD1_READ 0x40 55 #define PHY_CMD1_WRITE 0x20 56 #define PHY_CMD1_PHYADDR 0x01 57 58 #define PHY_CMD2_PEND 0x80 59 #define PHY_CMD2_READY 0x40 60 61 #define CONF_CFG 0x80 62 #define CONF_SPEED100 0x40 63 #define CONF_FDX_ENABLE 0x20 64 #define CONF_RXENABLE 0x10 65 #define CONF_TXENABLE 0x08 66 #define CONF_SLEEPMODE 0x04 67 #define CONF_ALLMULTICAST 0x02 68 #define CONF_PROMISCUOUS 0x01 69 70 #define PAUSE_THRESHOLD_DEFAULT 0 71 72 /* bit masks for the status byte which follows received ethernet frames */ 73 #define STAT_RX_FRAME_CORRECT 0x20 74 #define STAT_RX_LARGE_FRAME 0x10 75 #define STAT_RX_CRC_ERROR 0x08 76 #define STAT_RX_ALIGNMENT_ERROR 0x04 77 #define STAT_RX_LENGTH_ERROR 0x02 78 #define STAT_RX_SHORT_FRAME 0x01 79 80 /* 81 * struct mcs7830_private - private driver data for an individual adapter 82 * @config: shadow for the network adapter's configuration register 83 * @mchash: shadow for the network adapter's multicast hash registers 84 */ 85 struct mcs7830_private { 86 uint8_t config; 87 uint8_t mchash[8]; 88 }; 89 90 /* 91 * mcs7830_read_reg() - read a register of the network adapter 92 * @udev: network device to read from 93 * @idx: index of the register to start reading from 94 * @size: number of bytes to read 95 * @data: buffer to read into 96 * Return: zero upon success, negative upon error 97 */ 98 static int mcs7830_read_reg(struct usb_device *udev, uint8_t idx, 99 uint16_t size, void *data) 100 { 101 int len; 102 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size); 103 104 debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size); 105 106 len = usb_control_msg(udev, 107 usb_rcvctrlpipe(udev, 0), 108 MCS7830_RD_BREQ, 109 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 110 0, idx, buf, size, 111 USBCALL_TIMEOUT); 112 if (len != size) { 113 debug("%s() len=%d != sz=%d\n", __func__, len, size); 114 return -EIO; 115 } 116 memcpy(data, buf, size); 117 return 0; 118 } 119 120 /* 121 * mcs7830_write_reg() - write a register of the network adapter 122 * @udev: network device to write to 123 * @idx: index of the register to start writing to 124 * @size: number of bytes to write 125 * @data: buffer holding the data to write 126 * Return: zero upon success, negative upon error 127 */ 128 static int mcs7830_write_reg(struct usb_device *udev, uint8_t idx, 129 uint16_t size, void *data) 130 { 131 int len; 132 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size); 133 134 debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size); 135 136 memcpy(buf, data, size); 137 len = usb_control_msg(udev, 138 usb_sndctrlpipe(udev, 0), 139 MCS7830_WR_BREQ, 140 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 141 0, idx, buf, size, 142 USBCALL_TIMEOUT); 143 if (len != size) { 144 debug("%s() len=%d != sz=%d\n", __func__, len, size); 145 return -EIO; 146 } 147 return 0; 148 } 149 150 /* 151 * mcs7830_phy_emit_wait() - emit PHY read/write access, wait for its execution 152 * @udev: network device to talk to 153 * @rwflag: PHY_CMD1_READ or PHY_CMD1_WRITE opcode 154 * @index: number of the PHY register to read or write 155 * Return: zero upon success, negative upon error 156 */ 157 static int mcs7830_phy_emit_wait(struct usb_device *udev, 158 uint8_t rwflag, uint8_t index) 159 { 160 int rc; 161 int retry; 162 uint8_t cmd[2]; 163 164 /* send the PHY read/write request */ 165 cmd[0] = rwflag | PHY_CMD1_PHYADDR; 166 cmd[1] = PHY_CMD2_PEND | (index & 0x1f); 167 rc = mcs7830_write_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd); 168 if (rc < 0) 169 return rc; 170 171 /* wait for the response to become available (usually < 1ms) */ 172 retry = 10; 173 do { 174 rc = mcs7830_read_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd); 175 if (rc < 0) 176 return rc; 177 if (cmd[1] & PHY_CMD2_READY) 178 return 0; 179 if (!retry--) 180 return -ETIMEDOUT; 181 mdelay(1); 182 } while (1); 183 /* UNREACH */ 184 } 185 186 /* 187 * mcs7830_read_phy() - read a PHY register of the network adapter 188 * @udev: network device to read from 189 * @index: index of the PHY register to read from 190 * Return: non-negative 16bit register content, negative upon error 191 */ 192 static int mcs7830_read_phy(struct usb_device *udev, uint8_t index) 193 { 194 int rc; 195 uint16_t val; 196 197 /* issue the PHY read request and wait for its execution */ 198 rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_READ, index); 199 if (rc < 0) 200 return rc; 201 202 /* fetch the PHY data which was read */ 203 rc = mcs7830_read_reg(udev, REG_PHY_DATA, sizeof(val), &val); 204 if (rc < 0) 205 return rc; 206 rc = le16_to_cpu(val); 207 debug("%s(%d) => 0x%04X\n", __func__, index, rc); 208 return rc; 209 } 210 211 /* 212 * mcs7830_write_phy() - write a PHY register of the network adapter 213 * @udev: network device to write to 214 * @index: index of the PHY register to write to 215 * @val: value to write to the PHY register 216 * Return: zero upon success, negative upon error 217 */ 218 static int mcs7830_write_phy(struct usb_device *udev, uint8_t index, 219 uint16_t val) 220 { 221 int rc; 222 223 debug("%s(%d, 0x%04X)\n", __func__, index, val); 224 225 /* setup the PHY data which is to get written */ 226 val = cpu_to_le16(val); 227 rc = mcs7830_write_reg(udev, REG_PHY_DATA, sizeof(val), &val); 228 if (rc < 0) 229 return rc; 230 231 /* issue the PHY write request and wait for its execution */ 232 rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_WRITE, index); 233 if (rc < 0) 234 return rc; 235 236 return 0; 237 } 238 239 /* 240 * mcs7830_write_config() - write to the network adapter's config register 241 * @udev: network device to write to 242 * @priv: private data 243 * Return: zero upon success, negative upon error 244 * 245 * the data which gets written is taken from the shadow config register 246 * within the device driver's private data 247 */ 248 static int mcs7830_write_config(struct usb_device *udev, 249 struct mcs7830_private *priv) 250 { 251 int rc; 252 253 debug("%s()\n", __func__); 254 255 rc = mcs7830_write_reg(udev, REG_CONFIG, 256 sizeof(priv->config), &priv->config); 257 if (rc < 0) { 258 debug("writing config to adapter failed\n"); 259 return rc; 260 } 261 262 return 0; 263 } 264 265 /* 266 * mcs7830_write_mchash() - write the network adapter's multicast filter 267 * @udev: network device to write to 268 * @priv: private data 269 * Return: zero upon success, negative upon error 270 * 271 * the data which gets written is taken from the shadow multicast hashes 272 * within the device driver's private data 273 */ 274 static int mcs7830_write_mchash(struct usb_device *udev, 275 struct mcs7830_private *priv) 276 { 277 int rc; 278 279 debug("%s()\n", __func__); 280 281 rc = mcs7830_write_reg(udev, REG_MULTICAST_HASH, 282 sizeof(priv->mchash), &priv->mchash); 283 if (rc < 0) { 284 debug("writing multicast hash to adapter failed\n"); 285 return rc; 286 } 287 288 return 0; 289 } 290 291 /* 292 * mcs7830_set_autoneg() - setup and trigger ethernet link autonegotiation 293 * @udev: network device to run link negotiation on 294 * Return: zero upon success, negative upon error 295 * 296 * the routine advertises available media and starts autonegotiation 297 */ 298 static int mcs7830_set_autoneg(struct usb_device *udev) 299 { 300 int adv, flg; 301 int rc; 302 303 debug("%s()\n", __func__); 304 305 /* 306 * algorithm taken from the Linux driver, which took it from 307 * "the original mcs7830 version 1.4 driver": 308 * 309 * enable all media, reset BMCR, enable auto neg, restart 310 * auto neg while keeping the enable auto neg flag set 311 */ 312 313 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_ALL | ADVERTISE_CSMA; 314 rc = mcs7830_write_phy(udev, MII_ADVERTISE, adv); 315 316 flg = 0; 317 if (!rc) 318 rc = mcs7830_write_phy(udev, MII_BMCR, flg); 319 320 flg |= BMCR_ANENABLE; 321 if (!rc) 322 rc = mcs7830_write_phy(udev, MII_BMCR, flg); 323 324 flg |= BMCR_ANRESTART; 325 if (!rc) 326 rc = mcs7830_write_phy(udev, MII_BMCR, flg); 327 328 return rc; 329 } 330 331 /* 332 * mcs7830_get_rev() - identify a network adapter's chip revision 333 * @udev: network device to identify 334 * Return: non-negative number, reflecting the revision number 335 * 336 * currently, only "rev C and higher" and "below rev C" are needed, so 337 * the return value is #1 for "below rev C", and #2 for "rev C and above" 338 */ 339 static int mcs7830_get_rev(struct usb_device *udev) 340 { 341 uint8_t buf[2]; 342 int rc; 343 int rev; 344 345 /* register 22 is readable in rev C and higher */ 346 rc = mcs7830_read_reg(udev, REG_FRAME_DROP_COUNTER, sizeof(buf), buf); 347 if (rc < 0) 348 rev = 1; 349 else 350 rev = 2; 351 debug("%s() rc=%d, rev=%d\n", __func__, rc, rev); 352 return rev; 353 } 354 355 /* 356 * mcs7830_apply_fixup() - identify an adapter and potentially apply fixups 357 * @udev: network device to identify and apply fixups to 358 * Return: zero upon success (no errors emitted from here) 359 * 360 * this routine identifies the network adapter's chip revision, and applies 361 * fixups for known issues 362 */ 363 static int mcs7830_apply_fixup(struct usb_device *udev) 364 { 365 int rev; 366 int i; 367 uint8_t thr; 368 369 rev = mcs7830_get_rev(udev); 370 debug("%s() rev=%d\n", __func__, rev); 371 372 /* 373 * rev C requires setting the pause threshold (the Linux driver 374 * is inconsistent, the implementation does it for "rev C 375 * exactly", the introductory comment says "rev C and above") 376 */ 377 if (rev == 2) { 378 debug("%s: applying rev C fixup\n", __func__); 379 thr = PAUSE_THRESHOLD_DEFAULT; 380 for (i = 0; i < 2; i++) { 381 (void)mcs7830_write_reg(udev, REG_PAUSE_THRESHOLD, 382 sizeof(thr), &thr); 383 mdelay(1); 384 } 385 } 386 387 return 0; 388 } 389 390 /* 391 * mcs7830_basic_reset() - bring the network adapter into a known first state 392 * @eth: network device to act upon 393 * Return: zero upon success, negative upon error 394 * 395 * this routine initializes the network adapter such that subsequent invocations 396 * of the interface callbacks can exchange ethernet frames; link negotiation is 397 * triggered from here already and continues in background 398 */ 399 static int mcs7830_basic_reset(struct usb_device *udev, 400 struct mcs7830_private *priv) 401 { 402 int rc; 403 404 debug("%s()\n", __func__); 405 406 /* 407 * comment from the respective Linux driver, which 408 * unconditionally sets the ALLMULTICAST flag as well: 409 * should not be needed, but does not work otherwise 410 */ 411 priv->config = CONF_TXENABLE; 412 priv->config |= CONF_ALLMULTICAST; 413 414 rc = mcs7830_set_autoneg(udev); 415 if (rc < 0) { 416 error("setting autoneg failed\n"); 417 return rc; 418 } 419 420 rc = mcs7830_write_mchash(udev, priv); 421 if (rc < 0) { 422 error("failed to set multicast hash\n"); 423 return rc; 424 } 425 426 rc = mcs7830_write_config(udev, priv); 427 if (rc < 0) { 428 error("failed to set configuration\n"); 429 return rc; 430 } 431 432 rc = mcs7830_apply_fixup(udev); 433 if (rc < 0) { 434 error("fixup application failed\n"); 435 return rc; 436 } 437 438 return 0; 439 } 440 441 /* 442 * mcs7830_read_mac() - read an ethernet adapter's MAC address 443 * @udev: network device to read from 444 * @enetaddr: place to put ethernet MAC address 445 * Return: zero upon success, negative upon error 446 * 447 * this routine fetches the MAC address stored within the ethernet adapter, 448 * and stores it in the ethernet interface's data structure 449 */ 450 static int mcs7830_read_mac(struct usb_device *udev, unsigned char enetaddr[]) 451 { 452 int rc; 453 uint8_t buf[ETH_ALEN]; 454 455 debug("%s()\n", __func__); 456 457 rc = mcs7830_read_reg(udev, REG_ETHER_ADDR, ETH_ALEN, buf); 458 if (rc < 0) { 459 debug("reading MAC from adapter failed\n"); 460 return rc; 461 } 462 463 memcpy(enetaddr, buf, ETH_ALEN); 464 return 0; 465 } 466 467 static int mcs7830_write_mac_common(struct usb_device *udev, 468 unsigned char enetaddr[]) 469 { 470 int rc; 471 472 debug("%s()\n", __func__); 473 474 rc = mcs7830_write_reg(udev, REG_ETHER_ADDR, ETH_ALEN, enetaddr); 475 if (rc < 0) { 476 debug("writing MAC to adapter failed\n"); 477 return rc; 478 } 479 return 0; 480 } 481 482 static int mcs7830_init_common(struct usb_device *udev) 483 { 484 int timeout; 485 int have_link; 486 487 debug("%s()\n", __func__); 488 489 timeout = 0; 490 do { 491 have_link = mcs7830_read_phy(udev, MII_BMSR) & BMSR_LSTATUS; 492 if (have_link) 493 break; 494 udelay(LINKSTATUS_TIMEOUT_RES * 1000); 495 timeout += LINKSTATUS_TIMEOUT_RES; 496 } while (timeout < LINKSTATUS_TIMEOUT); 497 if (!have_link) { 498 debug("ethernet link is down\n"); 499 return -ETIMEDOUT; 500 } 501 return 0; 502 } 503 504 static int mcs7830_send_common(struct ueth_data *ueth, void *packet, 505 int length) 506 { 507 struct usb_device *udev = ueth->pusb_dev; 508 int rc; 509 int gotlen; 510 /* there is a status byte after the ethernet frame */ 511 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, PKTSIZE + sizeof(uint8_t)); 512 513 memcpy(buf, packet, length); 514 rc = usb_bulk_msg(udev, 515 usb_sndbulkpipe(udev, ueth->ep_out), 516 &buf[0], length, &gotlen, 517 USBCALL_TIMEOUT); 518 debug("%s() TX want len %d, got len %d, rc %d\n", 519 __func__, length, gotlen, rc); 520 return rc; 521 } 522 523 static int mcs7830_recv_common(struct ueth_data *ueth, uint8_t *buf) 524 { 525 int rc, wantlen, gotlen; 526 uint8_t sts; 527 528 debug("%s()\n", __func__); 529 530 /* fetch input data from the adapter */ 531 wantlen = MCS7830_RX_URB_SIZE; 532 rc = usb_bulk_msg(ueth->pusb_dev, 533 usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in), 534 &buf[0], wantlen, &gotlen, 535 USBCALL_TIMEOUT); 536 debug("%s() RX want len %d, got len %d, rc %d\n", 537 __func__, wantlen, gotlen, rc); 538 if (rc != 0) { 539 error("RX: failed to receive\n"); 540 return rc; 541 } 542 if (gotlen > wantlen) { 543 error("RX: got too many bytes (%d)\n", gotlen); 544 return -EIO; 545 } 546 547 /* 548 * the bulk message that we received from USB contains exactly 549 * one ethernet frame and a trailing status byte 550 */ 551 if (gotlen < sizeof(sts)) 552 return -EIO; 553 gotlen -= sizeof(sts); 554 sts = buf[gotlen]; 555 556 if (sts == STAT_RX_FRAME_CORRECT) { 557 debug("%s() got a frame, len=%d\n", __func__, gotlen); 558 return gotlen; 559 } 560 561 debug("RX: frame error (sts 0x%02X, %s %s %s %s %s)\n", 562 sts, 563 (sts & STAT_RX_LARGE_FRAME) ? "large" : "-", 564 (sts & STAT_RX_LENGTH_ERROR) ? "length" : "-", 565 (sts & STAT_RX_SHORT_FRAME) ? "short" : "-", 566 (sts & STAT_RX_CRC_ERROR) ? "crc" : "-", 567 (sts & STAT_RX_ALIGNMENT_ERROR) ? "align" : "-"); 568 return -EIO; 569 } 570 571 /* 572 * mcs7830_init() - network interface's init callback 573 * @udev: network device to initialize 574 * @bd: board information 575 * Return: zero upon success, negative upon error 576 * 577 * after initial setup during probe() and get_info(), this init() callback 578 * ensures that the link is up and subsequent send() and recv() calls can 579 * exchange ethernet frames 580 */ 581 static int mcs7830_init(struct eth_device *eth, bd_t *bd) 582 { 583 struct ueth_data *dev = eth->priv; 584 585 return mcs7830_init_common(dev->pusb_dev); 586 } 587 588 /* 589 * mcs7830_send() - network interface's send callback 590 * @eth: network device to send the frame from 591 * @packet: ethernet frame content 592 * @length: ethernet frame length 593 * Return: zero upon success, negative upon error 594 * 595 * this routine send an ethernet frame out of the network interface 596 */ 597 static int mcs7830_send(struct eth_device *eth, void *packet, int length) 598 { 599 struct ueth_data *dev = eth->priv; 600 601 return mcs7830_send_common(dev, packet, length); 602 } 603 604 /* 605 * mcs7830_recv() - network interface's recv callback 606 * @eth: network device to receive frames from 607 * Return: zero upon success, negative upon error 608 * 609 * this routine checks for available ethernet frames that the network 610 * interface might have received, and notifies the network stack 611 */ 612 static int mcs7830_recv(struct eth_device *eth) 613 { 614 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, MCS7830_RX_URB_SIZE); 615 struct ueth_data *ueth = eth->priv; 616 int len; 617 618 len = mcs7830_recv_common(ueth, buf); 619 if (len <= 0) 620 net_process_received_packet(buf, len); 621 622 return 0; 623 } 624 625 /* 626 * mcs7830_halt() - network interface's halt callback 627 * @eth: network device to cease operation of 628 * Return: none 629 * 630 * this routine is supposed to undo the effect of previous initialization and 631 * ethernet frames exchange; in this implementation it's a NOP 632 */ 633 static void mcs7830_halt(struct eth_device *eth) 634 { 635 debug("%s()\n", __func__); 636 } 637 638 /* 639 * mcs7830_write_mac() - write an ethernet adapter's MAC address 640 * @eth: network device to write to 641 * Return: zero upon success, negative upon error 642 * 643 * this routine takes the MAC address from the ethernet interface's data 644 * structure, and writes it into the ethernet adapter such that subsequent 645 * exchange of ethernet frames uses this address 646 */ 647 static int mcs7830_write_mac(struct eth_device *eth) 648 { 649 struct ueth_data *ueth = eth->priv; 650 651 return mcs7830_write_mac_common(ueth->pusb_dev, eth->enetaddr); 652 } 653 654 /* 655 * mcs7830_iface_idx - index of detected network interfaces 656 * 657 * this counter keeps track of identified supported interfaces, 658 * to assign unique names as more interfaces are found 659 */ 660 static int mcs7830_iface_idx; 661 662 /* 663 * mcs7830_eth_before_probe() - network driver's before_probe callback 664 * Return: none 665 * 666 * this routine initializes driver's internal data in preparation of 667 * subsequent probe callbacks 668 */ 669 void mcs7830_eth_before_probe(void) 670 { 671 mcs7830_iface_idx = 0; 672 } 673 674 /* 675 * struct mcs7830_dongle - description of a supported Moschip ethernet dongle 676 * @vendor: 16bit USB vendor identification 677 * @product: 16bit USB product identification 678 * 679 * this structure describes a supported USB ethernet dongle by means of the 680 * vendor and product codes found during USB enumeration; no flags are held 681 * here since all supported dongles have identical behaviour, and required 682 * fixups get determined at runtime, such that no manual configuration is 683 * needed 684 */ 685 struct mcs7830_dongle { 686 uint16_t vendor; 687 uint16_t product; 688 }; 689 690 /* 691 * mcs7830_dongles - the list of supported Moschip based USB ethernet dongles 692 */ 693 static const struct mcs7830_dongle mcs7830_dongles[] = { 694 { 0x9710, 0x7832, }, /* Moschip 7832 */ 695 { 0x9710, 0x7830, }, /* Moschip 7830 */ 696 { 0x9710, 0x7730, }, /* Moschip 7730 */ 697 { 0x0df6, 0x0021, }, /* Sitecom LN 30 */ 698 }; 699 700 /* 701 * mcs7830_eth_probe() - network driver's probe callback 702 * @dev: detected USB device to check 703 * @ifnum: detected USB interface to check 704 * @ss: USB ethernet data structure to fill in upon match 705 * Return: #1 upon match, #0 upon mismatch or error 706 * 707 * this routine checks whether the found USB device is supported by 708 * this ethernet driver, and upon match fills in the USB ethernet 709 * data structure which later is passed to the get_info callback 710 */ 711 int mcs7830_eth_probe(struct usb_device *dev, unsigned int ifnum, 712 struct ueth_data *ss) 713 { 714 struct usb_interface *iface; 715 struct usb_interface_descriptor *iface_desc; 716 int i; 717 struct mcs7830_private *priv; 718 int ep_in_found, ep_out_found, ep_intr_found; 719 720 debug("%s()\n", __func__); 721 722 /* iterate the list of supported dongles */ 723 iface = &dev->config.if_desc[ifnum]; 724 iface_desc = &iface->desc; 725 for (i = 0; i < ARRAY_SIZE(mcs7830_dongles); i++) { 726 if (dev->descriptor.idVendor == mcs7830_dongles[i].vendor && 727 dev->descriptor.idProduct == mcs7830_dongles[i].product) 728 break; 729 } 730 if (i == ARRAY_SIZE(mcs7830_dongles)) 731 return 0; 732 debug("detected USB ethernet device: %04X:%04X\n", 733 dev->descriptor.idVendor, dev->descriptor.idProduct); 734 735 /* fill in driver private data */ 736 priv = calloc(1, sizeof(*priv)); 737 if (!priv) 738 return 0; 739 740 /* fill in the ueth_data structure, attach private data */ 741 memset(ss, 0, sizeof(*ss)); 742 ss->ifnum = ifnum; 743 ss->pusb_dev = dev; 744 ss->subclass = iface_desc->bInterfaceSubClass; 745 ss->protocol = iface_desc->bInterfaceProtocol; 746 ss->dev_priv = priv; 747 748 /* 749 * a minimum of three endpoints is expected: in (bulk), 750 * out (bulk), and interrupt; ignore all others 751 */ 752 ep_in_found = ep_out_found = ep_intr_found = 0; 753 for (i = 0; i < iface_desc->bNumEndpoints; i++) { 754 uint8_t eptype, epaddr; 755 bool is_input; 756 757 eptype = iface->ep_desc[i].bmAttributes; 758 eptype &= USB_ENDPOINT_XFERTYPE_MASK; 759 760 epaddr = iface->ep_desc[i].bEndpointAddress; 761 is_input = epaddr & USB_DIR_IN; 762 epaddr &= USB_ENDPOINT_NUMBER_MASK; 763 764 if (eptype == USB_ENDPOINT_XFER_BULK) { 765 if (is_input && !ep_in_found) { 766 ss->ep_in = epaddr; 767 ep_in_found++; 768 } 769 if (!is_input && !ep_out_found) { 770 ss->ep_out = epaddr; 771 ep_out_found++; 772 } 773 } 774 775 if (eptype == USB_ENDPOINT_XFER_INT) { 776 if (is_input && !ep_intr_found) { 777 ss->ep_int = epaddr; 778 ss->irqinterval = iface->ep_desc[i].bInterval; 779 ep_intr_found++; 780 } 781 } 782 } 783 debug("endpoints: in %d, out %d, intr %d\n", 784 ss->ep_in, ss->ep_out, ss->ep_int); 785 786 /* apply basic sanity checks */ 787 if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || 788 !ss->ep_in || !ss->ep_out || !ss->ep_int) { 789 debug("device probe incomplete\n"); 790 return 0; 791 } 792 793 dev->privptr = ss; 794 return 1; 795 } 796 797 /* 798 * mcs7830_eth_get_info() - network driver's get_info callback 799 * @dev: detected USB device 800 * @ss: USB ethernet data structure filled in at probe() 801 * @eth: ethernet interface data structure to fill in 802 * Return: #1 upon success, #0 upon error 803 * 804 * this routine registers the mandatory init(), send(), recv(), and 805 * halt() callbacks with the ethernet interface, can register the 806 * optional write_hwaddr() callback with the ethernet interface, 807 * and initiates configuration of the interface such that subsequent 808 * calls to those callbacks results in network communication 809 */ 810 int mcs7830_eth_get_info(struct usb_device *dev, struct ueth_data *ss, 811 struct eth_device *eth) 812 { 813 debug("%s()\n", __func__); 814 if (!eth) { 815 debug("%s: missing parameter.\n", __func__); 816 return 0; 817 } 818 819 snprintf(eth->name, sizeof(eth->name), "%s%d", 820 MCS7830_BASE_NAME, mcs7830_iface_idx++); 821 eth->init = mcs7830_init; 822 eth->send = mcs7830_send; 823 eth->recv = mcs7830_recv; 824 eth->halt = mcs7830_halt; 825 eth->write_hwaddr = mcs7830_write_mac; 826 eth->priv = ss; 827 828 if (mcs7830_basic_reset(ss->pusb_dev, ss->dev_priv)) 829 return 0; 830 831 if (mcs7830_read_mac(ss->pusb_dev, eth->enetaddr)) 832 return 0; 833 debug("MAC %pM\n", eth->enetaddr); 834 835 return 1; 836 } 837