mcs7830.c 21 KB

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