Root/
Source at commit a7cf06c0218ec0246ba1fe414500a3798b53d3d1 created 12 years 8 months ago. By Stefan Schmidt, drivers/spi/atusb: Remove ctrl_urb from local struct. | |
---|---|
1 | /* |
2 | * atusb - SPI host look-alike for ATSUB |
3 | * |
4 | * Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com> |
5 | * Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org> |
6 | * |
7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License as |
9 | * published by the Free Software Foundation, version 2 |
10 | * |
11 | */ |
12 | |
13 | /* |
14 | * - Implement buffer and sram read write |
15 | * - Implement IRQ handling |
16 | */ |
17 | |
18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/usb.h> |
23 | #include <linux/spi/spi.h> |
24 | #include <linux/spi/at86rf230.h> |
25 | |
26 | #include "../ieee802154/at86rf230.h" /* dirty */ |
27 | |
28 | #define VENDOR_ID 0x20b7 |
29 | #define PRODUCT_ID 0x1540 |
30 | |
31 | /* The devices we work with */ |
32 | static const struct usb_device_id atusb_device_table[] = { |
33 | { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, |
34 | { }, |
35 | }; |
36 | MODULE_DEVICE_TABLE(usb, atusb_device_table); |
37 | |
38 | #define ATUSB_BUILD_SIZE 256 |
39 | struct atusb_local { |
40 | struct usb_device * udev; |
41 | /* The interface to the RF part info, if applicable */ |
42 | uint8_t ep0_atusb_major; |
43 | uint8_t ep0_atusb_minor; |
44 | uint8_t atusb_hw_type; |
45 | unsigned char *atusb_build; |
46 | struct spi_master *master; |
47 | int slave_irq; |
48 | int usb_irq; |
49 | struct at86rf230_platform_data platform_data; |
50 | /* copy platform_data so that we can adapt .reset_data */ |
51 | struct spi_device *spi; |
52 | size_t bulk_in_filled; /* number of bytes in the buffer */ |
53 | struct completion urb_completion; |
54 | // unsigned char buffer[3]; |
55 | unsigned char buffer[260]; /* XXL, just in case */ |
56 | struct spi_message *msg; |
57 | }; |
58 | |
59 | /* Commands to our device. Make sure this is synced with the firmware */ |
60 | enum atspi_requests { |
61 | ATUSB_ID = 0x00, /* system status/control grp */ |
62 | ATUSB_BUILD, |
63 | ATUSB_RESET, |
64 | ATUSB_RF_RESET = 0x10, /* debug/test group */ |
65 | ATUSB_POLL_INT, |
66 | ATUSB_TEST, /* atusb-sil only */ |
67 | ATUSB_TIMER, |
68 | ATUSB_GPIO, |
69 | ATUSB_SLP_TR, |
70 | ATUSB_GPIO_CLEANUP, |
71 | ATUSB_REG_WRITE = 0x20, /* transceiver group */ |
72 | ATUSB_REG_READ, |
73 | ATUSB_BUF_WRITE, |
74 | ATUSB_BUF_READ, |
75 | ATUSB_SRAM_WRITE, |
76 | ATUSB_SRAM_READ, |
77 | ATUSB_SPI_WRITE = 0x30, /* SPI group */ |
78 | ATUSB_SPI_READ1, |
79 | ATUSB_SPI_READ2, |
80 | }; |
81 | |
82 | /* |
83 | * Direction bRequest wValue wIndex wLength |
84 | * |
85 | * ->host ATUSB_ID - - 3 |
86 | * ->host ATUSB_BUILD - - #bytes |
87 | * host-> ATUSB_RESET - - 0 |
88 | * |
89 | * host-> ATUSB_RF_RESET - - 0 |
90 | * ->host ATUSB_POLL_INT - - 1 |
91 | * host-> ATUSB_TEST - - 0 |
92 | * ->host ATUSB_TIMER - - #bytes (6) |
93 | * ->host ATUSB_GPIO dir+data mask+p# 3 |
94 | * host-> ATUSB_SLP_TR - - 0 |
95 | * host-> ATUSB_GPIO_CLEANUP - - 0 |
96 | * |
97 | * host-> ATUSB_REG_WRITE value addr 0 |
98 | * ->host ATUSB_REG_READ - addr 1 |
99 | * host-> ATUSB_BUF_WRITE - - #bytes |
100 | * ->host ATUSB_BUF_READ - - #bytes |
101 | * host-> ATUSB_SRAM_WRITE - addr #bytes |
102 | * ->host ATUSB_SRAM_READ - addr #bytes |
103 | * |
104 | * host-> ATUSB_SPI_WRITE byte0 byte1 #bytes |
105 | * ->host ATUSB_SPI_READ1 byte0 - #bytes |
106 | * ->host ATUSB_SPI_READ2 byte0 byte1 #bytes |
107 | */ |
108 | |
109 | #define ATUSB_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN) |
110 | #define ATUSB_TO_DEV (USB_TYPE_VENDOR | USB_DIR_OUT) |
111 | |
112 | static void atusb_read1_cb(struct urb *urb) |
113 | { |
114 | struct atusb_local *atusb = urb->context; |
115 | struct spi_message *msg = atusb->msg; |
116 | |
117 | if (urb->status) { |
118 | if (!(urb->status == -ENOENT || |
119 | urb->status == -ECONNRESET || |
120 | urb->status == -ESHUTDOWN)) |
121 | printk("Async USB failed with error %i\n", urb->status); |
122 | msg->actual_length = 0; |
123 | } else { |
124 | printk("Async USB succeeded with length %i\n", urb->actual_length); |
125 | } |
126 | |
127 | msg->status = urb->status; |
128 | msg->complete(msg->context); |
129 | |
130 | kfree(urb->setup_packet); |
131 | usb_free_urb(urb); |
132 | } |
133 | |
134 | static void atusb_read_fb_cb(struct urb *urb) |
135 | { |
136 | struct atusb_local *atusb = urb->context; |
137 | struct spi_message *msg = atusb->msg; |
138 | const struct spi_transfer *xfer; |
139 | uint8_t *rx; |
140 | |
141 | if (urb->status) { |
142 | if (!(urb->status == -ENOENT || |
143 | urb->status == -ECONNRESET || |
144 | urb->status == -ESHUTDOWN)) |
145 | printk("Async USB failed with error %i\n", urb->status); |
146 | msg->actual_length = 0; |
147 | } else { |
148 | printk("Async USB succeeded with length %i\n", urb->actual_length); |
149 | BUG_ON(!urb->actual_length); |
150 | xfer = list_first_entry(&msg->transfers, struct spi_transfer, |
151 | transfer_list); |
152 | rx = xfer->rx_buf; |
153 | rx[1] = atusb->buffer[0]; |
154 | xfer = list_entry(xfer->transfer_list.next, |
155 | struct spi_transfer, transfer_list); |
156 | memcpy(xfer->rx_buf, atusb->buffer+1, urb->actual_length-1); |
157 | } |
158 | |
159 | msg->status = urb->status; |
160 | msg->complete(msg->context); |
161 | |
162 | kfree(urb->setup_packet); |
163 | usb_free_urb(urb); |
164 | } |
165 | |
166 | static int atusb_get_static_info(struct atusb_local *atusb) |
167 | { |
168 | int retval; |
169 | |
170 | atusb->atusb_build = kzalloc(ATUSB_BUILD_SIZE+1, GFP_KERNEL); |
171 | if (!atusb->atusb_build) { |
172 | dev_err(&atusb->udev->dev, "out of memory\n"); |
173 | retval = -ENOMEM; |
174 | } |
175 | |
176 | /* Get a couple of the ATMega Firmware values */ |
177 | retval = usb_control_msg(atusb->udev, |
178 | usb_rcvctrlpipe(atusb->udev, 0), |
179 | ATUSB_ID, ATUSB_FROM_DEV, 0, 0, |
180 | atusb->buffer, 3, 1000); |
181 | if (retval < 0) { |
182 | dev_info(&atusb->udev->dev, "failed submitting read urb, error %d", |
183 | retval); |
184 | retval = (retval == -ENOMEM) ? retval : -EIO; |
185 | } |
186 | |
187 | retval = usb_control_msg(atusb->udev, |
188 | usb_rcvctrlpipe(atusb->udev, 0), |
189 | ATUSB_BUILD, ATUSB_FROM_DEV, 0, 0, |
190 | atusb->atusb_build, ATUSB_BUILD_SIZE+1, 1000); |
191 | if (retval < 0) { |
192 | dev_info(&atusb->udev->dev, "failed submitting read urb, error %d", |
193 | retval); |
194 | retval = (retval == -ENOMEM) ? retval : -EIO; |
195 | } |
196 | |
197 | return retval; |
198 | } |
199 | |
200 | static void atusb_reset(void *reset_data) |
201 | { |
202 | int retval; |
203 | struct atusb_local *atusb = reset_data; |
204 | |
205 | retval = usb_control_msg(atusb->udev, |
206 | usb_rcvctrlpipe(atusb->udev, 0), |
207 | ATUSB_RF_RESET, ATUSB_TO_DEV, 0, 0, |
208 | NULL, 0, 1000); |
209 | if (retval < 0) { |
210 | dev_info(&atusb->udev->dev, |
211 | "%s: error doing reset retval = %d\n", |
212 | __func__, retval); |
213 | } |
214 | } |
215 | |
216 | static int submit_control_msg(struct atusb_local *atusb, |
217 | __u8 request, __u8 requesttype, __u16 value, __u16 index, |
218 | void *data, __u16 size, usb_complete_t complete_fn, void *context) |
219 | { |
220 | struct usb_device *dev = atusb->udev; |
221 | struct usb_ctrlrequest *req; |
222 | struct urb *ctrl_urb; |
223 | int retval = -ENOMEM; |
224 | |
225 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); |
226 | if (!req) |
227 | return -ENOMEM; |
228 | |
229 | req->bRequest = request; |
230 | req->bRequestType = requesttype; |
231 | req->wValue = cpu_to_le16(value); |
232 | req->wIndex = cpu_to_le16(index); |
233 | req->wLength = cpu_to_le16(size); |
234 | |
235 | ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); |
236 | if (!ctrl_urb) |
237 | goto out_nourb; |
238 | |
239 | usb_fill_control_urb(ctrl_urb, dev, |
240 | requesttype == ATUSB_FROM_DEV ? |
241 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0), |
242 | (unsigned char *) req, data, size, complete_fn, context); |
243 | |
244 | retval = usb_submit_urb(ctrl_urb, GFP_KERNEL); |
245 | if (!retval) |
246 | return 0; |
247 | dev_info(&dev->dev, "failed submitting read urb, error %d", |
248 | retval); |
249 | retval = retval == -ENOMEM ? retval : -EIO; |
250 | |
251 | usb_free_urb(ctrl_urb); |
252 | out_nourb: |
253 | kfree(req); |
254 | |
255 | return retval; |
256 | } |
257 | |
258 | |
259 | static int atusb_read1(struct atusb_local *atusb, |
260 | uint8_t tx, uint8_t *rx, int len) |
261 | { |
262 | dev_info(&atusb->udev->dev, "atusb_read1: tx = 0x%x\n", tx); |
263 | return submit_control_msg(atusb, |
264 | ATUSB_SPI_READ1, ATUSB_FROM_DEV, tx, 0, |
265 | rx, 1, atusb_read1_cb, atusb); |
266 | } |
267 | |
268 | static int atusb_read_fb(struct atusb_local *atusb, |
269 | uint8_t tx, uint8_t *rx0, uint8_t *rx, int len) |
270 | { |
271 | dev_info(&atusb->udev->dev, "atusb_read_fb: tx = 0x%x\n", tx); |
272 | return submit_control_msg(atusb, |
273 | ATUSB_SPI_READ1, ATUSB_FROM_DEV, tx, 0, |
274 | atusb->buffer, len+1, atusb_read_fb_cb, atusb); |
275 | } |
276 | |
277 | static void atusb_read2(struct atusb_local *atusb, uint8_t *buf, int len) |
278 | { |
279 | /* ->host ATUSB_SPI_READ2 byte0 byte1 #bytes */ |
280 | } |
281 | |
282 | static int atusb_write(struct atusb_local *atusb, |
283 | uint8_t tx0, uint8_t tx1, const uint8_t *tx, int len) |
284 | { |
285 | dev_info(&atusb->udev->dev, "atusb_write: tx[0] = 0x%x\n", tx0); |
286 | dev_info(&atusb->udev->dev, "atusb_write: tx[1] = 0x%x\n", tx1); |
287 | return submit_control_msg(atusb, |
288 | ATUSB_SPI_WRITE, ATUSB_TO_DEV, tx0, tx1, |
289 | (uint8_t *) tx, len, atusb_read1_cb, atusb); |
290 | } |
291 | |
292 | static int atusb_transfer(struct spi_device *spi, struct spi_message *msg) |
293 | { |
294 | struct atusb_local *atusb = spi_master_get_devdata(spi->master); |
295 | struct spi_transfer *xfer; |
296 | struct spi_transfer *x[2]; |
297 | int n; |
298 | const uint8_t *tx; |
299 | uint8_t *rx; |
300 | int len; |
301 | int retval = 0; |
302 | |
303 | if (unlikely(list_empty(&msg->transfers))) { |
304 | dev_err(&atusb->udev->dev, "transfer is empty\n"); |
305 | return -EINVAL; |
306 | } |
307 | |
308 | atusb->msg = msg; |
309 | |
310 | /* Classify the request */ |
311 | n = 0; |
312 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { |
313 | if (n == ARRAY_SIZE(x)) { |
314 | dev_info(&atusb->udev->dev, "too many transfers\n"); |
315 | return -EINVAL; |
316 | } |
317 | x[n] = xfer; |
318 | n++; |
319 | } |
320 | |
321 | tx = x[0]->tx_buf; |
322 | rx = x[0]->rx_buf; |
323 | len = x[0]->len; |
324 | |
325 | msg->actual_length = len; |
326 | |
327 | if (!tx || len != 2) |
328 | goto bad_req; |
329 | if (n == 1) { |
330 | if (rx) { |
331 | dev_info(&atusb->udev->dev, "read 1\n"); |
332 | retval = atusb_read1(atusb, tx[0], rx+1, len-1); |
333 | } else { |
334 | dev_info(&atusb->udev->dev, "write 2\n"); |
335 | /* |
336 | * Don't take our clock away !! ;-) |
337 | */ |
338 | if (tx[0] == (CMD_REG | CMD_WRITE | RG_TRX_CTRL_0)) { |
339 | msg->status = 0; |
340 | msg->complete(msg->context); |
341 | } else { |
342 | retval = atusb_write(atusb, |
343 | tx[0], tx[1], NULL, 0); |
344 | } |
345 | } |
346 | } else { |
347 | if (x[0]->rx_buf) { |
348 | if (x[1]->tx_buf || !x[1]->rx_buf) |
349 | goto bad_req; |
350 | dev_info(&atusb->udev->dev, "read 1+\n"); |
351 | retval = atusb_read_fb(atusb, tx[0], rx+1, |
352 | x[1]->rx_buf, x[1]->len); |
353 | } else { |
354 | if (!x[1]->tx_buf ||x[1]->rx_buf) |
355 | goto bad_req; |
356 | dev_info(&atusb->udev->dev, "write 2+n\n"); |
357 | retval = atusb_write(atusb, tx[0], tx[1], |
358 | x[1]->tx_buf, x[1]->len); |
359 | } |
360 | } |
361 | #if 0 |
362 | /* |
363 | * The AT86RF230 driver sometimes requires a transceiver state |
364 | * transition to be an interrupt barrier. This is the case after |
365 | * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register. |
366 | * |
367 | * Since there is no other means of notification, we just decode the |
368 | * transfer and do a bit of pattern matching. |
369 | */ |
370 | xfer = list_first_entry(&msg->transfers, struct spi_transfer, |
371 | transfer_list); |
372 | tx = xfer->tx_buf; |
373 | if (tx && xfer->len == 2 && |
374 | tx[0] == (CMD_REG | CMD_WRITE | RG_TRX_STATE) && |
375 | (tx[1] & 0x1f) == STATE_FORCE_TX_ON) |
376 | synchronize_irq(atusb->gpio_irq); |
377 | #endif |
378 | return retval; |
379 | |
380 | bad_req: |
381 | dev_info(&atusb->udev->dev, "unrecognized request:\n"); |
382 | list_for_each_entry(xfer, &msg->transfers, transfer_list) |
383 | dev_info(&atusb->udev->dev, "%stx %srx len %u\n", |
384 | xfer->tx_buf ? "" : "!", xfer->rx_buf ? " " : "!", |
385 | xfer->len); |
386 | return -EINVAL; |
387 | } |
388 | |
389 | static int atusb_setup(struct spi_device *spi) |
390 | { |
391 | return 0; |
392 | } |
393 | #if 0 |
394 | static irqreturn_t atusb_irq(int irq, void *data) |
395 | { |
396 | struct atusb_local *atusb = data; |
397 | |
398 | generic_handle_irq(atusb->slave_irq); |
399 | return IRQ_HANDLED; |
400 | } |
401 | #endif |
402 | static void atusb_irq_mask(struct irq_data *data) |
403 | { |
404 | // struct atben_local *atusb = irq_data_get_irq_chip_data(data); |
405 | |
406 | // disable_irq_nosync(atusb->usb_irq); |
407 | } |
408 | |
409 | static void atusb_irq_unmask(struct irq_data *data) |
410 | { |
411 | // struct atben_local *atusb = irq_data_get_irq_chip_data(data); |
412 | |
413 | // enable_irq(atusb->usb_irq); |
414 | } |
415 | |
416 | static struct irq_chip atusb_irq_chip = { |
417 | .name = "atusb-slave", |
418 | .irq_mask = atusb_irq_mask, |
419 | .irq_unmask = atusb_irq_unmask, |
420 | }; |
421 | |
422 | struct at86rf230_platform_data at86rf230_platform_data = { |
423 | .rstn = -1, |
424 | .slp_tr = -1, |
425 | .dig2 = -1, |
426 | .reset = atusb_reset, |
427 | /* set .reset_data later */ |
428 | }; |
429 | |
430 | static int atusb_probe(struct usb_interface *interface, |
431 | const struct usb_device_id *id) |
432 | { |
433 | struct spi_board_info board_info = { |
434 | .modalias = "at86rf230", |
435 | /* set .irq later */ |
436 | .chip_select = 0, |
437 | .bus_num = -1, |
438 | .max_speed_hz = 8 * 1000 * 1000, |
439 | }; |
440 | |
441 | struct usb_device *udev = interface_to_usbdev(interface); |
442 | struct atusb_local *atusb = NULL; |
443 | struct spi_master *master; |
444 | int retval; |
445 | |
446 | /* |
447 | * Ignore all interfaces used for DFU, i.e., everything while in the |
448 | * boot loader, and interface #1 when in the application. |
449 | */ |
450 | if (interface->cur_altsetting->desc.bInterfaceClass != |
451 | USB_CLASS_VENDOR_SPEC) { |
452 | dev_info(&udev->dev, |
453 | "Ignoring interface with class 0x%02x\n", |
454 | interface->cur_altsetting->desc.bInterfaceClass); |
455 | return -ENODEV; |
456 | } |
457 | |
458 | master = spi_alloc_master(&udev->dev, sizeof(*atusb)); |
459 | if (!master) |
460 | return -ENOMEM; |
461 | |
462 | atusb = spi_master_get_devdata(master); |
463 | |
464 | init_completion(&atusb->urb_completion); |
465 | |
466 | atusb->udev = usb_get_dev(udev); |
467 | usb_set_intfdata(interface, atusb); |
468 | |
469 | atusb->master = spi_master_get(master); |
470 | |
471 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
472 | master->bus_num = -1; |
473 | master->num_chipselect = 1; |
474 | master->setup = atusb_setup; |
475 | master->transfer = atusb_transfer; |
476 | |
477 | atusb->slave_irq = irq_alloc_desc(numa_node_id()); |
478 | if (atusb->slave_irq < 0) { |
479 | dev_info(&udev->dev, "can't allocate slave irq\n"); |
480 | retval = -ENXIO; |
481 | goto err_free; |
482 | } |
483 | |
484 | set_irq_chip_data(atusb->slave_irq, atusb); |
485 | set_irq_chip_and_handler(atusb->slave_irq, &atusb_irq_chip, |
486 | handle_level_irq); |
487 | |
488 | /* FIXME prepare USB IRQ */ |
489 | |
490 | retval = spi_register_master(master); |
491 | if (retval < 0) { |
492 | dev_info(&udev->dev, "can't register spi master\n"); |
493 | goto err_slave_irq; |
494 | } |
495 | |
496 | atusb->platform_data = at86rf230_platform_data; |
497 | atusb->platform_data.reset_data = atusb; |
498 | board_info.platform_data = &atusb->platform_data; |
499 | board_info.irq = atusb->slave_irq; |
500 | |
501 | atusb->spi = spi_new_device(master, &board_info); |
502 | if (!atusb->spi) { |
503 | dev_info(&udev->dev, "can't create new device for %s\n", |
504 | board_info.modalias); |
505 | goto err_master; |
506 | } |
507 | |
508 | dev_info(&atusb->spi->dev, "ATUSB ready for mischief (IRQ %d)\n", board_info.irq); |
509 | |
510 | /* Get the static info from the device and save it */ |
511 | retval = atusb_get_static_info(atusb); |
512 | if (retval < 0) { |
513 | dev_info(&interface->dev, "%s: Failed to get static info: %d\n", |
514 | __func__, |
515 | retval); |
516 | goto err_master; |
517 | } |
518 | |
519 | dev_info(&udev->dev, "Firmware: build %s\n", atusb->atusb_build); |
520 | atusb->ep0_atusb_major = atusb->buffer[0]; |
521 | atusb->ep0_atusb_minor = atusb->buffer[1]; |
522 | atusb->atusb_hw_type = atusb->buffer[2]; |
523 | dev_info(&udev->dev, "Firmware: major: %u, minor: %u, hardware type: %u\n", |
524 | atusb->ep0_atusb_major, atusb->ep0_atusb_minor, atusb->atusb_hw_type); |
525 | |
526 | return 0; |
527 | |
528 | err_master: |
529 | spi_master_put(atusb->master); |
530 | err_slave_irq: |
531 | set_irq_chained_handler(atusb->slave_irq, NULL); |
532 | set_irq_chip_data(atusb->slave_irq, NULL); |
533 | irq_free_desc(atusb->slave_irq); |
534 | err_free: |
535 | return retval; |
536 | } |
537 | |
538 | static void atusb_disconnect(struct usb_interface *interface) |
539 | { |
540 | struct atusb_local *atusb = usb_get_intfdata(interface); |
541 | struct spi_master *master = atusb->master; |
542 | |
543 | kfree(atusb->atusb_build); |
544 | |
545 | usb_set_intfdata(interface, NULL); |
546 | usb_put_dev(atusb->udev); |
547 | |
548 | spi_dev_put(atusb->spi); |
549 | |
550 | spi_unregister_master(master); |
551 | |
552 | set_irq_chained_handler(atusb->slave_irq, NULL); |
553 | set_irq_chip_data(atusb->slave_irq, NULL); |
554 | irq_free_desc(atusb->slave_irq); |
555 | |
556 | spi_master_put(master); |
557 | } |
558 | |
559 | void atusb_release(struct device *dev) |
560 | { |
561 | return; |
562 | } |
563 | |
564 | static struct usb_driver atusb_driver = { |
565 | .name = "atusb_ben-wpan", |
566 | .probe = atusb_probe, |
567 | .disconnect = atusb_disconnect, |
568 | .id_table = atusb_device_table, |
569 | }; |
570 | |
571 | static struct platform_device atusb_device = { |
572 | .name = "spi_atusb", |
573 | .id = -1, |
574 | .dev.release = atusb_release, |
575 | }; |
576 | |
577 | static int __init atusb_init(void) |
578 | { |
579 | int retval; |
580 | |
581 | retval = platform_device_register(&atusb_device); |
582 | if (retval) |
583 | return retval; |
584 | |
585 | return usb_register(&atusb_driver); |
586 | } |
587 | |
588 | static void __exit atusb_exit(void) |
589 | { |
590 | usb_deregister(&atusb_driver); |
591 | platform_device_unregister(&atusb_device); |
592 | } |
593 | |
594 | module_init (atusb_init); |
595 | module_exit (atusb_exit); |
596 | |
597 | MODULE_AUTHOR("Richard Sharpe <realrichardsharpe@gmail.com>, Stefan Schmidt \ |
598 | <stefan@datenfreihafen.org>"); |
599 | MODULE_DESCRIPTION( "ATUSB ben-wpan Driver"); |
600 | MODULE_LICENSE("GPL"); |
601 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9