[USB] Kind of works..
[people/balajirrao/gpxe.git] / src / drivers / net / usb / pegasus.c
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <gpxe/if_ether.h>
4 #include <gpxe/usb.h>
5 #include <gpxe/malloc.h>
6 #include <gpxe/usb/usbnet.h>
7 #include <gpxe/ethernet.h>
8 #include <gpxe/iobuf.h>
9 #include <mii.h>
10 #include <errno.h>
11 #include <little_bswap.h>
12
13 #include "pegasus.h"
14
15 static int mii_mode = 0;
16 static const char driver_name[] = "pegasus";
17
18 #undef  PEGASUS_WRITE_EEPROM
19 #define BMSR_MEDIA      (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
20                         BMSR_100FULL | BMSR_ANEGCAPABLE)
21
22 static struct usb_eth_dev usb_dev_id[] = {
23 #define PEGASUS_DEV(pn, vid, pid, flags)        \
24         {.name = pn, .vendor = vid, .device = pid, .private = flags},
25 #include "pegasus.h"
26 #undef  PEGASUS_DEV
27         {NULL, 0, 0, 0},
28         {NULL, 0, 0, 0}
29 };
30
31 static struct usb_device_id pegasus_ids[] = {
32 #define PEGASUS_DEV(pn, vid, dev, flags) \
33         USB_ROM (vid,dev, "pegasus", pn),
34 #include "pegasus.h"
35 #undef  PEGASUS_DEV
36         {NULL, 0, 0},
37         {NULL, 0, 0}
38 };
39
40 static int get_registers(pegasus_t * pegasus, uint16_t indx, uint16_t size,
41                          void *data)
42 {
43
44         return usb_control_msg(pegasus->udev, &pegasus->udev->ep_0_in, PEGASUS_REQ_GET_REGS | USB_DIR_IN,
45                         PEGASUS_REQT_READ, 0, indx, data, size);
46 }
47
48 static int set_registers(pegasus_t * pegasus, uint16_t indx, uint16_t size,
49                          void *data)
50 {
51
52         return usb_control_msg(pegasus->udev, &pegasus->udev->ep_0_out, PEGASUS_REQ_SET_REGS,
53                         PEGASUS_REQT_WRITE | USB_DIR_OUT, 0, indx, data, size);
54 }
55
56 static int set_register(pegasus_t * pegasus, uint16_t indx, uint8_t data)
57 {
58
59
60         usb_control_msg(pegasus->udev, &pegasus->udev->ep_0_out, PEGASUS_REQ_SET_REG,
61                         PEGASUS_REQT_WRITE, data, indx, NULL, 1);
62         return 0;
63 }
64
65 /* Returns 0 on success, error on failure */
66 static int read_mii_word(pegasus_t * pegasus, uint8_t phy, uint8_t indx, uint16_t * regd)
67 {
68         int i;
69         uint8_t data[4] = { phy, 0, 0, indx };
70         uint16_t regdi;
71         int ret =  -ETIMEDOUT;
72
73         set_register(pegasus, PhyCtrl, 0);
74         set_registers(pegasus, PhyAddr, sizeof (data), data);
75         set_register(pegasus, PhyCtrl, (indx | PHY_READ));
76         for (i = 0; i < REG_TIMEOUT; i++) {
77                 ret = get_registers(pegasus, PhyCtrl, 1, data);
78                 if (data[0] & PHY_DONE)
79                         break;
80         }
81         if (i < REG_TIMEOUT) {
82                 ret = get_registers(pegasus, PhyData, 2, &regdi);
83                 *regd = le16_to_cpu(regdi);
84                 return ret;
85         }
86
87         DBG("%s failed\n", __FUNCTION__);
88         return ret;
89 }
90
91
92 static int write_mii_word(pegasus_t * pegasus, uint8_t phy, uint8_t indx, uint16_t regd)
93 {
94         int i;
95         uint8_t data[4] = { phy, 0, 0, indx };
96         int ret;
97
98         data[1] = (u8) regd;
99         data[2] = (u8) (regd >> 8);
100         set_register(pegasus, PhyCtrl, 0);
101         set_registers(pegasus, PhyAddr, sizeof(data), data);
102         set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
103         for (i = 0; i < REG_TIMEOUT; i++) {
104                 ret = get_registers(pegasus, PhyCtrl, 1, data);
105                 if (data[0] & PHY_DONE)
106                         break;
107         }
108         if (i < REG_TIMEOUT)
109                 return ret;
110
111         DBG("%s failed\n", __FUNCTION__);
112         return -ETIMEDOUT;
113 }
114
115 void pegasus_remove(struct usb_device *udev __unused)
116 {
117
118 }
119
120 static int enable_net_traffic(struct net_device *dev)
121 {
122         uint16_t linkpart;
123         uint8_t data[4];
124         pegasus_t *pegasus = netdev_priv(dev);
125         int ret;
126
127         read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart);
128         data[0] = 0xc9;
129         data[1] = 0;
130         if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))
131                 data[1] |= 0x20;        /* set full duplex */
132         if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
133                 data[1] |= 0x10;        /* set 100 Mbps */
134         if (mii_mode)
135                 data[1] = 0;
136         data[2] = 0x01;
137         ret = set_registers(pegasus, EthCtrl0, 3, data);
138
139         if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
140             usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
141             usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
142                 u16 auxmode;
143                 read_mii_word(pegasus, 0, 0x1b, &auxmode);
144                 write_mii_word(pegasus, 0, 0x1b, auxmode | 4);
145         }
146
147         return ret;
148 }
149
150 static int enqueue_one_rx_urb(pegasus_t *pegasus)
151 {
152         struct urb *urb;
153         struct io_buffer *iobuf;
154         int ret = -ENOMEM;
155
156         DBG("Enqueing one URB\n");
157         
158         iobuf = alloc_iob(PEGASUS_MTU);
159         if (!iobuf)
160                 goto err_iobuf_malloc;
161
162         urb = usb_alloc_urb();
163         if (!urb)
164                 goto err_usb_malloc;
165
166         usb_fill_bulk_urb(urb, pegasus->udev, pegasus->in, iob_put(iobuf, PEGASUS_MTU), PEGASUS_MTU);
167
168         ret = usb_submit_urb(urb);
169         if (ret < 0)
170                 goto err_submit_urb;
171         
172         urb->priv = iobuf;
173         list_add_tail(&urb->priv_list, &pegasus->rx_queue);
174         
175         return 0;
176
177 err_submit_urb:
178         usb_free_urb(urb);
179 err_usb_malloc:
180         free_iob(iobuf);
181 err_iobuf_malloc:
182
183         return ret;
184 }
185
186 int pegasus_open ( struct net_device *netdev __unused)
187 {
188         pegasus_t *pegasus = netdev_priv(netdev);
189         
190         if (enable_net_traffic(netdev) < 0)
191                 DBG("Error enabling pegasus\n");
192
193         if(set_registers(pegasus, EthID, 6, netdev->ll_addr) < 0)
194                 return -ENODEV;
195
196         return enqueue_one_rx_urb(pegasus);
197 }
198
199 void pegasus_close ( struct net_device *netdev ) {
200         
201         netdev++;
202 }
203
204 int pegasus_transmit ( struct net_device *netdev,
205                           struct io_buffer *iobuf) {
206
207         pegasus_t *pegasus = netdev_priv(netdev);
208         int length;
209         struct urb *urb = NULL;
210         int status;
211         void *buffer;
212         int ret = -ENOMEM;
213
214         length = iob_len(iobuf);
215
216         if ((length % pegasus->maxpacket) == 0)
217                 buffer = malloc_dma(length + 2, 1);
218         else
219                 buffer = malloc_dma(length + 3, 1);
220
221         if(!buffer)
222                 goto err_buffer_malloc;
223
224         ((char *)buffer)[0] = length;
225         ((char *)buffer)[1] = length >> 8;
226
227         memcpy(buffer + 2, iobuf->data, length);
228         length += 2;
229
230         urb = usb_alloc_urb();
231         if (!urb)
232                 goto err_alloc_urb;
233
234         /* don't assume the hardware handles USB_ZERO_PACKET
235          * NOTE:  strictly conforming cdc-ether devices should expect
236          * the ZLP here, but ignore the one-byte packet.
237          */
238         if ((length % pegasus->maxpacket) == 0) {
239                 ((char *)buffer)[length] = 0;
240                 length++;
241         }
242
243         usb_fill_bulk_urb (urb, pegasus->udev, pegasus->out,
244                         buffer, length);
245
246
247         ret = usb_submit_urb (urb);
248         
249         if (ret < 0)
250                 goto err_submit_urb;
251
252         urb->priv = iobuf;
253         list_add_tail(&urb->priv_list, &pegasus->tx_queue);
254
255         /* Report successful transmit completions */            
256         list_for_each_entry(urb, &pegasus->tx_queue, priv_list) {
257                 if ((status = usb_urb_status(urb)) == USB_URB_STATUS_COMPLETE) {
258                         netdev_tx_complete(netdev, urb->priv);
259
260                         list_del(&urb->priv_list);
261
262                         free_dma(urb->transfer_buffer, urb->transfer_buffer_length);
263                         usb_unlink_urb(urb);
264                         
265                         DBG("TX DONE\n");
266                 } else if (status == USB_URB_STATUS_ERROR)
267                         DBG("TX Error\n");
268         }
269         return 0;
270         
271         /* Nothing to do */
272 err_submit_urb:
273         usb_free_urb(urb);
274 err_alloc_urb:
275         free_dma(buffer, length);
276 err_buffer_malloc:
277         return ret;
278 }
279
280 void pegasus_poll(struct net_device *netdev) {
281         pegasus_t *pegasus;
282         struct urb *urb;
283         uint8_t *buffer;
284         struct io_buffer *iobuf;
285         uint8_t status = 0;
286         int count, rx_status;
287         uint16_t pkt_len;
288         
289         pegasus = netdev_priv(netdev);
290         
291         /* Check for RX */
292         list_for_each_entry(urb, &pegasus->rx_queue, priv_list) {
293         if ((status = usb_urb_status(urb)) == USB_URB_STATUS_COMPLETE) {
294                 if (enqueue_one_rx_urb(pegasus) < 0)
295                         DBG("Error enquing packet\n");
296                 
297                 buffer = urb->transfer_buffer;
298                 iobuf = urb->priv;
299
300                 count = urb->actual_length;
301                 rx_status = buffer[count - 2];
302
303
304                 if (rx_status & 0x1e) {
305                         DBG("%s: RX packet error %x\n", netdev->name, rx_status);
306                         usb_unlink_urb(urb);
307                         return;
308                 }
309                 if (pegasus->chip == 0x8513) {
310                         pkt_len = le32_to_cpu(*(uint32_t *)buffer);
311                         pkt_len &= 0x0fff;
312                         iobuf->data += 2;
313                 } else {
314                         pkt_len = buffer[count - 3] << 8;
315                         pkt_len += buffer[count - 4];
316                         pkt_len &= 0xfff;
317                         pkt_len -= 8;
318                 }
319                 
320                 iob_unput(iobuf, PEGASUS_MTU - pkt_len);
321                 netdev_rx(netdev, iobuf);
322
323                 list_del(&urb->priv_list);
324                 usb_unlink_urb(urb);
325                 }
326         }
327
328 }
329
330
331 /* pegasus net device operations */
332 static struct net_device_operations pegasus_operations = {
333         .open           = pegasus_open,
334         .close          = pegasus_close,
335         .transmit       = pegasus_transmit,
336         .poll           = pegasus_poll,
337 };
338
339
340 static int read_eprom_word(pegasus_t * pegasus, uint8_t index, uint16_t * retdata)
341 {
342         int i;
343         uint8_t tmp;
344         uint16_t retdatai;
345         int ret;
346
347         set_register(pegasus, EpromCtrl, 0);
348         set_register(pegasus, EpromOffset, index);
349         set_register(pegasus, EpromCtrl, EPROM_READ);
350
351         for (i = 0; i < REG_TIMEOUT; i++) {
352                 ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
353                 if (tmp & EPROM_DONE)
354                         break;
355         }
356         if (i < REG_TIMEOUT) {
357                 ret = get_registers(pegasus, EpromData, 2, &retdatai);
358                 *retdata = le16_to_cpu(retdatai);
359                 return ret;
360         }
361
362         return -ETIMEDOUT;
363 }
364
365
366 static inline void get_node_id(pegasus_t * pegasus, uint8_t * id)
367 {
368         int i;
369         uint16_t w16 = 0;
370
371         for (i = 0; i < 3; i++) {
372                 read_eprom_word(pegasus, i, &w16);
373                 ((uint16_t *) id)[i] = cpu_to_le16(w16);
374         }
375 }
376
377 static void set_ethernet_addr(pegasus_t * pegasus)
378 {
379         uint8_t node_id[6];
380
381         if (pegasus->features & PEGASUS_II) {
382                 get_registers(pegasus, 0x10, sizeof(node_id), node_id);
383         } else {
384                 get_node_id(pegasus, node_id);
385                 set_registers(pegasus, EthID, sizeof (node_id), node_id);
386         }
387         memcpy(pegasus->net->ll_addr, node_id, sizeof (node_id));
388 }
389
390 static inline int reset_mac(pegasus_t * pegasus)
391 {
392         uint8_t data = 0x8;
393         int i;
394
395         set_register(pegasus, EthCtrl1, data);
396         for (i = 0; i < REG_TIMEOUT; i++) {
397                 get_registers(pegasus, EthCtrl1, 1, &data);
398                 if (~data & 0x08) {
399                         if (mii_mode && (pegasus->features & HAS_HOME_PNA))
400                                 set_register(pegasus, Gpio1, 0x34);
401                         else
402                                 set_register(pegasus, Gpio1, 0x26);
403                         set_register(pegasus, Gpio0, pegasus->features);
404                         set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
405                         break;
406                 }
407         }
408         if (i == REG_TIMEOUT)
409                 return -ETIMEDOUT;
410
411         if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
412             usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
413                 set_register(pegasus, Gpio0, 0x24);
414                 set_register(pegasus, Gpio0, 0x26);
415         }
416         if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
417                 uint16_t auxmode;
418                 read_mii_word(pegasus, 3, 0x1b, &auxmode);
419                 write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
420         }
421
422         return 0;
423 }
424
425 static uint8_t mii_phy_probe(pegasus_t * pegasus)
426 {
427         int i;
428         uint16_t tmp;
429
430         return 0xff;
431
432         for (i = 0; i < 32; i++) {
433                 read_mii_word(pegasus, i, MII_BMSR, &tmp);
434                 if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
435                         continue;
436                 else
437                         return i;
438         }
439
440         return 0xff;
441 }
442
443 static inline void setup_pegasus_II(pegasus_t * pegasus)
444 {
445         uint8_t data = 0xa5;
446         
447         set_register(pegasus, Reg1d, 0);
448         set_register(pegasus, Reg7b, 1);
449         mdelay(100);
450         if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
451                 set_register(pegasus, Reg7b, 0);
452         else
453                 set_register(pegasus, Reg7b, 2);
454
455         set_register(pegasus, 0x83, data);
456         get_registers(pegasus, 0x83, 1, &data);
457
458         if (data == 0xa5) {
459                 pegasus->chip = 0x8513;
460         } else {
461                 pegasus->chip = 0;
462         }
463
464         set_register(pegasus, 0x80, 0xc0);
465         set_register(pegasus, 0x83, 0xff);
466         set_register(pegasus, 0x84, 0x01);
467         
468         if (pegasus->features & HAS_HOME_PNA && mii_mode)
469                 set_register(pegasus, Reg81, 6);
470         else
471                 set_register(pegasus, Reg81, 2);
472 }
473
474 int pegasus_probe(struct usb_device *udev,
475                         const struct usb_device_id *id)
476 {
477         struct net_device *netdev;
478         pegasus_t *pegasus;
479         int dev_index = id - pegasus_ids;
480         int res = -ENOMEM;
481         unsigned int i;
482
483         netdev = alloc_etherdev(sizeof(*pegasus));
484         netdev_init(netdev, &pegasus_operations);
485
486         if (!netdev) {
487                 DBG("can't allocate %s\n", "device");
488                 goto out;
489         }
490
491         pegasus = netdev_priv(netdev);
492         INIT_LIST_HEAD(&pegasus->tx_queue);
493         INIT_LIST_HEAD(&pegasus->rx_done_queue);
494         INIT_LIST_HEAD(&pegasus->rx_queue);
495         
496         pegasus->dev_index = dev_index;
497
498         pegasus->udev = udev;
499         pegasus->net = netdev;
500
501         netdev->dev = &udev->dev;
502
503         for(i = 0;i < udev->num_endpoints; i++) {
504                 if (usb_ep_xfertype(udev->endpoints[i]) == USB_ENDPOINT_XFER_BULK &&
505                                 usb_ep_dir(udev->endpoints[i]) == USB_DIR_IN)
506                         pegasus->in = udev->endpoints[i];
507
508                 if (usb_ep_xfertype(udev->endpoints[i]) == USB_ENDPOINT_XFER_BULK &&
509                                 usb_ep_dir(udev->endpoints[i]) == USB_DIR_OUT)
510                         pegasus->out = udev->endpoints[i];
511         }
512         pegasus->maxpacket = le16_to_cpu(pegasus->in->desc.wMaxPacketSize);
513
514         pegasus->features = usb_dev_id[dev_index].private;
515         
516         if (reset_mac(pegasus)) {
517                 DBG("can't reset MAC\n");
518                 res = -EIO;
519                 goto out;
520         }
521         set_ethernet_addr(pegasus);
522         
523         if (pegasus->features & PEGASUS_II) {
524                 DBG("setup Pegasus II specific registers\n");
525                 setup_pegasus_II(pegasus);
526         }
527         pegasus->phy = mii_phy_probe(pegasus);
528         if (pegasus->phy == 0xff) {
529                 DBG("can't locate MII phy, using default\n");
530                 pegasus->phy = 1;
531         }
532         
533         res = register_netdev(netdev);
534         if (res)
535                 goto out;
536         
537         DBG("%s, %s,", netdev->name, usb_dev_id[dev_index].name);
538         
539         DBG("MAC : %02x", netdev->ll_addr[0]);
540         for(i=1;i<6;i++)
541                 DBG(":%02x", netdev->ll_addr[i]);
542         DBG("\n");
543
544         netdev_link_up(netdev); 
545         return 0;
546 out:
547         return res;
548 }
549
550 struct usb_driver pegasus_usb_driver  __usb_driver = {
551         .ids = pegasus_ids,
552         .id_count = (sizeof(pegasus_ids) / sizeof(pegasus_ids[0])),
553         .probe = pegasus_probe,
554         .remove = pegasus_remove,
555 };
556