mcs7830.c 21 KB

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