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 * @dev: 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 ueth_data *dev, 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(dev->pusb_dev, 107 usb_rcvctrlpipe(dev->pusb_dev, 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 * @dev: 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 ueth_data *dev, 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(dev->pusb_dev, 138 usb_sndctrlpipe(dev->pusb_dev, 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 * @dev: 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 ueth_data *dev, 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(dev, 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(dev, 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 * @dev: 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 ueth_data *dev, 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(dev, 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(dev, REG_PHY_DATA, sizeof(val), &val); 204 if (rc < 0) 205 return rc; 206 rc = le16_to_cpu(val); 207 debug("%s(%s, %d) => 0x%04X\n", __func__, dev->eth_dev.name, index, rc); 208 return rc; 209 } 210 211 /* 212 * mcs7830_write_phy() - write a PHY register of the network adapter 213 * @dev: 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 ueth_data *dev, uint8_t index, uint16_t val) 219 { 220 int rc; 221 222 debug("%s(%s, %d, 0x%04X)\n", __func__, dev->eth_dev.name, index, val); 223 224 /* setup the PHY data which is to get written */ 225 val = cpu_to_le16(val); 226 rc = mcs7830_write_reg(dev, REG_PHY_DATA, sizeof(val), &val); 227 if (rc < 0) 228 return rc; 229 230 /* issue the PHY write request and wait for its execution */ 231 rc = mcs7830_phy_emit_wait(dev, PHY_CMD1_WRITE, index); 232 if (rc < 0) 233 return rc; 234 235 return 0; 236 } 237 238 /* 239 * mcs7830_write_config() - write to the network adapter's config register 240 * @eth: network device to write to 241 * Return: zero upon success, negative upon error 242 * 243 * the data which gets written is taken from the shadow config register 244 * within the device driver's private data 245 */ 246 static int mcs7830_write_config(struct ueth_data *dev) 247 { 248 struct mcs7830_private *priv; 249 int rc; 250 251 debug("%s()\n", __func__); 252 priv = dev->dev_priv; 253 254 rc = mcs7830_write_reg(dev, REG_CONFIG, 255 sizeof(priv->config), &priv->config); 256 if (rc < 0) { 257 debug("writing config to adapter failed\n"); 258 return rc; 259 } 260 261 return 0; 262 } 263 264 /* 265 * mcs7830_write_mchash() - write the network adapter's multicast filter 266 * @eth: network device to write to 267 * Return: zero upon success, negative upon error 268 * 269 * the data which gets written is taken from the shadow multicast hashes 270 * within the device driver's private data 271 */ 272 static int mcs7830_write_mchash(struct ueth_data *dev) 273 { 274 struct mcs7830_private *priv; 275 int rc; 276 277 debug("%s()\n", __func__); 278 priv = dev->dev_priv; 279 280 rc = mcs7830_write_reg(dev, REG_MULTICAST_HASH, 281 sizeof(priv->mchash), &priv->mchash); 282 if (rc < 0) { 283 debug("writing multicast hash to adapter failed\n"); 284 return rc; 285 } 286 287 return 0; 288 } 289 290 /* 291 * mcs7830_set_autoneg() - setup and trigger ethernet link autonegotiation 292 * @eth: network device to run link negotiation on 293 * Return: zero upon success, negative upon error 294 * 295 * the routine advertises available media and starts autonegotiation 296 */ 297 static int mcs7830_set_autoneg(struct ueth_data *dev) 298 { 299 int adv, flg; 300 int rc; 301 302 debug("%s()\n", __func__); 303 304 /* 305 * algorithm taken from the Linux driver, which took it from 306 * "the original mcs7830 version 1.4 driver": 307 * 308 * enable all media, reset BMCR, enable auto neg, restart 309 * auto neg while keeping the enable auto neg flag set 310 */ 311 312 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_ALL | ADVERTISE_CSMA; 313 rc = mcs7830_write_phy(dev, MII_ADVERTISE, adv); 314 315 flg = 0; 316 if (!rc) 317 rc = mcs7830_write_phy(dev, MII_BMCR, flg); 318 319 flg |= BMCR_ANENABLE; 320 if (!rc) 321 rc = mcs7830_write_phy(dev, MII_BMCR, flg); 322 323 flg |= BMCR_ANRESTART; 324 if (!rc) 325 rc = mcs7830_write_phy(dev, MII_BMCR, flg); 326 327 return rc; 328 } 329 330 /* 331 * mcs7830_get_rev() - identify a network adapter's chip revision 332 * @eth: network device to identify 333 * Return: non-negative number, reflecting the revision number 334 * 335 * currently, only "rev C and higher" and "below rev C" are needed, so 336 * the return value is #1 for "below rev C", and #2 for "rev C and above" 337 */ 338 static int mcs7830_get_rev(struct ueth_data *dev) 339 { 340 uint8_t buf[2]; 341 int rc; 342 int rev; 343 344 /* register 22 is readable in rev C and higher */ 345 rc = mcs7830_read_reg(dev, REG_FRAME_DROP_COUNTER, sizeof(buf), buf); 346 if (rc < 0) 347 rev = 1; 348 else 349 rev = 2; 350 debug("%s() rc=%d, rev=%d\n", __func__, rc, rev); 351 return rev; 352 } 353 354 /* 355 * mcs7830_apply_fixup() - identify an adapter and potentially apply fixups 356 * @eth: network device to identify and apply fixups to 357 * Return: zero upon success (no errors emitted from here) 358 * 359 * this routine identifies the network adapter's chip revision, and applies 360 * fixups for known issues 361 */ 362 static int mcs7830_apply_fixup(struct ueth_data *dev) 363 { 364 int rev; 365 int i; 366 uint8_t thr; 367 368 rev = mcs7830_get_rev(dev); 369 debug("%s() rev=%d\n", __func__, rev); 370 371 /* 372 * rev C requires setting the pause threshold (the Linux driver 373 * is inconsistent, the implementation does it for "rev C 374 * exactly", the introductory comment says "rev C and above") 375 */ 376 if (rev == 2) { 377 debug("%s: applying rev C fixup\n", dev->eth_dev.name); 378 thr = PAUSE_THRESHOLD_DEFAULT; 379 for (i = 0; i < 2; i++) { 380 (void)mcs7830_write_reg(dev, REG_PAUSE_THRESHOLD, 381 sizeof(thr), &thr); 382 mdelay(1); 383 } 384 } 385 386 return 0; 387 } 388 389 /* 390 * mcs7830_basic_reset() - bring the network adapter into a known first state 391 * @eth: network device to act upon 392 * Return: zero upon success, negative upon error 393 * 394 * this routine initializes the network adapter such that subsequent invocations 395 * of the interface callbacks can exchange ethernet frames; link negotiation is 396 * triggered from here already and continues in background 397 */ 398 static int mcs7830_basic_reset(struct ueth_data *dev) 399 { 400 struct mcs7830_private *priv; 401 int rc; 402 403 debug("%s()\n", __func__); 404 priv = dev->dev_priv; 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(dev); 415 if (rc < 0) { 416 error("setting autoneg failed\n"); 417 return rc; 418 } 419 420 rc = mcs7830_write_mchash(dev); 421 if (rc < 0) { 422 error("failed to set multicast hash\n"); 423 return rc; 424 } 425 426 rc = mcs7830_write_config(dev); 427 if (rc < 0) { 428 error("failed to set configuration\n"); 429 return rc; 430 } 431 432 rc = mcs7830_apply_fixup(dev); 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 * @eth: network device to read from 444 * Return: zero upon success, negative upon error 445 * 446 * this routine fetches the MAC address stored within the ethernet adapter, 447 * and stores it in the ethernet interface's data structure 448 */ 449 static int mcs7830_read_mac(struct eth_device *eth) 450 { 451 struct ueth_data *dev; 452 int rc; 453 uint8_t buf[ETH_ALEN]; 454 455 debug("%s()\n", __func__); 456 dev = eth->priv; 457 458 rc = mcs7830_read_reg(dev, REG_ETHER_ADDR, ETH_ALEN, buf); 459 if (rc < 0) { 460 debug("reading MAC from adapter failed\n"); 461 return rc; 462 } 463 464 memcpy(ð->enetaddr[0], buf, ETH_ALEN); 465 return 0; 466 } 467 468 /* 469 * mcs7830_write_mac() - write an ethernet adapter's MAC address 470 * @eth: network device to write to 471 * Return: zero upon success, negative upon error 472 * 473 * this routine takes the MAC address from the ethernet interface's data 474 * structure, and writes it into the ethernet adapter such that subsequent 475 * exchange of ethernet frames uses this address 476 */ 477 static int mcs7830_write_mac(struct eth_device *eth) 478 { 479 struct ueth_data *dev; 480 int rc; 481 482 debug("%s()\n", __func__); 483 dev = eth->priv; 484 485 if (sizeof(eth->enetaddr) != ETH_ALEN) 486 return -EINVAL; 487 rc = mcs7830_write_reg(dev, REG_ETHER_ADDR, ETH_ALEN, eth->enetaddr); 488 if (rc < 0) { 489 debug("writing MAC to adapter failed\n"); 490 return rc; 491 } 492 return 0; 493 } 494 495 /* 496 * mcs7830_init() - network interface's init callback 497 * @eth: network device to initialize 498 * @bd: board information 499 * Return: zero upon success, negative upon error 500 * 501 * after initial setup during probe() and get_info(), this init() callback 502 * ensures that the link is up and subsequent send() and recv() calls can 503 * exchange ethernet frames 504 */ 505 static int mcs7830_init(struct eth_device *eth, bd_t *bd) 506 { 507 struct ueth_data *dev; 508 int timeout; 509 int have_link; 510 511 debug("%s()\n", __func__); 512 dev = eth->priv; 513 514 timeout = 0; 515 do { 516 have_link = mcs7830_read_phy(dev, MII_BMSR) & BMSR_LSTATUS; 517 if (have_link) 518 break; 519 udelay(LINKSTATUS_TIMEOUT_RES * 1000); 520 timeout += LINKSTATUS_TIMEOUT_RES; 521 } while (timeout < LINKSTATUS_TIMEOUT); 522 if (!have_link) { 523 debug("ethernet link is down\n"); 524 return -ETIMEDOUT; 525 } 526 return 0; 527 } 528 529 /* 530 * mcs7830_send() - network interface's send callback 531 * @eth: network device to send the frame from 532 * @packet: ethernet frame content 533 * @length: ethernet frame length 534 * Return: zero upon success, negative upon error 535 * 536 * this routine send an ethernet frame out of the network interface 537 */ 538 static int mcs7830_send(struct eth_device *eth, void *packet, int length) 539 { 540 struct ueth_data *dev; 541 int rc; 542 int gotlen; 543 /* there is a status byte after the ethernet frame */ 544 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, PKTSIZE + sizeof(uint8_t)); 545 546 dev = eth->priv; 547 548 memcpy(buf, packet, length); 549 rc = usb_bulk_msg(dev->pusb_dev, 550 usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), 551 &buf[0], length, &gotlen, 552 USBCALL_TIMEOUT); 553 debug("%s() TX want len %d, got len %d, rc %d\n", 554 __func__, length, gotlen, rc); 555 return rc; 556 } 557 558 /* 559 * mcs7830_recv() - network interface's recv callback 560 * @eth: network device to receive frames from 561 * Return: zero upon success, negative upon error 562 * 563 * this routine checks for available ethernet frames that the network 564 * interface might have received, and notifies the network stack 565 */ 566 static int mcs7830_recv(struct eth_device *eth) 567 { 568 struct ueth_data *dev; 569 ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, MCS7830_RX_URB_SIZE); 570 int rc, wantlen, gotlen; 571 uint8_t sts; 572 573 debug("%s()\n", __func__); 574 dev = eth->priv; 575 576 /* fetch input data from the adapter */ 577 wantlen = MCS7830_RX_URB_SIZE; 578 rc = usb_bulk_msg(dev->pusb_dev, 579 usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), 580 &buf[0], wantlen, &gotlen, 581 USBCALL_TIMEOUT); 582 debug("%s() RX want len %d, got len %d, rc %d\n", 583 __func__, wantlen, gotlen, rc); 584 if (rc != 0) { 585 error("RX: failed to receive\n"); 586 return rc; 587 } 588 if (gotlen > wantlen) { 589 error("RX: got too many bytes (%d)\n", gotlen); 590 return -EIO; 591 } 592 593 /* 594 * the bulk message that we received from USB contains exactly 595 * one ethernet frame and a trailing status byte 596 */ 597 if (gotlen < sizeof(sts)) 598 return -EIO; 599 gotlen -= sizeof(sts); 600 sts = buf[gotlen]; 601 602 if (sts == STAT_RX_FRAME_CORRECT) { 603 debug("%s() got a frame, len=%d\n", __func__, gotlen); 604 net_process_received_packet(buf, gotlen); 605 return 0; 606 } 607 608 debug("RX: frame error (sts 0x%02X, %s %s %s %s %s)\n", 609 sts, 610 (sts & STAT_RX_LARGE_FRAME) ? "large" : "-", 611 (sts & STAT_RX_LENGTH_ERROR) ? "length" : "-", 612 (sts & STAT_RX_SHORT_FRAME) ? "short" : "-", 613 (sts & STAT_RX_CRC_ERROR) ? "crc" : "-", 614 (sts & STAT_RX_ALIGNMENT_ERROR) ? "align" : "-"); 615 return -EIO; 616 } 617 618 /* 619 * mcs7830_halt() - network interface's halt callback 620 * @eth: network device to cease operation of 621 * Return: none 622 * 623 * this routine is supposed to undo the effect of previous initialization and 624 * ethernet frames exchange; in this implementation it's a NOP 625 */ 626 static void mcs7830_halt(struct eth_device *eth) 627 { 628 debug("%s()\n", __func__); 629 } 630 631 /* 632 * mcs7830_iface_idx - index of detected network interfaces 633 * 634 * this counter keeps track of identified supported interfaces, 635 * to assign unique names as more interfaces are found 636 */ 637 static int mcs7830_iface_idx; 638 639 /* 640 * mcs7830_eth_before_probe() - network driver's before_probe callback 641 * Return: none 642 * 643 * this routine initializes driver's internal data in preparation of 644 * subsequent probe callbacks 645 */ 646 void mcs7830_eth_before_probe(void) 647 { 648 mcs7830_iface_idx = 0; 649 } 650 651 /* 652 * struct mcs7830_dongle - description of a supported Moschip ethernet dongle 653 * @vendor: 16bit USB vendor identification 654 * @product: 16bit USB product identification 655 * 656 * this structure describes a supported USB ethernet dongle by means of the 657 * vendor and product codes found during USB enumeration; no flags are held 658 * here since all supported dongles have identical behaviour, and required 659 * fixups get determined at runtime, such that no manual configuration is 660 * needed 661 */ 662 struct mcs7830_dongle { 663 uint16_t vendor; 664 uint16_t product; 665 }; 666 667 /* 668 * mcs7830_dongles - the list of supported Moschip based USB ethernet dongles 669 */ 670 static const struct mcs7830_dongle mcs7830_dongles[] = { 671 { 0x9710, 0x7832, }, /* Moschip 7832 */ 672 { 0x9710, 0x7830, }, /* Moschip 7830 */ 673 { 0x9710, 0x7730, }, /* Moschip 7730 */ 674 { 0x0df6, 0x0021, }, /* Sitecom LN 30 */ 675 }; 676 677 /* 678 * mcs7830_eth_probe() - network driver's probe callback 679 * @dev: detected USB device to check 680 * @ifnum: detected USB interface to check 681 * @ss: USB ethernet data structure to fill in upon match 682 * Return: #1 upon match, #0 upon mismatch or error 683 * 684 * this routine checks whether the found USB device is supported by 685 * this ethernet driver, and upon match fills in the USB ethernet 686 * data structure which later is passed to the get_info callback 687 */ 688 int mcs7830_eth_probe(struct usb_device *dev, unsigned int ifnum, 689 struct ueth_data *ss) 690 { 691 struct usb_interface *iface; 692 struct usb_interface_descriptor *iface_desc; 693 int i; 694 struct mcs7830_private *priv; 695 int ep_in_found, ep_out_found, ep_intr_found; 696 697 debug("%s()\n", __func__); 698 699 /* iterate the list of supported dongles */ 700 iface = &dev->config.if_desc[ifnum]; 701 iface_desc = &iface->desc; 702 for (i = 0; i < ARRAY_SIZE(mcs7830_dongles); i++) { 703 if (dev->descriptor.idVendor == mcs7830_dongles[i].vendor && 704 dev->descriptor.idProduct == mcs7830_dongles[i].product) 705 break; 706 } 707 if (i == ARRAY_SIZE(mcs7830_dongles)) 708 return 0; 709 debug("detected USB ethernet device: %04X:%04X\n", 710 dev->descriptor.idVendor, dev->descriptor.idProduct); 711 712 /* fill in driver private data */ 713 priv = calloc(1, sizeof(*priv)); 714 if (!priv) 715 return 0; 716 717 /* fill in the ueth_data structure, attach private data */ 718 memset(ss, 0, sizeof(*ss)); 719 ss->ifnum = ifnum; 720 ss->pusb_dev = dev; 721 ss->subclass = iface_desc->bInterfaceSubClass; 722 ss->protocol = iface_desc->bInterfaceProtocol; 723 ss->dev_priv = priv; 724 725 /* 726 * a minimum of three endpoints is expected: in (bulk), 727 * out (bulk), and interrupt; ignore all others 728 */ 729 ep_in_found = ep_out_found = ep_intr_found = 0; 730 for (i = 0; i < iface_desc->bNumEndpoints; i++) { 731 uint8_t eptype, epaddr; 732 bool is_input; 733 734 eptype = iface->ep_desc[i].bmAttributes; 735 eptype &= USB_ENDPOINT_XFERTYPE_MASK; 736 737 epaddr = iface->ep_desc[i].bEndpointAddress; 738 is_input = epaddr & USB_DIR_IN; 739 epaddr &= USB_ENDPOINT_NUMBER_MASK; 740 741 if (eptype == USB_ENDPOINT_XFER_BULK) { 742 if (is_input && !ep_in_found) { 743 ss->ep_in = epaddr; 744 ep_in_found++; 745 } 746 if (!is_input && !ep_out_found) { 747 ss->ep_out = epaddr; 748 ep_out_found++; 749 } 750 } 751 752 if (eptype == USB_ENDPOINT_XFER_INT) { 753 if (is_input && !ep_intr_found) { 754 ss->ep_int = epaddr; 755 ss->irqinterval = iface->ep_desc[i].bInterval; 756 ep_intr_found++; 757 } 758 } 759 } 760 debug("endpoints: in %d, out %d, intr %d\n", 761 ss->ep_in, ss->ep_out, ss->ep_int); 762 763 /* apply basic sanity checks */ 764 if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || 765 !ss->ep_in || !ss->ep_out || !ss->ep_int) { 766 debug("device probe incomplete\n"); 767 return 0; 768 } 769 770 dev->privptr = ss; 771 return 1; 772 } 773 774 /* 775 * mcs7830_eth_get_info() - network driver's get_info callback 776 * @dev: detected USB device 777 * @ss: USB ethernet data structure filled in at probe() 778 * @eth: ethernet interface data structure to fill in 779 * Return: #1 upon success, #0 upon error 780 * 781 * this routine registers the mandatory init(), send(), recv(), and 782 * halt() callbacks with the ethernet interface, can register the 783 * optional write_hwaddr() callback with the ethernet interface, 784 * and initiates configuration of the interface such that subsequent 785 * calls to those callbacks results in network communication 786 */ 787 int mcs7830_eth_get_info(struct usb_device *dev, struct ueth_data *ss, 788 struct eth_device *eth) 789 { 790 debug("%s()\n", __func__); 791 if (!eth) { 792 debug("%s: missing parameter.\n", __func__); 793 return 0; 794 } 795 796 snprintf(eth->name, sizeof(eth->name), "%s%d", 797 MCS7830_BASE_NAME, mcs7830_iface_idx++); 798 eth->init = mcs7830_init; 799 eth->send = mcs7830_send; 800 eth->recv = mcs7830_recv; 801 eth->halt = mcs7830_halt; 802 eth->write_hwaddr = mcs7830_write_mac; 803 eth->priv = ss; 804 805 if (mcs7830_basic_reset(ss)) 806 return 0; 807 808 if (mcs7830_read_mac(eth)) 809 return 0; 810 debug("MAC %pM\n", eth->enetaddr); 811 812 return 1; 813 } 814