1 | /* |
2 | * USB 10M/100M ethernet adapter |
3 | * |
4 | * This file is licensed under the terms of the GNU General Public License |
5 | * version 2. This program is licensed "as is" without any warranty of any |
6 | * kind, whether express or implied |
7 | * |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/sched.h> |
13 | #include <linux/stddef.h> |
14 | #include <linux/init.h> |
15 | #include <linux/netdevice.h> |
16 | #include <linux/etherdevice.h> |
17 | #include <linux/ethtool.h> |
18 | #include <linux/mii.h> |
19 | #include <linux/usb.h> |
20 | #include <linux/crc32.h> |
21 | #include <linux/usb/usbnet.h> |
22 | #include <linux/slab.h> |
23 | |
24 | #define CH9200_VID 0x1A86 |
25 | #define CH9200_PID_E092 0xE092 |
26 | |
27 | #define CTRL_TIMEOUT_MS 1000 |
28 | |
29 | #define CONTROL_TIMEOUT_MS 1000 |
30 | |
31 | #define REQUEST_READ 0x0E |
32 | #define REQUEST_WRITE 0x0F |
33 | |
34 | /* Address space: |
35 | * 00-63 : MII |
36 | * 64-128: MAC |
37 | * |
38 | * Note: all accesses must be 16-bit |
39 | */ |
40 | |
41 | #define MAC_REG_CTRL 64 |
42 | #define MAC_REG_STATUS 66 |
43 | #define MAC_REG_INTERRUPT_MASK 68 |
44 | #define MAC_REG_PHY_COMMAND 70 |
45 | #define MAC_REG_PHY_DATA 72 |
46 | #define MAC_REG_STATION_L 74 |
47 | #define MAC_REG_STATION_M 76 |
48 | #define MAC_REG_STATION_H 78 |
49 | #define MAC_REG_HASH_L 80 |
50 | #define MAC_REG_HASH_M1 82 |
51 | #define MAC_REG_HASH_M2 84 |
52 | #define MAC_REG_HASH_H 86 |
53 | #define MAC_REG_THRESHOLD 88 |
54 | #define MAC_REG_FIFO_DEPTH 90 |
55 | #define MAC_REG_PAUSE 92 |
56 | #define MAC_REG_FLOW_CONTROL 94 |
57 | |
58 | /* Control register bits |
59 | * |
60 | * Note: bits 13 and 15 are reserved |
61 | */ |
62 | #define LOOPBACK (0x01 << 14) |
63 | #define BASE100X (0x01 << 12) |
64 | #define MBPS_10 (0x01 << 11) |
65 | #define DUPLEX_MODE (0x01 << 10) |
66 | #define PAUSE_FRAME (0x01 << 9) |
67 | #define PROMISCUOUS (0x01 << 8) |
68 | #define MULTICAST (0x01 << 7) |
69 | #define BROADCAST (0x01 << 6) |
70 | #define HASH (0x01 << 5) |
71 | #define APPEND_PAD (0x01 << 4) |
72 | #define APPEND_CRC (0x01 << 3) |
73 | #define TRANSMITTER_ACTION (0x01 << 2) |
74 | #define RECEIVER_ACTION (0x01 << 1) |
75 | #define DMA_ACTION (0x01 << 0) |
76 | |
77 | /* Status register bits |
78 | * |
79 | * Note: bits 7-15 are reserved |
80 | */ |
81 | #define ALIGNMENT (0x01 << 6) |
82 | #define FIFO_OVER_RUN (0x01 << 5) |
83 | #define FIFO_UNDER_RUN (0x01 << 4) |
84 | #define RX_ERROR (0x01 << 3) |
85 | #define RX_COMPLETE (0x01 << 2) |
86 | #define TX_ERROR (0x01 << 1) |
87 | #define TX_COMPLETE (0x01 << 0) |
88 | |
89 | /* FIFO depth register bits |
90 | * |
91 | * Note: bits 6 and 14 are reserved |
92 | */ |
93 | |
94 | #define ETH_TXBD (0x01 << 15) |
95 | #define ETN_TX_FIFO_DEPTH (0x01 << 8) |
96 | #define ETH_RXBD (0x01 << 7) |
97 | #define ETH_RX_FIFO_DEPTH (0x01 << 0) |
98 | |
99 | static int control_read(struct usbnet *dev, |
100 | unsigned char request, unsigned short value, |
101 | unsigned short index, void *data, unsigned short size, |
102 | int timeout) |
103 | { |
104 | unsigned char *buf = NULL; |
105 | unsigned char request_type; |
106 | int err = 0; |
107 | |
108 | if (request == REQUEST_READ) |
109 | request_type = (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER); |
110 | else |
111 | request_type = (USB_DIR_IN | USB_TYPE_VENDOR | |
112 | USB_RECIP_DEVICE); |
113 | |
114 | netdev_dbg(dev->net, "%s() index=0x%02x size=%d\n" , |
115 | __func__, index, size); |
116 | |
117 | buf = kmalloc(size, GFP_KERNEL); |
118 | if (!buf) { |
119 | err = -ENOMEM; |
120 | goto err_out; |
121 | } |
122 | |
123 | err = usb_control_msg(dev: dev->udev, |
124 | usb_rcvctrlpipe(dev->udev, 0), |
125 | request, requesttype: request_type, value, index, data: buf, size, |
126 | timeout); |
127 | if (err == size) |
128 | memcpy(data, buf, size); |
129 | else if (err >= 0) |
130 | err = -EINVAL; |
131 | kfree(objp: buf); |
132 | |
133 | err_out: |
134 | return err; |
135 | } |
136 | |
137 | static int control_write(struct usbnet *dev, unsigned char request, |
138 | unsigned short value, unsigned short index, |
139 | void *data, unsigned short size, int timeout) |
140 | { |
141 | unsigned char *buf = NULL; |
142 | unsigned char request_type; |
143 | int err = 0; |
144 | |
145 | if (request == REQUEST_WRITE) |
146 | request_type = (USB_DIR_OUT | USB_TYPE_VENDOR | |
147 | USB_RECIP_OTHER); |
148 | else |
149 | request_type = (USB_DIR_OUT | USB_TYPE_VENDOR | |
150 | USB_RECIP_DEVICE); |
151 | |
152 | netdev_dbg(dev->net, "%s() index=0x%02x size=%d\n" , |
153 | __func__, index, size); |
154 | |
155 | if (data) { |
156 | buf = kmemdup(p: data, size, GFP_KERNEL); |
157 | if (!buf) { |
158 | err = -ENOMEM; |
159 | goto err_out; |
160 | } |
161 | } |
162 | |
163 | err = usb_control_msg(dev: dev->udev, |
164 | usb_sndctrlpipe(dev->udev, 0), |
165 | request, requesttype: request_type, value, index, data: buf, size, |
166 | timeout); |
167 | if (err >= 0 && err < size) |
168 | err = -EINVAL; |
169 | kfree(objp: buf); |
170 | |
171 | return 0; |
172 | |
173 | err_out: |
174 | return err; |
175 | } |
176 | |
177 | static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc) |
178 | { |
179 | struct usbnet *dev = netdev_priv(dev: netdev); |
180 | unsigned char buff[2]; |
181 | |
182 | netdev_dbg(netdev, "%s phy_id:%02x loc:%02x\n" , |
183 | __func__, phy_id, loc); |
184 | |
185 | if (phy_id != 0) |
186 | return -ENODEV; |
187 | |
188 | control_read(dev, REQUEST_READ, value: 0, index: loc * 2, data: buff, size: 0x02, |
189 | CONTROL_TIMEOUT_MS); |
190 | |
191 | return (buff[0] | buff[1] << 8); |
192 | } |
193 | |
194 | static void ch9200_mdio_write(struct net_device *netdev, |
195 | int phy_id, int loc, int val) |
196 | { |
197 | struct usbnet *dev = netdev_priv(dev: netdev); |
198 | unsigned char buff[2]; |
199 | |
200 | netdev_dbg(netdev, "%s() phy_id=%02x loc:%02x\n" , |
201 | __func__, phy_id, loc); |
202 | |
203 | if (phy_id != 0) |
204 | return; |
205 | |
206 | buff[0] = (unsigned char)val; |
207 | buff[1] = (unsigned char)(val >> 8); |
208 | |
209 | control_write(dev, REQUEST_WRITE, value: 0, index: loc * 2, data: buff, size: 0x02, |
210 | CONTROL_TIMEOUT_MS); |
211 | } |
212 | |
213 | static int ch9200_link_reset(struct usbnet *dev) |
214 | { |
215 | struct ethtool_cmd ecmd; |
216 | |
217 | mii_check_media(mii: &dev->mii, ok_to_print: 1, init_media: 1); |
218 | mii_ethtool_gset(mii: &dev->mii, ecmd: &ecmd); |
219 | |
220 | netdev_dbg(dev->net, "%s() speed:%d duplex:%d\n" , |
221 | __func__, ecmd.speed, ecmd.duplex); |
222 | |
223 | return 0; |
224 | } |
225 | |
226 | static void ch9200_status(struct usbnet *dev, struct urb *urb) |
227 | { |
228 | int link; |
229 | unsigned char *buf; |
230 | |
231 | if (urb->actual_length < 16) |
232 | return; |
233 | |
234 | buf = urb->transfer_buffer; |
235 | link = !!(buf[0] & 0x01); |
236 | |
237 | if (link) { |
238 | netif_carrier_on(dev: dev->net); |
239 | usbnet_defer_kevent(dev, EVENT_LINK_RESET); |
240 | } else { |
241 | netif_carrier_off(dev: dev->net); |
242 | } |
243 | } |
244 | |
245 | static struct sk_buff *ch9200_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
246 | gfp_t flags) |
247 | { |
248 | int i = 0; |
249 | int len = 0; |
250 | int tx_overhead = 0; |
251 | |
252 | tx_overhead = 0x40; |
253 | |
254 | len = skb->len; |
255 | if (skb_cow_head(skb, headroom: tx_overhead)) { |
256 | dev_kfree_skb_any(skb); |
257 | return NULL; |
258 | } |
259 | |
260 | __skb_push(skb, len: tx_overhead); |
261 | /* usbnet adds padding if length is a multiple of packet size |
262 | * if so, adjust length value in header |
263 | */ |
264 | if ((skb->len % dev->maxpacket) == 0) |
265 | len++; |
266 | |
267 | skb->data[0] = len; |
268 | skb->data[1] = len >> 8; |
269 | skb->data[2] = 0x00; |
270 | skb->data[3] = 0x80; |
271 | |
272 | for (i = 4; i < 48; i++) |
273 | skb->data[i] = 0x00; |
274 | |
275 | skb->data[48] = len; |
276 | skb->data[49] = len >> 8; |
277 | skb->data[50] = 0x00; |
278 | skb->data[51] = 0x80; |
279 | |
280 | for (i = 52; i < 64; i++) |
281 | skb->data[i] = 0x00; |
282 | |
283 | return skb; |
284 | } |
285 | |
286 | static int ch9200_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
287 | { |
288 | int len = 0; |
289 | int rx_overhead = 0; |
290 | |
291 | rx_overhead = 64; |
292 | |
293 | if (unlikely(skb->len < rx_overhead)) { |
294 | dev_err(&dev->udev->dev, "unexpected tiny rx frame\n" ); |
295 | return 0; |
296 | } |
297 | |
298 | len = (skb->data[skb->len - 16] | skb->data[skb->len - 15] << 8); |
299 | skb_trim(skb, len); |
300 | |
301 | return 1; |
302 | } |
303 | |
304 | static int get_mac_address(struct usbnet *dev, unsigned char *data) |
305 | { |
306 | int err = 0; |
307 | unsigned char mac_addr[0x06]; |
308 | int rd_mac_len = 0; |
309 | |
310 | netdev_dbg(dev->net, "%s:\n\tusbnet VID:%0x PID:%0x\n" , __func__, |
311 | le16_to_cpu(dev->udev->descriptor.idVendor), |
312 | le16_to_cpu(dev->udev->descriptor.idProduct)); |
313 | |
314 | memset(mac_addr, 0, sizeof(mac_addr)); |
315 | rd_mac_len = control_read(dev, REQUEST_READ, value: 0, |
316 | MAC_REG_STATION_L, data: mac_addr, size: 0x02, |
317 | CONTROL_TIMEOUT_MS); |
318 | rd_mac_len += control_read(dev, REQUEST_READ, value: 0, MAC_REG_STATION_M, |
319 | data: mac_addr + 2, size: 0x02, CONTROL_TIMEOUT_MS); |
320 | rd_mac_len += control_read(dev, REQUEST_READ, value: 0, MAC_REG_STATION_H, |
321 | data: mac_addr + 4, size: 0x02, CONTROL_TIMEOUT_MS); |
322 | if (rd_mac_len != ETH_ALEN) |
323 | err = -EINVAL; |
324 | |
325 | data[0] = mac_addr[5]; |
326 | data[1] = mac_addr[4]; |
327 | data[2] = mac_addr[3]; |
328 | data[3] = mac_addr[2]; |
329 | data[4] = mac_addr[1]; |
330 | data[5] = mac_addr[0]; |
331 | |
332 | return err; |
333 | } |
334 | |
335 | static int ch9200_bind(struct usbnet *dev, struct usb_interface *intf) |
336 | { |
337 | int retval = 0; |
338 | unsigned char data[2]; |
339 | u8 addr[ETH_ALEN]; |
340 | |
341 | retval = usbnet_get_endpoints(dev, intf); |
342 | if (retval) |
343 | return retval; |
344 | |
345 | dev->mii.dev = dev->net; |
346 | dev->mii.mdio_read = ch9200_mdio_read; |
347 | dev->mii.mdio_write = ch9200_mdio_write; |
348 | dev->mii.reg_num_mask = 0x1f; |
349 | |
350 | dev->mii.phy_id_mask = 0x1f; |
351 | |
352 | dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; |
353 | dev->rx_urb_size = 24 * 64 + 16; |
354 | mii_nway_restart(mii: &dev->mii); |
355 | |
356 | data[0] = 0x01; |
357 | data[1] = 0x0F; |
358 | retval = control_write(dev, REQUEST_WRITE, value: 0, MAC_REG_THRESHOLD, data, |
359 | size: 0x02, CONTROL_TIMEOUT_MS); |
360 | |
361 | data[0] = 0xA0; |
362 | data[1] = 0x90; |
363 | retval = control_write(dev, REQUEST_WRITE, value: 0, MAC_REG_FIFO_DEPTH, data, |
364 | size: 0x02, CONTROL_TIMEOUT_MS); |
365 | |
366 | data[0] = 0x30; |
367 | data[1] = 0x00; |
368 | retval = control_write(dev, REQUEST_WRITE, value: 0, MAC_REG_PAUSE, data, |
369 | size: 0x02, CONTROL_TIMEOUT_MS); |
370 | |
371 | data[0] = 0x17; |
372 | data[1] = 0xD8; |
373 | retval = control_write(dev, REQUEST_WRITE, value: 0, MAC_REG_FLOW_CONTROL, |
374 | data, size: 0x02, CONTROL_TIMEOUT_MS); |
375 | |
376 | /* Undocumented register */ |
377 | data[0] = 0x01; |
378 | data[1] = 0x00; |
379 | retval = control_write(dev, REQUEST_WRITE, value: 0, index: 254, data, size: 0x02, |
380 | CONTROL_TIMEOUT_MS); |
381 | |
382 | data[0] = 0x5F; |
383 | data[1] = 0x0D; |
384 | retval = control_write(dev, REQUEST_WRITE, value: 0, MAC_REG_CTRL, data, size: 0x02, |
385 | CONTROL_TIMEOUT_MS); |
386 | |
387 | retval = get_mac_address(dev, data: addr); |
388 | eth_hw_addr_set(dev: dev->net, addr); |
389 | |
390 | return retval; |
391 | } |
392 | |
393 | static const struct driver_info ch9200_info = { |
394 | .description = "CH9200 USB to Network Adaptor" , |
395 | .flags = FLAG_ETHER, |
396 | .bind = ch9200_bind, |
397 | .rx_fixup = ch9200_rx_fixup, |
398 | .tx_fixup = ch9200_tx_fixup, |
399 | .status = ch9200_status, |
400 | .link_reset = ch9200_link_reset, |
401 | .reset = ch9200_link_reset, |
402 | }; |
403 | |
404 | static const struct usb_device_id ch9200_products[] = { |
405 | { |
406 | USB_DEVICE(0x1A86, 0xE092), |
407 | .driver_info = (unsigned long)&ch9200_info, |
408 | }, |
409 | {}, |
410 | }; |
411 | |
412 | MODULE_DEVICE_TABLE(usb, ch9200_products); |
413 | |
414 | static struct usb_driver ch9200_driver = { |
415 | .name = "ch9200" , |
416 | .id_table = ch9200_products, |
417 | .probe = usbnet_probe, |
418 | .disconnect = usbnet_disconnect, |
419 | .suspend = usbnet_suspend, |
420 | .resume = usbnet_resume, |
421 | }; |
422 | |
423 | module_usb_driver(ch9200_driver); |
424 | |
425 | MODULE_DESCRIPTION("QinHeng CH9200 USB Network device" ); |
426 | MODULE_LICENSE("GPL" ); |
427 | |