blob: bd708a2d14848042ed31077c05d94eba22d75b57 [file] [log] [blame]
Pavel Machek66101de2008-10-01 14:36:56 +02001/*
2 * Copyright 2008 Pavel Machek <pavel@suse.cz>
3 *
4 * Distribute under GPLv2.
5 */
6#include "sysdef.h"
7#include <net/mac80211.h>
8
Pekka Enbergdd38da42008-10-21 13:01:42 +03009MODULE_AUTHOR(DRIVER_AUTHOR);
10MODULE_DESCRIPTION(DRIVER_DESC);
Pavel Machek66101de2008-10-01 14:36:56 +020011MODULE_LICENSE("GPL");
12MODULE_VERSION("0.1");
13
Pekka Enbergdd38da42008-10-21 13:01:42 +030014static struct usb_device_id wb35_table[] __devinitdata = {
15 {USB_DEVICE(0x0416, 0x0035)},
16 {USB_DEVICE(0x18E8, 0x6201)},
17 {USB_DEVICE(0x18E8, 0x6206)},
18 {USB_DEVICE(0x18E8, 0x6217)},
19 {USB_DEVICE(0x18E8, 0x6230)},
20 {USB_DEVICE(0x18E8, 0x6233)},
21 {USB_DEVICE(0x1131, 0x2035)},
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070022 { 0, }
Pavel Machek66101de2008-10-01 14:36:56 +020023};
24
Pekka Enbergdd38da42008-10-21 13:01:42 +030025MODULE_DEVICE_TABLE(usb, wb35_table);
Pavel Machek66101de2008-10-01 14:36:56 +020026
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070027static struct ieee80211_rate wbsoft_rates[] = {
Pavel Machek66101de2008-10-01 14:36:56 +020028 { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
29};
30
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070031static struct ieee80211_channel wbsoft_channels[] = {
Pavel Machek66101de2008-10-01 14:36:56 +020032 { .center_freq = 2412},
33};
34
Pekka Enberga36e0892008-10-28 00:20:03 +020035static struct ieee80211_supported_band wbsoft_band_2GHz = {
36 .channels = wbsoft_channels,
37 .n_channels = ARRAY_SIZE(wbsoft_channels),
38 .bitrates = wbsoft_rates,
39 .n_bitrates = ARRAY_SIZE(wbsoft_rates),
40};
41
Pavel Machek66101de2008-10-01 14:36:56 +020042int wbsoft_enabled;
43struct ieee80211_hw *my_dev;
Pekka Enberg88ebc4b2008-10-22 11:03:19 +030044struct wb35_adapter * my_adapter;
Pavel Machek66101de2008-10-01 14:36:56 +020045
46static int wbsoft_add_interface(struct ieee80211_hw *dev,
47 struct ieee80211_if_init_conf *conf)
48{
49 printk("wbsoft_add interface called\n");
50 return 0;
51}
52
53static void wbsoft_remove_interface(struct ieee80211_hw *dev,
54 struct ieee80211_if_init_conf *conf)
55{
56 printk("wbsoft_remove interface called\n");
57}
58
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070059static void wbsoft_stop(struct ieee80211_hw *hw)
Pavel Machek66101de2008-10-01 14:36:56 +020060{
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070061 printk(KERN_INFO "%s called\n", __func__);
62}
63
64static int wbsoft_get_stats(struct ieee80211_hw *hw,
65 struct ieee80211_low_level_stats *stats)
66{
67 printk(KERN_INFO "%s called\n", __func__);
68 return 0;
69}
70
71static int wbsoft_get_tx_stats(struct ieee80211_hw *hw,
72 struct ieee80211_tx_queue_stats *stats)
73{
74 printk(KERN_INFO "%s called\n", __func__);
Pavel Machek66101de2008-10-01 14:36:56 +020075 return 0;
76}
77
78static void wbsoft_configure_filter(struct ieee80211_hw *dev,
79 unsigned int changed_flags,
80 unsigned int *total_flags,
81 int mc_count, struct dev_mc_list *mclist)
82{
83 unsigned int bit_nr, new_flags;
84 u32 mc_filter[2];
85 int i;
86
87 new_flags = 0;
88
89 if (*total_flags & FIF_PROMISC_IN_BSS) {
90 new_flags |= FIF_PROMISC_IN_BSS;
91 mc_filter[1] = mc_filter[0] = ~0;
92 } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
93 new_flags |= FIF_ALLMULTI;
94 mc_filter[1] = mc_filter[0] = ~0;
95 } else {
96 mc_filter[1] = mc_filter[0] = 0;
97 for (i = 0; i < mc_count; i++) {
98 if (!mclist)
99 break;
100 printk("Should call ether_crc here\n");
101 //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
102 bit_nr = 0;
103
104 bit_nr &= 0x3F;
105 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
106 mclist = mclist->next;
107 }
108 }
109
110 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
111
112 *total_flags = new_flags;
113}
114
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700115static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
Pavel Machek66101de2008-10-01 14:36:56 +0200116{
Pekka Enberg16d36592008-10-28 00:14:38 +0200117 MLMESendFrame(my_adapter, skb->data, skb->len, FRAME_TYPE_802_11_MANAGEMENT);
118
Pavel Machek66101de2008-10-01 14:36:56 +0200119 return NETDEV_TX_OK;
120}
121
122
123static int wbsoft_start(struct ieee80211_hw *dev)
124{
125 wbsoft_enabled = 1;
126 printk("wbsoft_start called\n");
127 return 0;
128}
129
130static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
131{
132 ChanInfo ch;
133 printk("wbsoft_config called\n");
134
135 ch.band = 1;
136 ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */
137
138
139 hal_set_current_channel(&my_adapter->sHwData, ch);
140 hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int);
141// hal_set_cap_info(&my_adapter->sHwData, ?? );
Pekka Enberg8b384e02008-10-21 00:03:41 +0300142// hal_set_ssid(phw_data_t pHwData, u8 * pssid, u8 ssid_len); ??
Pavel Machek66101de2008-10-01 14:36:56 +0200143 hal_set_accept_broadcast(&my_adapter->sHwData, 1);
144 hal_set_accept_promiscuous(&my_adapter->sHwData, 1);
145 hal_set_accept_multicast(&my_adapter->sHwData, 1);
146 hal_set_accept_beacon(&my_adapter->sHwData, 1);
147 hal_set_radio_mode(&my_adapter->sHwData, 0);
148 //hal_set_antenna_number( phw_data_t pHwData, u8 number )
149 //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex)
150
151
152// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ??
153
Pekka Enberg8b384e02008-10-21 00:03:41 +0300154//void hal_set_rates(phw_data_t pHwData, u8 * pbss_rates,
Pavel Machek66101de2008-10-01 14:36:56 +0200155// u8 length, unsigned char basic_rate_set)
156
157 return 0;
158}
159
160static int wbsoft_config_interface(struct ieee80211_hw *dev,
161 struct ieee80211_vif *vif,
162 struct ieee80211_if_conf *conf)
163{
164 printk("wbsoft_config_interface called\n");
165 return 0;
166}
167
168static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
169{
170 printk("wbsoft_get_tsf called\n");
171 return 0;
172}
173
174static const struct ieee80211_ops wbsoft_ops = {
175 .tx = wbsoft_tx,
176 .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700177 .stop = wbsoft_stop,
Pavel Machek66101de2008-10-01 14:36:56 +0200178 .add_interface = wbsoft_add_interface,
179 .remove_interface = wbsoft_remove_interface,
180 .config = wbsoft_config,
181 .config_interface = wbsoft_config_interface,
182 .configure_filter = wbsoft_configure_filter,
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700183 .get_stats = wbsoft_get_stats,
184 .get_tx_stats = wbsoft_get_tx_stats,
Pavel Machek66101de2008-10-01 14:36:56 +0200185 .get_tsf = wbsoft_get_tsf,
186// conf_tx: hal_set_cwmin()/hal_set_cwmax;
187};
188
189struct wbsoft_priv {
190};
191
Pekka Enberg302bae82008-10-22 19:05:54 +0300192static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
Pavel Machek66101de2008-10-01 14:36:56 +0200193{
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300194 struct wb35_adapter *adapter;
Pavel Machek66101de2008-10-01 14:36:56 +0200195 PWBUSB pWbUsb;
196 struct usb_host_interface *interface;
197 struct usb_endpoint_descriptor *endpoint;
Pavel Machek66101de2008-10-01 14:36:56 +0200198 u32 ltmp;
199 struct usb_device *udev = interface_to_usbdev(intf);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300200 struct wbsoft_priv *priv;
201 struct ieee80211_hw *dev;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300202 int err;
Pavel Machek66101de2008-10-01 14:36:56 +0200203
204 usb_get_dev(udev);
205
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300206 // 20060630.2 Check the device if it already be opened
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300207 err = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300208 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
209 0x0, 0x400, &ltmp, 4, HZ*100 );
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300210 if (err)
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300211 goto error;
212
213 ltmp = cpu_to_le32(ltmp);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300214 if (ltmp) { // Is already initialized?
215 err = -EBUSY;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300216 goto error;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300217 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300218
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300219 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300220 if (!adapter) {
221 err = -ENOMEM;
222 goto error;
223 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300224
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300225 my_adapter = adapter;
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300226 pWbUsb = &adapter->sHwData.WbUsb;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300227 pWbUsb->udev = udev;
228
229 interface = intf->cur_altsetting;
230 endpoint = &interface->endpoint[0].desc;
231
232 if (endpoint[2].wMaxPacketSize == 512) {
233 printk("[w35und] Working on USB 2.0\n");
234 pWbUsb->IsUsb20 = 1;
235 }
236
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300237 if (!WbWLanInitialize(adapter)) {
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300238 err = -EINVAL;
239 goto error_free_adapter;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300240 }
241
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300242 dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
243 if (!dev)
244 goto error_free_adapter;
245
246 my_dev = dev;
247
248 SET_IEEE80211_DEV(dev, &udev->dev);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300249 {
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300250 phw_data_t pHwData = &adapter->sHwData;
251 unsigned char dev_addr[MAX_ADDR_LEN];
252 hal_get_permanent_address(pHwData, dev_addr);
253 SET_IEEE80211_PERM_ADDR(dev, dev_addr);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300254 }
Pavel Machek66101de2008-10-01 14:36:56 +0200255
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300256 dev->extra_tx_headroom = 12; /* FIXME */
257 dev->flags = 0;
Pavel Machek66101de2008-10-01 14:36:56 +0200258
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300259 dev->channel_change_time = 1000;
260 dev->queues = 1;
261
Pekka Enberga36e0892008-10-28 00:20:03 +0200262 dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300263
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300264 err = ieee80211_register_hw(dev);
265 if (err)
266 goto error_free_hw;
267
268 usb_set_intfdata(intf, adapter);
269
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300270 return 0;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300271
272error_free_hw:
273 ieee80211_free_hw(dev);
274error_free_adapter:
275 kfree(adapter);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300276error:
Pekka Enberg4af12e52008-10-27 23:29:31 +0200277 usb_put_dev(udev);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300278 return err;
Pavel Machek66101de2008-10-01 14:36:56 +0200279}
280
281void packet_came(char *pRxBufferAddress, int PacketSize)
282{
283 struct sk_buff *skb;
284 struct ieee80211_rx_status rx_status = {0};
285
286 if (!wbsoft_enabled)
287 return;
288
289 skb = dev_alloc_skb(PacketSize);
290 if (!skb) {
291 printk("Not enough memory for packet, FIXME\n");
292 return;
293 }
294
295 memcpy(skb_put(skb, PacketSize),
296 pRxBufferAddress,
297 PacketSize);
298
299/*
300 rx_status.rate = 10;
301 rx_status.channel = 1;
302 rx_status.freq = 12345;
303 rx_status.phymode = MODE_IEEE80211B;
304*/
305
306 ieee80211_rx_irqsafe(my_dev, skb, &rx_status);
307}
308
Pekka Enberg302bae82008-10-22 19:05:54 +0300309static void wb35_disconnect(struct usb_interface *intf)
Pavel Machek66101de2008-10-01 14:36:56 +0200310{
Pekka Enberg4af12e52008-10-27 23:29:31 +0200311 struct wb35_adapter *adapter = usb_get_intfdata(intf);
Pavel Machek66101de2008-10-01 14:36:56 +0200312
Pekka Enberg88ebc4b2008-10-22 11:03:19 +0300313 WbWlanHalt(adapter);
Pavel Machek66101de2008-10-01 14:36:56 +0200314
Pekka Enberg4af12e52008-10-27 23:29:31 +0200315 usb_set_intfdata(intf, NULL);
316 usb_put_dev(interface_to_usbdev(intf));
Pavel Machek66101de2008-10-01 14:36:56 +0200317}
318
Pekka Enbergdd38da42008-10-21 13:01:42 +0300319static struct usb_driver wb35_driver = {
320 .name = "w35und",
321 .id_table = wb35_table,
322 .probe = wb35_probe,
323 .disconnect = wb35_disconnect,
324};
Pavel Machek66101de2008-10-01 14:36:56 +0200325
Pekka Enbergdd38da42008-10-21 13:01:42 +0300326static int __init wb35_init(void)
327{
328 return usb_register(&wb35_driver);
329}
330
331static void __exit wb35_exit(void)
332{
333 usb_deregister(&wb35_driver);
334}
335
336module_init(wb35_init);
337module_exit(wb35_exit);