diff options
Diffstat (limited to 'drivers/staging/winbond/linux/wbusb.c')
-rw-r--r-- | drivers/staging/winbond/linux/wbusb.c | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c new file mode 100644 index 0000000..cbad5fb --- /dev/null +++ b/drivers/staging/winbond/linux/wbusb.c @@ -0,0 +1,404 @@ +/* + * Copyright 2008 Pavel Machek <pavel@suse.cz> + * + * Distribute under GPLv2. + */ +#include "sysdef.h" +#include <net/mac80211.h> + + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + + +//============================================================ +// vendor ID and product ID can into here for others +//============================================================ +static struct usb_device_id Id_Table[] = +{ + {USB_DEVICE( 0x0416, 0x0035 )}, + {USB_DEVICE( 0x18E8, 0x6201 )}, + {USB_DEVICE( 0x18E8, 0x6206 )}, + {USB_DEVICE( 0x18E8, 0x6217 )}, + {USB_DEVICE( 0x18E8, 0x6230 )}, + {USB_DEVICE( 0x18E8, 0x6233 )}, + {USB_DEVICE( 0x1131, 0x2035 )}, + { } +}; + +MODULE_DEVICE_TABLE(usb, Id_Table); + +static struct usb_driver wb35_driver = { + .name = "w35und", + .probe = wb35_probe, + .disconnect = wb35_disconnect, + .id_table = Id_Table, +}; + +static const struct ieee80211_rate wbsoft_rates[] = { + { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, +}; + +static const struct ieee80211_channel wbsoft_channels[] = { + { .center_freq = 2412}, +}; + +int wbsoft_enabled; +struct ieee80211_hw *my_dev; +PADAPTER my_adapter; + +static int wbsoft_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + printk("wbsoft_add interface called\n"); + return 0; +} + +static void wbsoft_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + printk("wbsoft_remove interface called\n"); +} + +static int wbsoft_nop(void) +{ + printk("wbsoft_nop called\n"); + return 0; +} + +static void wbsoft_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + unsigned int bit_nr, new_flags; + u32 mc_filter[2]; + int i; + + new_flags = 0; + + if (*total_flags & FIF_PROMISC_IN_BSS) { + new_flags |= FIF_PROMISC_IN_BSS; + mc_filter[1] = mc_filter[0] = ~0; + } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + new_flags |= FIF_ALLMULTI; + mc_filter[1] = mc_filter[0] = ~0; + } else { + mc_filter[1] = mc_filter[0] = 0; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + printk("Should call ether_crc here\n"); + //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + bit_nr = 0; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + mclist = mclist->next; + } + } + + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + *total_flags = new_flags; +} + +static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + char *buffer = kmalloc(skb->len, GFP_ATOMIC); + printk("Sending frame %d bytes\n", skb->len); + memcpy(buffer, skb->data, skb->len); + if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT)) + printk("frame sent ok (%d bytes)?\n", skb->len); + return NETDEV_TX_OK; +} + + +static int wbsoft_start(struct ieee80211_hw *dev) +{ + wbsoft_enabled = 1; + printk("wbsoft_start called\n"); + return 0; +} + +static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + ChanInfo ch; + printk("wbsoft_config called\n"); + + ch.band = 1; + ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ + + + hal_set_current_channel(&my_adapter->sHwData, ch); + hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int); +// hal_set_cap_info(&my_adapter->sHwData, ?? ); +// hal_set_ssid(phw_data_t pHwData, PUCHAR pssid, u8 ssid_len); ?? + hal_set_accept_broadcast(&my_adapter->sHwData, 1); + hal_set_accept_promiscuous(&my_adapter->sHwData, 1); + hal_set_accept_multicast(&my_adapter->sHwData, 1); + hal_set_accept_beacon(&my_adapter->sHwData, 1); + hal_set_radio_mode(&my_adapter->sHwData, 0); + //hal_set_antenna_number( phw_data_t pHwData, u8 number ) + //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) + + +// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? + +//void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates, +// u8 length, unsigned char basic_rate_set) + + return 0; +} + +static int wbsoft_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + printk("wbsoft_config_interface called\n"); + return 0; +} + +static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) +{ + printk("wbsoft_get_tsf called\n"); + return 0; +} + +static const struct ieee80211_ops wbsoft_ops = { + .tx = wbsoft_tx, + .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */ + .stop = wbsoft_nop, + .add_interface = wbsoft_add_interface, + .remove_interface = wbsoft_remove_interface, + .config = wbsoft_config, + .config_interface = wbsoft_config_interface, + .configure_filter = wbsoft_configure_filter, + .get_stats = wbsoft_nop, + .get_tx_stats = wbsoft_nop, + .get_tsf = wbsoft_get_tsf, +// conf_tx: hal_set_cwmin()/hal_set_cwmax; +}; + +struct wbsoft_priv { +}; + + +int __init wb35_init(void) +{ + printk("[w35und]driver init\n"); + return usb_register(&wb35_driver); +} + +void __exit wb35_exit(void) +{ + printk("[w35und]driver exit\n"); + usb_deregister( &wb35_driver ); +} + +module_init(wb35_init); +module_exit(wb35_exit); + +// Usb kernel subsystem will call this function when a new device is plugged into. +int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) +{ + PADAPTER Adapter; + PWBLINUX pWbLinux; + PWBUSB pWbUsb; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + int i, ret = -1; + u32 ltmp; + struct usb_device *udev = interface_to_usbdev(intf); + + usb_get_dev(udev); + + printk("[w35und]wb35_probe ->\n"); + + do { + for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) { + if ((udev->descriptor.idVendor == Id_Table[i].idVendor) && + (udev->descriptor.idProduct == Id_Table[i].idProduct)) { + printk("[w35und]Found supported hardware\n"); + break; + } + } + if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) { + #ifdef _PE_USB_INI_DUMP_ + WBDEBUG(("[w35und] This is not the one we are interested about\n")); + #endif + return -ENODEV; + } + + // 20060630.2 Check the device if it already be opened + ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), + 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, + 0x0, 0x400, <mp, 4, HZ*100 ); + if( ret < 0 ) + break; + + ltmp = cpu_to_le32(ltmp); + if (ltmp) // Is already initialized? + break; + + + Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL); + + my_adapter = Adapter; + pWbLinux = &Adapter->WbLinux; + pWbUsb = &Adapter->sHwData.WbUsb; + pWbUsb->udev = udev; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + if (endpoint[2].wMaxPacketSize == 512) { + printk("[w35und] Working on USB 2.0\n"); + pWbUsb->IsUsb20 = 1; + } + + if (!WbWLanInitialize(Adapter)) { + printk("[w35und]WbWLanInitialize fail\n"); + break; + } + + { + struct wbsoft_priv *priv; + struct ieee80211_hw *dev; + int res; + + dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); + + if (!dev) { + printk("w35und: ieee80211 alloc failed\n" ); + BUG(); + } + + my_dev = dev; + + SET_IEEE80211_DEV(dev, &udev->dev); + { + phw_data_t pHwData = &Adapter->sHwData; + unsigned char dev_addr[MAX_ADDR_LEN]; + hal_get_permanent_address(pHwData, dev_addr); + SET_IEEE80211_PERM_ADDR(dev, dev_addr); + } + + + dev->extra_tx_headroom = 12; /* FIXME */ + dev->flags = 0; + + dev->channel_change_time = 1000; +// dev->max_rssi = 100; + + dev->queues = 1; + + static struct ieee80211_supported_band band; + + band.channels = wbsoft_channels; + band.n_channels = ARRAY_SIZE(wbsoft_channels); + band.bitrates = wbsoft_rates; + band.n_bitrates = ARRAY_SIZE(wbsoft_rates); + + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band; +#if 0 + wbsoft_modes[0].num_channels = 1; + wbsoft_modes[0].channels = wbsoft_channels; + wbsoft_modes[0].mode = MODE_IEEE80211B; + wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates); + wbsoft_modes[0].rates = wbsoft_rates; + + res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]); + BUG_ON(res); +#endif + + res = ieee80211_register_hw(dev); + BUG_ON(res); + } + + usb_set_intfdata( intf, Adapter ); + + printk("[w35und] _probe OK\n"); + return 0; + + } while(FALSE); + + return -ENOMEM; +} + +void packet_came(char *pRxBufferAddress, int PacketSize) +{ + struct sk_buff *skb; + struct ieee80211_rx_status rx_status = {0}; + + if (!wbsoft_enabled) + return; + + skb = dev_alloc_skb(PacketSize); + if (!skb) { + printk("Not enough memory for packet, FIXME\n"); + return; + } + + memcpy(skb_put(skb, PacketSize), + pRxBufferAddress, + PacketSize); + +/* + rx_status.rate = 10; + rx_status.channel = 1; + rx_status.freq = 12345; + rx_status.phymode = MODE_IEEE80211B; +*/ + + ieee80211_rx_irqsafe(my_dev, skb, &rx_status); +} + +unsigned char +WbUsb_initial(phw_data_t pHwData) +{ + return 1; +} + + +void +WbUsb_destroy(phw_data_t pHwData) +{ +} + +int wb35_open(struct net_device *netdev) +{ + PADAPTER Adapter = (PADAPTER)netdev->priv; + phw_data_t pHwData = &Adapter->sHwData; + + netif_start_queue(netdev); + + //TODO : put here temporarily + hal_set_accept_broadcast(pHwData, 1); // open accept broadcast + + return 0; +} + +int wb35_close(struct net_device *netdev) +{ + netif_stop_queue(netdev); + return 0; +} + +void wb35_disconnect(struct usb_interface *intf) +{ + PWBLINUX pWbLinux; + PADAPTER Adapter = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + pWbLinux = &Adapter->WbLinux; + + // Card remove + WbWlanHalt(Adapter); + +} + + |