Root/drivers/staging/winbond/wbusb.c

1/*
2 * Copyright 2008 Pavel Machek <pavel@ucw.cz>
3 *
4 * Distribute under GPLv2.
5 *
6 * The original driver was written by:
7 * Jeff Lee <YY_Lee@issc.com.tw>
8 *
9 * and was adapted to the 2.6 kernel by:
10 * Costantino Leandro (Rxart Desktop) <le_costantino@pixartargentina.com.ar>
11 */
12#include <net/mac80211.h>
13#include <linux/usb.h>
14#include <linux/module.h>
15
16#include "core.h"
17#include "mds_f.h"
18#include "mto.h"
19#include "wbhal.h"
20#include "wb35reg_f.h"
21#include "wb35tx_f.h"
22#include "wb35rx_f.h"
23
24MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
25MODULE_LICENSE("GPL");
26MODULE_VERSION("0.1");
27
28static const struct usb_device_id wb35_table[] = {
29    { USB_DEVICE(0x0416, 0x0035) },
30    { USB_DEVICE(0x18E8, 0x6201) },
31    { USB_DEVICE(0x18E8, 0x6206) },
32    { USB_DEVICE(0x18E8, 0x6217) },
33    { USB_DEVICE(0x18E8, 0x6230) },
34    { USB_DEVICE(0x18E8, 0x6233) },
35    { USB_DEVICE(0x1131, 0x2035) },
36    { 0, }
37};
38
39MODULE_DEVICE_TABLE(usb, wb35_table);
40
41static struct ieee80211_rate wbsoft_rates[] = {
42    { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
43};
44
45static struct ieee80211_channel wbsoft_channels[] = {
46    { .center_freq = 2412 },
47};
48
49static struct ieee80211_supported_band wbsoft_band_2GHz = {
50    .channels = wbsoft_channels,
51    .n_channels = ARRAY_SIZE(wbsoft_channels),
52    .bitrates = wbsoft_rates,
53    .n_bitrates = ARRAY_SIZE(wbsoft_rates),
54};
55
56static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
57{
58    u32 tmp;
59
60    if (pHwData->SurpriseRemove)
61        return;
62
63    pHwData->BeaconPeriod = beacon_period;
64    tmp = pHwData->BeaconPeriod << 16;
65    tmp |= pHwData->ProbeDelay;
66    Wb35Reg_Write(pHwData, 0x0848, tmp);
67}
68
69static int wbsoft_add_interface(struct ieee80211_hw *dev,
70                struct ieee80211_vif *vif)
71{
72    struct wbsoft_priv *priv = dev->priv;
73
74    hal_set_beacon_period(&priv->sHwData, vif->bss_conf.beacon_int);
75
76    return 0;
77}
78
79static void wbsoft_remove_interface(struct ieee80211_hw *dev,
80                    struct ieee80211_vif *vif)
81{
82    printk("wbsoft_remove interface called\n");
83}
84
85static void wbsoft_stop(struct ieee80211_hw *hw)
86{
87    printk(KERN_INFO "%s called\n", __func__);
88}
89
90static int wbsoft_get_stats(struct ieee80211_hw *hw,
91                struct ieee80211_low_level_stats *stats)
92{
93    printk(KERN_INFO "%s called\n", __func__);
94    return 0;
95}
96
97static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw,
98                    struct netdev_hw_addr_list *mc_list)
99{
100    return netdev_hw_addr_list_count(mc_list);
101}
102
103static void wbsoft_configure_filter(struct ieee80211_hw *dev,
104                    unsigned int changed_flags,
105                    unsigned int *total_flags,
106                    u64 multicast)
107{
108    unsigned int new_flags;
109
110    new_flags = 0;
111
112    if (*total_flags & FIF_PROMISC_IN_BSS)
113        new_flags |= FIF_PROMISC_IN_BSS;
114    else if ((*total_flags & FIF_ALLMULTI) || (multicast > 32))
115        new_flags |= FIF_ALLMULTI;
116
117    dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
118
119    *total_flags = new_flags;
120}
121
122static void wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
123{
124    struct wbsoft_priv *priv = dev->priv;
125
126    if (priv->sMlmeFrame.IsInUsed != PACKET_FREE_TO_USE) {
127        priv->sMlmeFrame.wNumTxMMPDUDiscarded++;
128        kfree_skb(skb);
129        return;
130    }
131
132    priv->sMlmeFrame.IsInUsed = PACKET_COME_FROM_MLME;
133
134    priv->sMlmeFrame.pMMPDU = skb->data;
135    priv->sMlmeFrame.DataType = FRAME_TYPE_802_11_MANAGEMENT;
136    priv->sMlmeFrame.len = skb->len;
137    priv->sMlmeFrame.wNumTxMMPDU++;
138
139    /*
140     * H/W will enter power save by set the register. S/W don't send null
141     * frame with PWRMgt bit enbled to enter power save now.
142     */
143
144    Mds_Tx(priv);
145}
146
147static int wbsoft_start(struct ieee80211_hw *dev)
148{
149    struct wbsoft_priv *priv = dev->priv;
150
151    priv->enabled = true;
152
153    return 0;
154}
155
156static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off)
157{
158    struct wb35_reg *reg = &pHwData->reg;
159
160    if (pHwData->SurpriseRemove)
161        return;
162
163    if (radio_off) { /* disable Baseband receive off */
164        pHwData->CurrentRadioSw = 1; /* off */
165        reg->M24_MacControl &= 0xffffffbf;
166    } else {
167        pHwData->CurrentRadioSw = 0; /* on */
168        reg->M24_MacControl |= 0x00000040;
169    }
170    Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl);
171}
172
173static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info channel)
174{
175    struct wb35_reg *reg = &pHwData->reg;
176
177    if (pHwData->SurpriseRemove)
178        return;
179
180    printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo);
181
182    RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */
183    pHwData->Channel = channel.ChanNo;
184    pHwData->band = channel.band;
185    pr_debug("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band);
186    reg->M28_MacControl &= ~0xff; /* Clean channel information field */
187    reg->M28_MacControl |= channel.ChanNo;
188    Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
189                       (s8 *) &channel,
190                       sizeof(struct chan_info));
191}
192
193static void hal_set_current_channel(struct hw_data *pHwData, struct chan_info channel)
194{
195    hal_set_current_channel_ex(pHwData, channel);
196}
197
198static void hal_set_accept_broadcast(struct hw_data *pHwData, u8 enable)
199{
200    struct wb35_reg *reg = &pHwData->reg;
201
202    if (pHwData->SurpriseRemove)
203        return;
204
205    reg->M00_MacControl &= ~0x02000000; /* The HW value */
206
207    if (enable)
208        reg->M00_MacControl |= 0x02000000; /* The HW value */
209
210    Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
211}
212
213/* For wep key error detection, we need to accept broadcast packets to be received temporary. */
214static void hal_set_accept_promiscuous(struct hw_data *pHwData, u8 enable)
215{
216    struct wb35_reg *reg = &pHwData->reg;
217
218    if (pHwData->SurpriseRemove)
219        return;
220
221    if (enable) {
222        reg->M00_MacControl |= 0x00400000;
223        Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
224    } else {
225        reg->M00_MacControl &= ~0x00400000;
226        Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
227    }
228}
229
230static void hal_set_accept_multicast(struct hw_data *pHwData, u8 enable)
231{
232    struct wb35_reg *reg = &pHwData->reg;
233
234    if (pHwData->SurpriseRemove)
235        return;
236
237    reg->M00_MacControl &= ~0x01000000; /* The HW value */
238    if (enable)
239        reg->M00_MacControl |= 0x01000000; /* The HW value */
240    Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
241}
242
243static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable)
244{
245    struct wb35_reg *reg = &pHwData->reg;
246
247    if (pHwData->SurpriseRemove)
248        return;
249
250    if (!enable) /* Due to SME and MLME are not suitable for 35 */
251        return;
252
253    reg->M00_MacControl &= ~0x04000000; /* The HW value */
254    if (enable)
255        reg->M00_MacControl |= 0x04000000; /* The HW value */
256
257    Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
258}
259
260static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
261{
262    struct wbsoft_priv *priv = dev->priv;
263    struct chan_info ch;
264
265    printk("wbsoft_config called\n");
266
267    /* Should use channel_num, or something, as that is already pre-translated */
268    ch.band = 1;
269    ch.ChanNo = 1;
270
271    hal_set_current_channel(&priv->sHwData, ch);
272    hal_set_accept_broadcast(&priv->sHwData, 1);
273    hal_set_accept_promiscuous(&priv->sHwData, 1);
274    hal_set_accept_multicast(&priv->sHwData, 1);
275    hal_set_accept_beacon(&priv->sHwData, 1);
276    hal_set_radio_mode(&priv->sHwData, 0);
277
278    return 0;
279}
280
281static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
282{
283    printk("wbsoft_get_tsf called\n");
284    return 0;
285}
286
287static const struct ieee80211_ops wbsoft_ops = {
288    .tx = wbsoft_tx,
289    .start = wbsoft_start,
290    .stop = wbsoft_stop,
291    .add_interface = wbsoft_add_interface,
292    .remove_interface = wbsoft_remove_interface,
293    .config = wbsoft_config,
294    .prepare_multicast = wbsoft_prepare_multicast,
295    .configure_filter = wbsoft_configure_filter,
296    .get_stats = wbsoft_get_stats,
297    .get_tsf = wbsoft_get_tsf,
298};
299
300static void hal_set_ethernet_address(struct hw_data *pHwData, u8 *current_address)
301{
302    u32 ltmp[2];
303
304    if (pHwData->SurpriseRemove)
305        return;
306
307    memcpy(pHwData->CurrentMacAddress, current_address, ETH_ALEN);
308
309    ltmp[0] = cpu_to_le32(*(u32 *) pHwData->CurrentMacAddress);
310    ltmp[1] = cpu_to_le32(*(u32 *) (pHwData->CurrentMacAddress + 4)) & 0xffff;
311
312    Wb35Reg_BurstWrite(pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT);
313}
314
315static void hal_get_permanent_address(struct hw_data *pHwData, u8 *pethernet_address)
316{
317    if (pHwData->SurpriseRemove)
318        return;
319
320    memcpy(pethernet_address, pHwData->PermanentMacAddress, 6);
321}
322
323static void hal_stop(struct hw_data *pHwData)
324{
325    struct wb35_reg *reg = &pHwData->reg;
326
327    pHwData->Wb35Rx.rx_halt = 1;
328    Wb35Rx_stop(pHwData);
329
330    pHwData->Wb35Tx.tx_halt = 1;
331    Wb35Tx_stop(pHwData);
332
333    reg->D00_DmaControl &= ~0xc0000000; /* Tx Off, Rx Off */
334    Wb35Reg_Write(pHwData, 0x0400, reg->D00_DmaControl);
335}
336
337static unsigned char hal_idle(struct hw_data *pHwData)
338{
339    struct wb35_reg *reg = &pHwData->reg;
340
341    if (!pHwData->SurpriseRemove && reg->EP0vm_state != VM_STOP)
342        return false;
343
344    return true;
345}
346
347u8 hal_get_antenna_number(struct hw_data *pHwData)
348{
349    struct wb35_reg *reg = &pHwData->reg;
350
351    if ((reg->BB2C & BIT(11)) == 0)
352        return 0;
353    else
354        return 1;
355}
356
357/* 0 : radio on; 1: radio off */
358static u8 hal_get_hw_radio_off(struct hw_data *pHwData)
359{
360    struct wb35_reg *reg = &pHwData->reg;
361
362    if (pHwData->SurpriseRemove)
363        return 1;
364
365    /* read the bit16 of register U1B0 */
366    Wb35Reg_Read(pHwData, 0x3b0, &reg->U1B0);
367    if ((reg->U1B0 & 0x00010000)) {
368        pHwData->CurrentRadioHw = 1;
369        return 1;
370    } else {
371        pHwData->CurrentRadioHw = 0;
372        return 0;
373    }
374}
375
376static u8 LED_GRAY[20] = {
377    0, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 8, 6, 4, 2
378};
379
380static u8 LED_GRAY2[30] = {
381    7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382    0, 15, 14, 13, 12, 11, 10, 9, 8
383};
384
385static void hal_led_control(unsigned long data)
386{
387    struct wbsoft_priv *adapter = (struct wbsoft_priv *)data;
388    struct hw_data *pHwData = &adapter->sHwData;
389    struct wb35_reg *reg = &pHwData->reg;
390    u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
391    u32 TimeInterval = 500, ltmp, ltmp2;
392    ltmp = 0;
393
394    if (pHwData->SurpriseRemove)
395        return;
396
397    if (pHwData->LED_control) {
398        ltmp2 = pHwData->LED_control & 0xff;
399        if (ltmp2 == 5) { /* 5 is WPS mode */
400            TimeInterval = 100;
401            ltmp2 = (pHwData->LED_control >> 8) & 0xff;
402            switch (ltmp2) {
403            case 1: /* [0.2 On][0.1 Off]... */
404                pHwData->LED_Blinking %= 3;
405                ltmp = 0x1010; /* Led 1 & 0 Green and Red */
406                if (pHwData->LED_Blinking == 2) /* Turn off */
407                    ltmp = 0;
408                break;
409            case 2: /* [0.1 On][0.1 Off]... */
410                pHwData->LED_Blinking %= 2;
411                ltmp = 0x0010; /* Led 0 red color */
412                if (pHwData->LED_Blinking) /* Turn off */
413                    ltmp = 0;
414                break;
415            case 3: /* [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]... */
416                pHwData->LED_Blinking %= 15;
417                ltmp = 0x0010; /* Led 0 red color */
418                if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2)) /* Turn off 0.6 sec */
419                    ltmp = 0;
420                break;
421            case 4: /* [300 On][ off ] */
422                ltmp = 0x1000; /* Led 1 Green color */
423                if (pHwData->LED_Blinking >= 3000)
424                    ltmp = 0; /* led maybe on after 300sec * 32bit counter overlap. */
425                break;
426            }
427            pHwData->LED_Blinking++;
428
429            reg->U1BC_LEDConfigure = ltmp;
430            if (LEDSet != 7) { /* Only 111 mode has 2 LEDs on PCB. */
431                reg->U1BC_LEDConfigure |= (ltmp & 0xff) << 8; /* Copy LED result to each LED control register */
432                reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8;
433            }
434            Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
435        }
436    } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw) { /* If radio off */
437        if (reg->U1BC_LEDConfigure & 0x1010) {
438            reg->U1BC_LEDConfigure &= ~0x1010;
439            Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
440        }
441    } else {
442        switch (LEDSet) {
443        case 4: /* [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
444            if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
445                /* Blinking if scanning is on progress */
446                if (pHwData->LED_Scanning) {
447                    if (pHwData->LED_Blinking == 0) {
448                        reg->U1BC_LEDConfigure |= 0x10;
449                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
450                        pHwData->LED_Blinking = 1;
451                        TimeInterval = 300;
452                    } else {
453                        reg->U1BC_LEDConfigure &= ~0x10;
454                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
455                        pHwData->LED_Blinking = 0;
456                        TimeInterval = 300;
457                    }
458                } else {
459                    /* Turn Off LED_0 */
460                    if (reg->U1BC_LEDConfigure & 0x10) {
461                        reg->U1BC_LEDConfigure &= ~0x10;
462                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
463                    }
464                }
465            } else {
466                /* Turn On LED_0 */
467                if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
468                    reg->U1BC_LEDConfigure |= 0x10;
469                    Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
470                }
471            }
472            break;
473        case 6: /* [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
474            if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
475                /* Blinking if scanning is on progress */
476                if (pHwData->LED_Scanning) {
477                    if (pHwData->LED_Blinking == 0) {
478                        reg->U1BC_LEDConfigure &= ~0xf;
479                        reg->U1BC_LEDConfigure |= 0x10;
480                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
481                        pHwData->LED_Blinking = 1;
482                        TimeInterval = 300;
483                    } else {
484                        reg->U1BC_LEDConfigure &= ~0x1f;
485                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
486                        pHwData->LED_Blinking = 0;
487                        TimeInterval = 300;
488                    }
489                } else {
490                    /* Gray blinking if in disconnect state and not scanning */
491                    ltmp = reg->U1BC_LEDConfigure;
492                    reg->U1BC_LEDConfigure &= ~0x1f;
493                    if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) {
494                        reg->U1BC_LEDConfigure |= 0x10;
495                        reg->U1BC_LEDConfigure |=
496                            LED_GRAY2[(pHwData->LED_Blinking % 30)];
497                    }
498                    pHwData->LED_Blinking++;
499                    if (reg->U1BC_LEDConfigure != ltmp)
500                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
501                    TimeInterval = 100;
502                }
503            } else {
504                /* Turn On LED_0 */
505                if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
506                    reg->U1BC_LEDConfigure |= 0x10;
507                    Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
508                }
509            }
510            break;
511        case 5: /* [101] Only 1 Led be placed on PCB and use LED_1 for showing */
512            if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
513                /* Blinking if scanning is on progress */
514                if (pHwData->LED_Scanning) {
515                    if (pHwData->LED_Blinking == 0) {
516                        reg->U1BC_LEDConfigure |= 0x1000;
517                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
518                        pHwData->LED_Blinking = 1;
519                        TimeInterval = 300;
520                    } else {
521                        reg->U1BC_LEDConfigure &= ~0x1000;
522                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
523                        pHwData->LED_Blinking = 0;
524                        TimeInterval = 300;
525                    }
526                } else {
527                    /* Turn Off LED_1 */
528                    if (reg->U1BC_LEDConfigure & 0x1000) {
529                        reg->U1BC_LEDConfigure &= ~0x1000;
530                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
531                    }
532                }
533            } else {
534                /* Is transmitting/receiving ?? */
535                if ((adapter->RxByteCount !=
536                     pHwData->RxByteCountLast)
537                    || (adapter->TxByteCount !=
538                    pHwData->TxByteCountLast)) {
539                    if ((reg->U1BC_LEDConfigure & 0x3000) !=
540                        0x3000) {
541                        reg->U1BC_LEDConfigure |= 0x3000;
542                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
543                    }
544                    /* Update variable */
545                    pHwData->RxByteCountLast =
546                        adapter->RxByteCount;
547                    pHwData->TxByteCountLast =
548                        adapter->TxByteCount;
549                    TimeInterval = 200;
550                } else {
551                    /* Turn On LED_1 and blinking if transmitting/receiving */
552                    if ((reg->U1BC_LEDConfigure & 0x3000) !=
553                        0x1000) {
554                        reg->U1BC_LEDConfigure &=
555                            ~0x3000;
556                        reg->U1BC_LEDConfigure |=
557                            0x1000;
558                        Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
559                    }
560                }
561            }
562            break;
563        default: /* Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active */
564            if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) {
565                reg->U1BC_LEDConfigure |= 0x3000; /* LED_1 is always on and event enable */
566                Wb35Reg_Write(pHwData, 0x03bc,
567                          reg->U1BC_LEDConfigure);
568            }
569
570            if (pHwData->LED_Blinking) {
571                /* Gray blinking */
572                reg->U1BC_LEDConfigure &= ~0x0f;
573                reg->U1BC_LEDConfigure |= 0x10;
574                reg->U1BC_LEDConfigure |=
575                    LED_GRAY[(pHwData->LED_Blinking - 1) % 20];
576                Wb35Reg_Write(pHwData, 0x03bc,
577                          reg->U1BC_LEDConfigure);
578
579                pHwData->LED_Blinking += 2;
580                if (pHwData->LED_Blinking < 40)
581                    TimeInterval = 100;
582                else {
583                    pHwData->LED_Blinking = 0; /* Stop blinking */
584                    reg->U1BC_LEDConfigure &= ~0x0f;
585                    Wb35Reg_Write(pHwData, 0x03bc,
586                              reg->U1BC_LEDConfigure);
587                }
588                break;
589            }
590
591            if (pHwData->LED_LinkOn) {
592                if (!(reg->U1BC_LEDConfigure & 0x10)) { /* Check the LED_0 */
593                    /* Try to turn ON LED_0 after gray blinking */
594                    reg->U1BC_LEDConfigure |= 0x10;
595                    pHwData->LED_Blinking = 1; /* Start blinking */
596                    TimeInterval = 50;
597                }
598            } else {
599                if (reg->U1BC_LEDConfigure & 0x10) { /* Check the LED_0 */
600                    reg->U1BC_LEDConfigure &= ~0x10;
601                    Wb35Reg_Write(pHwData, 0x03bc,
602                              reg->U1BC_LEDConfigure);
603                }
604            }
605            break;
606        }
607    }
608
609    pHwData->time_count += TimeInterval;
610    Wb35Tx_CurrentTime(adapter, pHwData->time_count);
611    pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval);
612    add_timer(&pHwData->LEDTimer);
613}
614
615static int hal_init_hardware(struct ieee80211_hw *hw)
616{
617    struct wbsoft_priv *priv = hw->priv;
618    struct hw_data *pHwData = &priv->sHwData;
619    u16 SoftwareSet;
620
621    pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME;
622    pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
623
624    if (!Wb35Reg_initial(pHwData))
625        goto error_reg_destroy;
626
627    if (!Wb35Tx_initial(pHwData))
628        goto error_tx_destroy;
629
630    if (!Wb35Rx_initial(pHwData))
631        goto error_rx_destroy;
632
633    init_timer(&pHwData->LEDTimer);
634    pHwData->LEDTimer.function = hal_led_control;
635    pHwData->LEDTimer.data = (unsigned long)priv;
636    pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000);
637    add_timer(&pHwData->LEDTimer);
638
639    SoftwareSet = hal_software_set(pHwData);
640
641    Wb35Rx_start(hw);
642    Wb35Tx_EP2VM_start(priv);
643
644    return 0;
645
646error_rx_destroy:
647    Wb35Rx_destroy(pHwData);
648error_tx_destroy:
649    Wb35Tx_destroy(pHwData);
650error_reg_destroy:
651    Wb35Reg_destroy(pHwData);
652
653    pHwData->SurpriseRemove = 1;
654    return -EINVAL;
655}
656
657static int wb35_hw_init(struct ieee80211_hw *hw)
658{
659    struct wbsoft_priv *priv = hw->priv;
660    struct hw_data *pHwData = &priv->sHwData;
661    u8 EEPROM_region;
662    u8 HwRadioOff;
663    u8 *pMacAddr2;
664    u8 *pMacAddr;
665    int err;
666
667    pHwData->phy_type = RF_DECIDE_BY_INF;
668
669    priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
670    priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
671
672    priv->sLocalPara.region_INF = REGION_AUTO;
673    priv->sLocalPara.TxRateMode = RATE_AUTO;
674    priv->sLocalPara.bMacOperationMode = MODE_802_11_BG;
675    priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
676    priv->sLocalPara.bPreambleMode = AUTO_MODE;
677    priv->sLocalPara.bWepKeyError = false;
678    priv->sLocalPara.bToSelfPacketReceived = false;
679    priv->sLocalPara.WepKeyDetectTimerCount = 2 * 100; /* 2 seconds */
680
681    priv->sLocalPara.RadioOffStatus.boSwRadioOff = false;
682
683    err = hal_init_hardware(hw);
684    if (err)
685        goto error;
686
687    EEPROM_region = hal_get_region_from_EEPROM(pHwData);
688    if (EEPROM_region != REGION_AUTO)
689        priv->sLocalPara.region = EEPROM_region;
690    else {
691        if (priv->sLocalPara.region_INF != REGION_AUTO)
692            priv->sLocalPara.region = priv->sLocalPara.region_INF;
693        else
694            priv->sLocalPara.region = REGION_USA; /* default setting */
695    }
696
697    Mds_initial(priv);
698
699    /*
700     * If no user-defined address in the registry, use the address
701     * "burned" on the NIC instead.
702     */
703    pMacAddr = priv->sLocalPara.ThisMacAddress;
704    pMacAddr2 = priv->sLocalPara.PermanentAddress;
705
706    /* Reading ethernet address from EEPROM */
707    hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress);
708    if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0)
709        memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH);
710    else {
711        /* Set the user define MAC address */
712        hal_set_ethernet_address(pHwData,
713                     priv->sLocalPara.ThisMacAddress);
714    }
715
716    priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
717    pr_debug("Driver init, antenna no = %d\n", priv->sLocalPara.bAntennaNo);
718    hal_get_hw_radio_off(pHwData);
719
720    /* Waiting for HAL setting OK */
721    while (!hal_idle(pHwData))
722        msleep(10);
723
724    MTO_Init(priv);
725
726    HwRadioOff = hal_get_hw_radio_off(pHwData);
727    priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff;
728
729    hal_set_radio_mode(pHwData,
730               (unsigned char)(priv->sLocalPara.RadioOffStatus.
731                       boSwRadioOff
732                       || priv->sLocalPara.RadioOffStatus.
733                       boHwRadioOff));
734
735    /* Notify hal that the driver is ready now. */
736    hal_driver_init_OK(pHwData) = 1;
737
738error:
739    return err;
740}
741
742static int wb35_probe(struct usb_interface *intf,
743              const struct usb_device_id *id_table)
744{
745    struct usb_device *udev = interface_to_usbdev(intf);
746    struct usb_endpoint_descriptor *endpoint;
747    struct usb_host_interface *interface;
748    struct ieee80211_hw *dev;
749    struct wbsoft_priv *priv;
750    int err;
751    u32 ltmp;
752
753    usb_get_dev(udev);
754
755    /* Check the device if it already be opened */
756    err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
757                 0x01,
758                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
759                 0x0, 0x400, &ltmp, 4, HZ * 100);
760    if (err < 0)
761        goto error;
762
763    /* Is already initialized? */
764    ltmp = cpu_to_le32(ltmp);
765    if (ltmp) {
766        err = -EBUSY;
767        goto error;
768    }
769
770    dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
771    if (!dev) {
772        err = -ENOMEM;
773        goto error;
774    }
775
776    priv = dev->priv;
777
778    priv->sHwData.udev = udev;
779
780    interface = intf->cur_altsetting;
781    endpoint = &interface->endpoint[0].desc;
782
783    if (endpoint[2].wMaxPacketSize == 512)
784        printk("[w35und] Working on USB 2.0\n");
785
786    err = wb35_hw_init(dev);
787    if (err)
788        goto error_free_hw;
789
790    SET_IEEE80211_DEV(dev, &udev->dev);
791    {
792        struct hw_data *pHwData = &priv->sHwData;
793        unsigned char dev_addr[MAX_ADDR_LEN];
794        hal_get_permanent_address(pHwData, dev_addr);
795        SET_IEEE80211_PERM_ADDR(dev, dev_addr);
796    }
797
798    dev->extra_tx_headroom = 12; /* FIXME */
799    dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
800    dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
801
802    dev->channel_change_time = 1000;
803    dev->max_signal = 100;
804    dev->queues = 1;
805
806    dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
807
808    err = ieee80211_register_hw(dev);
809    if (err)
810        goto error_free_hw;
811
812    usb_set_intfdata(intf, dev);
813
814    return 0;
815
816error_free_hw:
817    ieee80211_free_hw(dev);
818error:
819    usb_put_dev(udev);
820    return err;
821}
822
823static void hal_halt(struct hw_data *pHwData)
824{
825    del_timer_sync(&pHwData->LEDTimer);
826    /* XXX: Wait for Timer DPC exit. */
827    msleep(100);
828    Wb35Rx_destroy(pHwData);
829    Wb35Tx_destroy(pHwData);
830    Wb35Reg_destroy(pHwData);
831}
832
833static void wb35_hw_halt(struct wbsoft_priv *adapter)
834{
835    /* Turn off Rx and Tx hardware ability */
836    hal_stop(&adapter->sHwData);
837    pr_debug("[w35und] Hal_stop O.K.\n");
838    /* Waiting Irp completed */
839    msleep(100);
840
841    hal_halt(&adapter->sHwData);
842}
843
844static void wb35_disconnect(struct usb_interface *intf)
845{
846    struct ieee80211_hw *hw = usb_get_intfdata(intf);
847    struct wbsoft_priv *priv = hw->priv;
848
849    wb35_hw_halt(priv);
850
851    ieee80211_stop_queues(hw);
852    ieee80211_unregister_hw(hw);
853    ieee80211_free_hw(hw);
854
855    usb_set_intfdata(intf, NULL);
856    usb_put_dev(interface_to_usbdev(intf));
857}
858
859static struct usb_driver wb35_driver = {
860    .name = "w35und",
861    .id_table = wb35_table,
862    .probe = wb35_probe,
863    .disconnect = wb35_disconnect,
864};
865
866module_usb_driver(wb35_driver);
867

Archive Download this file



interactive