]>
Commit | Line | Data |
---|---|---|
66101de1 PM |
1 | /* |
2 | * Copyright 2008 Pavel Machek <pavel@suse.cz> | |
3 | * | |
4 | * Distribute under GPLv2. | |
5 | */ | |
6 | #include "sysdef.h" | |
7 | #include <net/mac80211.h> | |
8 | ||
9 | ||
10 | MODULE_AUTHOR( DRIVER_AUTHOR ); | |
11 | MODULE_DESCRIPTION( DRIVER_DESC ); | |
12 | MODULE_LICENSE("GPL"); | |
13 | MODULE_VERSION("0.1"); | |
14 | ||
15 | ||
16 | //============================================================ | |
17 | // vendor ID and product ID can into here for others | |
18 | //============================================================ | |
19 | static struct usb_device_id Id_Table[] = | |
20 | { | |
21 | {USB_DEVICE( 0x0416, 0x0035 )}, | |
22 | {USB_DEVICE( 0x18E8, 0x6201 )}, | |
23 | {USB_DEVICE( 0x18E8, 0x6206 )}, | |
24 | {USB_DEVICE( 0x18E8, 0x6217 )}, | |
25 | {USB_DEVICE( 0x18E8, 0x6230 )}, | |
26 | {USB_DEVICE( 0x18E8, 0x6233 )}, | |
27 | {USB_DEVICE( 0x1131, 0x2035 )}, | |
28 | { } | |
29 | }; | |
30 | ||
31 | MODULE_DEVICE_TABLE(usb, Id_Table); | |
32 | ||
33 | static struct usb_driver wb35_driver = { | |
34 | .name = "w35und", | |
35 | .probe = wb35_probe, | |
36 | .disconnect = wb35_disconnect, | |
37 | .id_table = Id_Table, | |
38 | }; | |
39 | ||
40 | static const struct ieee80211_rate wbsoft_rates[] = { | |
41 | { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | |
42 | }; | |
43 | ||
44 | static const struct ieee80211_channel wbsoft_channels[] = { | |
45 | { .center_freq = 2412}, | |
46 | }; | |
47 | ||
48 | int wbsoft_enabled; | |
49 | struct ieee80211_hw *my_dev; | |
50 | PADAPTER my_adapter; | |
51 | ||
52 | static int wbsoft_add_interface(struct ieee80211_hw *dev, | |
53 | struct ieee80211_if_init_conf *conf) | |
54 | { | |
55 | printk("wbsoft_add interface called\n"); | |
56 | return 0; | |
57 | } | |
58 | ||
59 | static void wbsoft_remove_interface(struct ieee80211_hw *dev, | |
60 | struct ieee80211_if_init_conf *conf) | |
61 | { | |
62 | printk("wbsoft_remove interface called\n"); | |
63 | } | |
64 | ||
65 | static int wbsoft_nop(void) | |
66 | { | |
67 | printk("wbsoft_nop called\n"); | |
68 | return 0; | |
69 | } | |
70 | ||
71 | static void wbsoft_configure_filter(struct ieee80211_hw *dev, | |
72 | unsigned int changed_flags, | |
73 | unsigned int *total_flags, | |
74 | int mc_count, struct dev_mc_list *mclist) | |
75 | { | |
76 | unsigned int bit_nr, new_flags; | |
77 | u32 mc_filter[2]; | |
78 | int i; | |
79 | ||
80 | new_flags = 0; | |
81 | ||
82 | if (*total_flags & FIF_PROMISC_IN_BSS) { | |
83 | new_flags |= FIF_PROMISC_IN_BSS; | |
84 | mc_filter[1] = mc_filter[0] = ~0; | |
85 | } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { | |
86 | new_flags |= FIF_ALLMULTI; | |
87 | mc_filter[1] = mc_filter[0] = ~0; | |
88 | } else { | |
89 | mc_filter[1] = mc_filter[0] = 0; | |
90 | for (i = 0; i < mc_count; i++) { | |
91 | if (!mclist) | |
92 | break; | |
93 | printk("Should call ether_crc here\n"); | |
94 | //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | |
95 | bit_nr = 0; | |
96 | ||
97 | bit_nr &= 0x3F; | |
98 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | |
99 | mclist = mclist->next; | |
100 | } | |
101 | } | |
102 | ||
103 | dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; | |
104 | ||
105 | *total_flags = new_flags; | |
106 | } | |
107 | ||
108 | static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb, | |
109 | struct ieee80211_tx_control *control) | |
110 | { | |
111 | char *buffer = kmalloc(skb->len, GFP_ATOMIC); | |
112 | printk("Sending frame %d bytes\n", skb->len); | |
113 | memcpy(buffer, skb->data, skb->len); | |
114 | if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT)) | |
115 | printk("frame sent ok (%d bytes)?\n", skb->len); | |
116 | return NETDEV_TX_OK; | |
117 | } | |
118 | ||
119 | ||
120 | static int wbsoft_start(struct ieee80211_hw *dev) | |
121 | { | |
122 | wbsoft_enabled = 1; | |
123 | printk("wbsoft_start called\n"); | |
124 | return 0; | |
125 | } | |
126 | ||
127 | static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |
128 | { | |
129 | ChanInfo ch; | |
130 | printk("wbsoft_config called\n"); | |
131 | ||
132 | ch.band = 1; | |
133 | ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ | |
134 | ||
135 | ||
136 | hal_set_current_channel(&my_adapter->sHwData, ch); | |
137 | hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int); | |
138 | // hal_set_cap_info(&my_adapter->sHwData, ?? ); | |
8b384e0c | 139 | // hal_set_ssid(phw_data_t pHwData, u8 * pssid, u8 ssid_len); ?? |
66101de1 PM |
140 | hal_set_accept_broadcast(&my_adapter->sHwData, 1); |
141 | hal_set_accept_promiscuous(&my_adapter->sHwData, 1); | |
142 | hal_set_accept_multicast(&my_adapter->sHwData, 1); | |
143 | hal_set_accept_beacon(&my_adapter->sHwData, 1); | |
144 | hal_set_radio_mode(&my_adapter->sHwData, 0); | |
145 | //hal_set_antenna_number( phw_data_t pHwData, u8 number ) | |
146 | //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) | |
147 | ||
148 | ||
149 | // hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? | |
150 | ||
8b384e0c | 151 | //void hal_set_rates(phw_data_t pHwData, u8 * pbss_rates, |
66101de1 PM |
152 | // u8 length, unsigned char basic_rate_set) |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | static int wbsoft_config_interface(struct ieee80211_hw *dev, | |
158 | struct ieee80211_vif *vif, | |
159 | struct ieee80211_if_conf *conf) | |
160 | { | |
161 | printk("wbsoft_config_interface called\n"); | |
162 | return 0; | |
163 | } | |
164 | ||
165 | static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) | |
166 | { | |
167 | printk("wbsoft_get_tsf called\n"); | |
168 | return 0; | |
169 | } | |
170 | ||
171 | static const struct ieee80211_ops wbsoft_ops = { | |
172 | .tx = wbsoft_tx, | |
173 | .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */ | |
174 | .stop = wbsoft_nop, | |
175 | .add_interface = wbsoft_add_interface, | |
176 | .remove_interface = wbsoft_remove_interface, | |
177 | .config = wbsoft_config, | |
178 | .config_interface = wbsoft_config_interface, | |
179 | .configure_filter = wbsoft_configure_filter, | |
180 | .get_stats = wbsoft_nop, | |
181 | .get_tx_stats = wbsoft_nop, | |
182 | .get_tsf = wbsoft_get_tsf, | |
183 | // conf_tx: hal_set_cwmin()/hal_set_cwmax; | |
184 | }; | |
185 | ||
186 | struct wbsoft_priv { | |
187 | }; | |
188 | ||
189 | ||
190 | int __init wb35_init(void) | |
191 | { | |
192 | printk("[w35und]driver init\n"); | |
193 | return usb_register(&wb35_driver); | |
194 | } | |
195 | ||
196 | void __exit wb35_exit(void) | |
197 | { | |
198 | printk("[w35und]driver exit\n"); | |
199 | usb_deregister( &wb35_driver ); | |
200 | } | |
201 | ||
202 | module_init(wb35_init); | |
203 | module_exit(wb35_exit); | |
204 | ||
205 | // Usb kernel subsystem will call this function when a new device is plugged into. | |
206 | int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) | |
207 | { | |
208 | PADAPTER Adapter; | |
209 | PWBLINUX pWbLinux; | |
210 | PWBUSB pWbUsb; | |
211 | struct usb_host_interface *interface; | |
212 | struct usb_endpoint_descriptor *endpoint; | |
213 | int i, ret = -1; | |
214 | u32 ltmp; | |
215 | struct usb_device *udev = interface_to_usbdev(intf); | |
216 | ||
217 | usb_get_dev(udev); | |
218 | ||
219 | printk("[w35und]wb35_probe ->\n"); | |
220 | ||
dc7e04fe PE |
221 | for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) { |
222 | if ((udev->descriptor.idVendor == Id_Table[i].idVendor) && | |
223 | (udev->descriptor.idProduct == Id_Table[i].idProduct)) { | |
224 | printk("[w35und]Found supported hardware\n"); | |
225 | break; | |
66101de1 | 226 | } |
dc7e04fe | 227 | } |
66101de1 | 228 | |
dc7e04fe PE |
229 | if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) { |
230 | #ifdef _PE_USB_INI_DUMP_ | |
231 | WBDEBUG(("[w35und] This is not the one we are interested about\n")); | |
232 | #endif | |
233 | return -ENODEV; | |
234 | } | |
66101de1 | 235 | |
dc7e04fe PE |
236 | // 20060630.2 Check the device if it already be opened |
237 | ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), | |
238 | 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, | |
239 | 0x0, 0x400, <mp, 4, HZ*100 ); | |
240 | if (ret < 0) | |
241 | goto error; | |
66101de1 | 242 | |
dc7e04fe PE |
243 | ltmp = cpu_to_le32(ltmp); |
244 | if (ltmp) // Is already initialized? | |
245 | goto error; | |
66101de1 | 246 | |
dc7e04fe | 247 | Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL); |
66101de1 | 248 | |
dc7e04fe PE |
249 | my_adapter = Adapter; |
250 | pWbLinux = &Adapter->WbLinux; | |
251 | pWbUsb = &Adapter->sHwData.WbUsb; | |
252 | pWbUsb->udev = udev; | |
66101de1 | 253 | |
dc7e04fe PE |
254 | interface = intf->cur_altsetting; |
255 | endpoint = &interface->endpoint[0].desc; | |
66101de1 | 256 | |
dc7e04fe PE |
257 | if (endpoint[2].wMaxPacketSize == 512) { |
258 | printk("[w35und] Working on USB 2.0\n"); | |
259 | pWbUsb->IsUsb20 = 1; | |
260 | } | |
66101de1 | 261 | |
dc7e04fe PE |
262 | if (!WbWLanInitialize(Adapter)) { |
263 | printk("[w35und]WbWLanInitialize fail\n"); | |
264 | goto error; | |
265 | } | |
66101de1 | 266 | |
dc7e04fe PE |
267 | { |
268 | struct wbsoft_priv *priv; | |
269 | struct ieee80211_hw *dev; | |
270 | int res; | |
66101de1 | 271 | |
dc7e04fe | 272 | dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); |
66101de1 | 273 | |
dc7e04fe PE |
274 | if (!dev) { |
275 | printk("w35und: ieee80211 alloc failed\n" ); | |
276 | BUG(); | |
277 | } | |
66101de1 | 278 | |
dc7e04fe | 279 | my_dev = dev; |
66101de1 | 280 | |
dc7e04fe PE |
281 | SET_IEEE80211_DEV(dev, &udev->dev); |
282 | { | |
283 | phw_data_t pHwData = &Adapter->sHwData; | |
284 | unsigned char dev_addr[MAX_ADDR_LEN]; | |
285 | hal_get_permanent_address(pHwData, dev_addr); | |
286 | SET_IEEE80211_PERM_ADDR(dev, dev_addr); | |
287 | } | |
66101de1 PM |
288 | |
289 | ||
dc7e04fe PE |
290 | dev->extra_tx_headroom = 12; /* FIXME */ |
291 | dev->flags = 0; | |
66101de1 | 292 | |
dc7e04fe PE |
293 | dev->channel_change_time = 1000; |
294 | // dev->max_rssi = 100; | |
66101de1 | 295 | |
dc7e04fe | 296 | dev->queues = 1; |
66101de1 | 297 | |
dc7e04fe | 298 | static struct ieee80211_supported_band band; |
66101de1 | 299 | |
dc7e04fe PE |
300 | band.channels = wbsoft_channels; |
301 | band.n_channels = ARRAY_SIZE(wbsoft_channels); | |
302 | band.bitrates = wbsoft_rates; | |
303 | band.n_bitrates = ARRAY_SIZE(wbsoft_rates); | |
66101de1 | 304 | |
dc7e04fe | 305 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band; |
66101de1 | 306 | #if 0 |
dc7e04fe PE |
307 | wbsoft_modes[0].num_channels = 1; |
308 | wbsoft_modes[0].channels = wbsoft_channels; | |
309 | wbsoft_modes[0].mode = MODE_IEEE80211B; | |
310 | wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates); | |
311 | wbsoft_modes[0].rates = wbsoft_rates; | |
312 | ||
313 | res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]); | |
314 | BUG_ON(res); | |
66101de1 PM |
315 | #endif |
316 | ||
dc7e04fe PE |
317 | res = ieee80211_register_hw(dev); |
318 | BUG_ON(res); | |
319 | } | |
66101de1 | 320 | |
dc7e04fe | 321 | usb_set_intfdata( intf, Adapter ); |
66101de1 | 322 | |
dc7e04fe PE |
323 | printk("[w35und] _probe OK\n"); |
324 | return 0; | |
325 | error: | |
66101de1 PM |
326 | return -ENOMEM; |
327 | } | |
328 | ||
329 | void packet_came(char *pRxBufferAddress, int PacketSize) | |
330 | { | |
331 | struct sk_buff *skb; | |
332 | struct ieee80211_rx_status rx_status = {0}; | |
333 | ||
334 | if (!wbsoft_enabled) | |
335 | return; | |
336 | ||
337 | skb = dev_alloc_skb(PacketSize); | |
338 | if (!skb) { | |
339 | printk("Not enough memory for packet, FIXME\n"); | |
340 | return; | |
341 | } | |
342 | ||
343 | memcpy(skb_put(skb, PacketSize), | |
344 | pRxBufferAddress, | |
345 | PacketSize); | |
346 | ||
347 | /* | |
348 | rx_status.rate = 10; | |
349 | rx_status.channel = 1; | |
350 | rx_status.freq = 12345; | |
351 | rx_status.phymode = MODE_IEEE80211B; | |
352 | */ | |
353 | ||
354 | ieee80211_rx_irqsafe(my_dev, skb, &rx_status); | |
355 | } | |
356 | ||
357 | unsigned char | |
358 | WbUsb_initial(phw_data_t pHwData) | |
359 | { | |
360 | return 1; | |
361 | } | |
362 | ||
363 | ||
364 | void | |
365 | WbUsb_destroy(phw_data_t pHwData) | |
366 | { | |
367 | } | |
368 | ||
369 | int wb35_open(struct net_device *netdev) | |
370 | { | |
371 | PADAPTER Adapter = (PADAPTER)netdev->priv; | |
372 | phw_data_t pHwData = &Adapter->sHwData; | |
373 | ||
374 | netif_start_queue(netdev); | |
375 | ||
376 | //TODO : put here temporarily | |
377 | hal_set_accept_broadcast(pHwData, 1); // open accept broadcast | |
378 | ||
379 | return 0; | |
380 | } | |
381 | ||
382 | int wb35_close(struct net_device *netdev) | |
383 | { | |
384 | netif_stop_queue(netdev); | |
385 | return 0; | |
386 | } | |
387 | ||
388 | void wb35_disconnect(struct usb_interface *intf) | |
389 | { | |
390 | PWBLINUX pWbLinux; | |
391 | PADAPTER Adapter = usb_get_intfdata(intf); | |
392 | usb_set_intfdata(intf, NULL); | |
393 | ||
394 | pWbLinux = &Adapter->WbLinux; | |
395 | ||
396 | // Card remove | |
397 | WbWlanHalt(Adapter); | |
398 | ||
399 | } | |
400 | ||
401 |