blob: c5eca46996fb591dfd0fae63f8a5872355f7f81f [file] [log] [blame]
Sebastian Haase0ce8a72009-05-14 20:46:12 -07001/*
2 * CPC-USB CAN Interface Kernel Driver
3 *
4 * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/slab.h>
23#include <linux/vmalloc.h>
24#include <linux/module.h>
25#include <linux/poll.h>
26#include <linux/smp_lock.h>
27#include <linux/completion.h>
28#include <asm/uaccess.h>
29#include <linux/usb.h>
30
Sebastian Haase0ce8a72009-05-14 20:46:12 -070031
Alexander Beregalovc32a4e02009-05-21 15:44:45 +040032#include <linux/proc_fs.h>
Sebastian Haase0ce8a72009-05-14 20:46:12 -070033
34#include "cpc.h"
35
36#include "cpc_int.h"
37#include "cpcusb.h"
38
39#include "sja2m16c.h"
40
41/* Version Information */
42#define DRIVER_AUTHOR "Sebastian Haas <haas@ems-wuensche.com>"
43#define DRIVER_DESC "CPC-USB Driver for Linux Kernel 2.6"
Greg Kroah-Hartman84a209d2009-05-14 20:56:58 -070044#define DRIVER_VERSION CPC_DRIVER_VERSION
Sebastian Haase0ce8a72009-05-14 20:46:12 -070045
46MODULE_AUTHOR(DRIVER_AUTHOR);
47MODULE_DESCRIPTION(DRIVER_DESC);
48MODULE_VERSION(DRIVER_VERSION);
49MODULE_LICENSE("GPL v2");
50
51/* Define these values to match your devices */
52#define USB_CPCUSB_VENDOR_ID 0x12D6
53
54#define USB_CPCUSB_M16C_PRODUCT_ID 0x0888
55#define USB_CPCUSB_LPC2119_PRODUCT_ID 0x0444
56
Sebastian Haase0ce8a72009-05-14 20:46:12 -070057#define CPC_USB_PROC_DIR CPC_PROC_DIR "cpc-usb"
58
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -070059static struct proc_dir_entry *procDir;
60static struct proc_dir_entry *procEntry;
Sebastian Haase0ce8a72009-05-14 20:46:12 -070061
62/* Module parameters */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -070063static int debug;
Sebastian Haase0ce8a72009-05-14 20:46:12 -070064module_param(debug, int, S_IRUGO);
65
66/* table of devices that work with this driver */
67static struct usb_device_id cpcusb_table[] = {
68 {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_M16C_PRODUCT_ID)},
69 {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_LPC2119_PRODUCT_ID)},
70 {} /* Terminating entry */
71};
72
73MODULE_DEVICE_TABLE(usb, cpcusb_table);
74
75/* use to prevent kernel panic if driver is unloaded
76 * while a programm has still open the device
77 */
78DECLARE_WAIT_QUEUE_HEAD(rmmodWq);
79atomic_t useCount;
80
81static CPC_USB_T *CPCUSB_Table[CPC_USB_CARD_CNT] = { 0 };
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -070082static unsigned int CPCUsbCnt;
Sebastian Haase0ce8a72009-05-14 20:46:12 -070083
84/* prevent races between open() and disconnect() */
85static DECLARE_MUTEX(disconnect_sem);
86
87/* local function prototypes */
88static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -070089 loff_t *ppos);
Sebastian Haase0ce8a72009-05-14 20:46:12 -070090static ssize_t cpcusb_write(struct file *file, const char *buffer,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -070091 size_t count, loff_t *ppos);
Sebastian Haase0ce8a72009-05-14 20:46:12 -070092static unsigned int cpcusb_poll(struct file *file, poll_table * wait);
93static int cpcusb_open(struct inode *inode, struct file *file);
94static int cpcusb_release(struct inode *inode, struct file *file);
95
96static int cpcusb_probe(struct usb_interface *interface,
97 const struct usb_device_id *id);
98static void cpcusb_disconnect(struct usb_interface *interface);
99
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700100static void cpcusb_read_bulk_callback(struct urb *urb);
101static void cpcusb_write_bulk_callback(struct urb *urb);
102static void cpcusb_read_interrupt_callback(struct urb *urb);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700103
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700104static int cpcusb_setup_intrep(CPC_USB_T *card);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700105
106static struct file_operations cpcusb_fops = {
107 /*
108 * The owner field is part of the module-locking
109 * mechanism. The idea is that the kernel knows
110 * which module to increment the use-counter of
111 * BEFORE it calls the device's open() function.
112 * This also means that the kernel can decrement
113 * the use-counter again before calling release()
114 * or should the open() function fail.
115 */
116 .owner = THIS_MODULE,
117
118 .read = cpcusb_read,
119 .write = cpcusb_write,
120 .poll = cpcusb_poll,
121 .open = cpcusb_open,
122 .release = cpcusb_release,
123};
124
125/*
126 * usb class driver info in order to get a minor number from the usb core,
127 * and to have the device registered with devfs and the driver core
128 */
129static struct usb_class_driver cpcusb_class = {
130 .name = "usb/cpc_usb%d",
131 .fops = &cpcusb_fops,
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700132 .minor_base = CPC_USB_BASE_MNR,
133};
134
135/* usb specific object needed to register this driver with the usb subsystem */
136static struct usb_driver cpcusb_driver = {
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700137 .name = "cpc-usb",
138 .probe = cpcusb_probe,
139 .disconnect = cpcusb_disconnect,
140 .id_table = cpcusb_table,
141};
142
143static int cpcusb_create_info_output(char *buf)
144{
145 int i = 0, j;
146
147 for (j = 0; j < CPC_USB_CARD_CNT; j++) {
148 if (CPCUSB_Table[j]) {
149 CPC_USB_T *card = CPCUSB_Table[j];
150 CPC_CHAN_T *chan = card->chan;
151
152 /* MINOR CHANNELNO BUSNO SLOTNO */
153 i += sprintf(&buf[i], "%d %s\n", chan->minor,
154 card->serialNumber);
155 }
156 }
157
158 return i;
159}
160
161static int cpcusb_proc_read_info(char *page, char **start, off_t off,
162 int count, int *eof, void *data)
163{
164 int len = cpcusb_create_info_output(page);
165
166 if (len <= off + count)
167 *eof = 1;
168 *start = page + off;
169 len -= off;
170 if (len > count)
171 len = count;
172 if (len < 0)
173 len = 0;
174
175 return len;
176}
177
178/*
179 * Remove CPC-USB and cleanup
180 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700181static inline void cpcusb_delete(CPC_USB_T *card)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700182{
183 if (card) {
184 if (card->chan) {
185 if (card->chan->buf)
186 vfree(card->chan->buf);
187
188 if (card->chan->CPCWait_q)
189 kfree(card->chan->CPCWait_q);
190
191 kfree(card->chan);
192 }
193
194 CPCUSB_Table[card->idx] = NULL;
195 kfree(card);
196 }
197}
198
199/*
200 * setup the interrupt IN endpoint of a specific CPC-USB device
201 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700202static int cpcusb_setup_intrep(CPC_USB_T *card)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700203{
204 int retval = 0;
205 struct usb_endpoint_descriptor *ep;
206
207 ep = &card->interface->altsetting[0].endpoint[card->num_intr_in].desc;
208
209 card->intr_in_buffer[0] = 0;
210 card->free_slots = 15; /* initial size */
211
212 /* setup the urb */
213 usb_fill_int_urb(card->intr_in_urb, card->udev,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700214 usb_rcvintpipe(card->udev, card->num_intr_in),
215 card->intr_in_buffer,
216 sizeof(card->intr_in_buffer),
217 cpcusb_read_interrupt_callback,
218 card,
219 ep->bInterval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700220
221 card->intr_in_urb->status = 0; /* needed! */
222
223 /* submit the urb */
224 retval = usb_submit_urb(card->intr_in_urb, GFP_KERNEL);
225
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700226 if (retval)
227 err("%s - failed submitting intr urb, error %d", __func__,
228 retval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700229
230 return retval;
231}
232
233static int cpcusb_open(struct inode *inode, struct file *file)
234{
235 CPC_USB_T *card = NULL;
236 struct usb_interface *interface;
237 int subminor;
238 int j, retval = 0;
239
240 subminor = iminor(inode);
241
242 /* prevent disconnects */
243 down(&disconnect_sem);
244
245 interface = usb_find_interface(&cpcusb_driver, subminor);
246 if (!interface) {
247 err("%s - error, can't find device for minor %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700248 __func__, subminor);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700249 retval = CPC_ERR_NO_INTERFACE_PRESENT;
250 goto exit_no_device;
251 }
252
253 card = usb_get_intfdata(interface);
254 if (!card) {
255 retval = CPC_ERR_NO_INTERFACE_PRESENT;
256 goto exit_no_device;
257 }
258
259 /* lock this device */
260 down(&card->sem);
261
262 /* increment our usage count for the driver */
263 if (card->open) {
264 dbg("device already opened");
265 retval = CPC_ERR_CHANNEL_ALREADY_OPEN;
266 goto exit_on_error;
267 }
268
269 /* save our object in the file's private structure */
270 file->private_data = card;
271 for (j = 0; j < CPC_USB_URB_CNT; j++) {
272 usb_fill_bulk_urb(card->urbs[j].urb, card->udev,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700273 usb_rcvbulkpipe(card->udev, card->num_bulk_in),
274 card->urbs[j].buffer, card->urbs[j].size,
275 cpcusb_read_bulk_callback, card);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700276
277 retval = usb_submit_urb(card->urbs[j].urb, GFP_KERNEL);
278
279 if (retval) {
280 err("%s - failed submitting read urb, error %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700281 __func__, retval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700282 retval = CPC_ERR_TRANSMISSION_FAILED;
283 goto exit_on_error;
284 }
285 }
286
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700287 info("%s - %d URB's submitted", __func__, j);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700288
289 ResetBuffer(card->chan);
290
291 cpcusb_setup_intrep(card);
292 card->open = 1;
293
294 atomic_inc(&useCount);
295
296exit_on_error:
297 /* unlock this device */
298 up(&card->sem);
299
300exit_no_device:
301 up(&disconnect_sem);
302
303 return retval;
304}
305
306static unsigned int cpcusb_poll(struct file *file, poll_table * wait)
307{
308 CPC_USB_T *card = (CPC_USB_T *) file->private_data;
309 unsigned int retval = 0;
310
311 if (!card) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700312 err("%s - device object lost", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700313 return -EIO;
314 }
315
316 poll_wait(file, card->chan->CPCWait_q, wait);
317
318 if (IsBufferNotEmpty(card->chan) || !(card->present))
319 retval |= (POLLIN | POLLRDNORM);
320
321 if (card->free_slots)
322 retval |= (POLLOUT | POLLWRNORM);
323
324 return retval;
325}
326
327static int cpcusb_release(struct inode *inode, struct file *file)
328{
329 CPC_USB_T *card = (CPC_USB_T *) file->private_data;
330 int j, retval = 0;
331
332 if (card == NULL) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700333 dbg("%s - object is NULL", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700334 return CPC_ERR_NO_INTERFACE_PRESENT;
335 }
336
337 /* lock our device */
338 down(&card->sem);
339
340 if (!card->open) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700341 dbg("%s - device not opened", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700342 retval = CPC_ERR_NO_INTERFACE_PRESENT;
343 goto exit_not_opened;
344 }
345
346 /* if device wasn't unplugged kill all urbs */
347 if (card->present) {
348 /* kill read urbs */
349 for (j = 0; j < CPC_USB_URB_CNT; j++) {
350 usb_kill_urb(card->urbs[j].urb);
351 }
352
353 /* kill irq urb */
354 usb_kill_urb(card->intr_in_urb);
355
356 /* kill write urbs */
357 for (j = 0; j < CPC_USB_URB_CNT; j++) {
358 if (atomic_read(&card->wrUrbs[j].busy)) {
359 usb_kill_urb(card->wrUrbs[j].urb);
360 wait_for_completion(&card->wrUrbs[j].finished);
361 }
362 }
363 }
364
365 atomic_dec(&useCount);
366
367 /* last process detached */
368 if (atomic_read(&useCount) == 0) {
369 wake_up(&rmmodWq);
370 }
371
372 if (!card->present && card->open) {
373 /* the device was unplugged before the file was released */
374 up(&card->sem);
375 cpcusb_delete(card);
376 return 0;
377 }
378
379 card->open = 0;
380
381exit_not_opened:
382 up(&card->sem);
383
384 return 0;
385}
386
387static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700388 loff_t *ppos)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700389{
390 CPC_USB_T *card = (CPC_USB_T *) file->private_data;
391 CPC_CHAN_T *chan;
392 int retval = 0;
393
394 if (count < sizeof(CPC_MSG_T))
395 return CPC_ERR_UNKNOWN;
396
397 /* check if can read from the given address */
398 if (!access_ok(VERIFY_WRITE, buffer, count))
399 return CPC_ERR_UNKNOWN;
400
401 /* lock this object */
402 down(&card->sem);
403
404 /* verify that the device wasn't unplugged */
405 if (!card->present) {
406 up(&card->sem);
407 return CPC_ERR_NO_INTERFACE_PRESENT;
408 }
409
410 if (IsBufferEmpty(card->chan)) {
411 retval = 0;
412 } else {
413 chan = card->chan;
414
415#if 0
416 /* convert LPC2119 params back to SJA1000 params */
417 if (card->deviceRevision >= 0x0200
418 && chan->buf[chan->oidx].type == CPC_MSG_T_CAN_PRMS) {
419 LPC2119_TO_SJA1000_Params(&chan->buf[chan->oidx]);
420 }
421#endif
422
423 if (copy_to_user(buffer, &chan->buf[chan->oidx], count) != 0) {
424 retval = CPC_ERR_IO_TRANSFER;
425 } else {
426 chan->oidx = (chan->oidx + 1) % CPC_MSG_BUF_CNT;
427 chan->WnR = 1;
428 retval = sizeof(CPC_MSG_T);
429 }
430 }
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700431/* spin_unlock_irqrestore(&card->slock, flags); */
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700432
433 /* unlock the device */
434 up(&card->sem);
435
436 return retval;
437}
438
439#define SHIFT 1
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700440static inline void cpcusb_align_buffer_alignment(unsigned char *buf)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700441{
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700442 /* CPC-USB uploads packed bytes. */
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700443 CPC_MSG_T *cpc = (CPC_MSG_T *) buf;
444 unsigned int i;
445
446 for (i = 0; i < cpc->length + (2 * sizeof(unsigned long)); i++) {
447 ((unsigned char *) &cpc->msgid)[1 + i] =
448 ((unsigned char *) &cpc->msgid)[1 + SHIFT + i];
449 }
450}
451
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700452static int cpc_get_buffer_count(CPC_CHAN_T *chan)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700453{
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700454 /* check the buffer parameters */
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700455 if (chan->iidx == chan->oidx)
456 return !chan->WnR ? CPC_MSG_BUF_CNT : 0;
457 else if (chan->iidx >= chan->oidx)
458 return (chan->iidx - chan->oidx) % CPC_MSG_BUF_CNT;
459
460 return (chan->iidx + CPC_MSG_BUF_CNT - chan->oidx) % CPC_MSG_BUF_CNT;
461}
462
463static ssize_t cpcusb_write(struct file *file, const char *buffer,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700464 size_t count, loff_t *ppos)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700465{
466 CPC_USB_T *card = (CPC_USB_T *) file->private_data;
467 CPC_USB_WRITE_URB_T *wrUrb = NULL;
468
469 ssize_t bytes_written = 0;
470 int retval = 0;
471 int j;
472
473 unsigned char *obuf = NULL;
474 unsigned char type = 0;
475 CPC_MSG_T *info = NULL;
476
Alexander Beregalov5e23f3e2009-05-21 15:44:46 +0400477 dbg("%s - entered minor %d, count = %zu, present = %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700478 __func__, card->minor, count, card->present);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700479
480 if (count > sizeof(CPC_MSG_T))
481 return CPC_ERR_UNKNOWN;
482
483 /* check if can read from the given address */
484 if (!access_ok(VERIFY_READ, buffer, count))
485 return CPC_ERR_UNKNOWN;
486
487 /* lock this object */
488 down(&card->sem);
489
490 /* verify that the device wasn't unplugged */
491 if (!card->present) {
492 retval = CPC_ERR_NO_INTERFACE_PRESENT;
493 goto exit;
494 }
495
496 /* verify that we actually have some data to write */
497 if (count == 0) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700498 dbg("%s - write request of 0 bytes", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700499 goto exit;
500 }
501
502 if (card->free_slots <= 5) {
503 info = (CPC_MSG_T *) buffer;
504
505 if (info->type != CPC_CMD_T_CLEAR_CMD_QUEUE
506 || card->free_slots <= 0) {
507 dbg("%s - send buffer full please try again %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700508 __func__, card->free_slots);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700509 retval = CPC_ERR_CAN_NO_TRANSMIT_BUF;
510 goto exit;
511 }
512 }
513
514 /* Find a free write urb */
515 for (j = 0; j < CPC_USB_URB_CNT; j++) {
516 if (!atomic_read(&card->wrUrbs[j].busy)) {
517 wrUrb = &card->wrUrbs[j]; /* remember found URB */
518 atomic_set(&wrUrb->busy, 1); /* lock this URB */
519 init_completion(&wrUrb->finished); /* init completion */
520 dbg("WR URB no. %d started", j);
521 break;
522 }
523 }
524
525 /* don't found write urb say error */
526 if (!wrUrb) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700527 dbg("%s - no free send urb available", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700528 retval = CPC_ERR_CAN_NO_TRANSMIT_BUF;
529 goto exit;
530 }
531 dbg("URB write req");
532
533 obuf = (unsigned char *) wrUrb->urb->transfer_buffer;
534
535 /* copy the data from userspace into our transfer buffer;
536 * this is the only copy required.
537 */
538 if (copy_from_user(&obuf[4], buffer, count) != 0) {
539 atomic_set(&wrUrb->busy, 0); /* release urb */
540 retval = CPC_ERR_IO_TRANSFER;
541 goto exit;
542 }
543
544 /* check if it is a DRIVER information message, so we can
545 * response to that message and not the USB
546 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700547 info = (CPC_MSG_T *) &obuf[4];
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700548
549 bytes_written = 11 + info->length;
550 if (bytes_written >= wrUrb->size) {
551 retval = CPC_ERR_IO_TRANSFER;
552 goto exit;
553 }
554
555 switch (info->type) {
556 case CPC_CMD_T_CLEAR_MSG_QUEUE:
557 ResetBuffer(card->chan);
558 break;
559
560 case CPC_CMD_T_INQ_MSG_QUEUE_CNT:
561 retval = cpc_get_buffer_count(card->chan);
562 atomic_set(&wrUrb->busy, 0);
563
564 goto exit;
565
566 case CPC_CMD_T_INQ_INFO:
567 if (info->msg.info.source == CPC_INFOMSG_T_DRIVER) {
568 /* release urb cause we'll use it for driver
569 * information
570 */
571 atomic_set(&wrUrb->busy, 0);
572 if (IsBufferFull(card->chan)) {
573 retval = CPC_ERR_IO_TRANSFER;
574 goto exit;
575 }
576
577 /* it is a driver information request message and we have
578 * free rx slots to store the response
579 */
580 type = info->msg.info.type;
581 info = &card->chan->buf[card->chan->iidx];
582
583 info->type = CPC_MSG_T_INFO;
584 info->msg.info.source = CPC_INFOMSG_T_DRIVER;
585 info->msg.info.type = type;
586
587 switch (type) {
588 case CPC_INFOMSG_T_VERSION:
589 info->length = strlen(CPC_DRIVER_VERSION) + 2;
590 sprintf(info->msg.info.msg, "%s\n",
591 CPC_DRIVER_VERSION);
592 break;
593
594 case CPC_INFOMSG_T_SERIAL:
595 info->length = strlen(CPC_DRIVER_SERIAL) + 2;
596 sprintf(info->msg.info.msg, "%s\n",
597 CPC_DRIVER_SERIAL);
598 break;
599
600 default:
601 info->length = 2;
602 info->msg.info.type =
603 CPC_INFOMSG_T_UNKNOWN_TYPE;
604 }
605
606 card->chan->WnR = 0;
607 card->chan->iidx =
608 (card->chan->iidx + 1) % CPC_MSG_BUF_CNT;
609
610 retval = info->length;
611 goto exit;
612 }
613 break;
614 case CPC_CMD_T_CAN_PRMS:
615 /* Check the controller type. If it's the new CPC-USB, make sure if these are SJA1000 params */
616 if (info->msg.canparams.cc_type != SJA1000
617 && info->msg.canparams.cc_type != M16C_BASIC
618 && (card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID
619 && info->msg.canparams.cc_type != SJA1000)) {
620 /* don't forget to release the urb */
621 atomic_set(&wrUrb->busy, 0);
622 retval = CPC_ERR_WRONG_CONTROLLER_TYPE;
623 goto exit;
624 }
625 break;
626 }
627
628 /* just convert the params if it is an old CPC-USB with M16C controller */
629 if (card->productId == USB_CPCUSB_M16C_PRODUCT_ID) {
630 /* if it is a parameter message convert it from SJA1000 controller
631 * settings to M16C Basic controller settings
632 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700633 SJA1000_TO_M16C_BASIC_Params((CPC_MSG_T *) &obuf[4]);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700634 }
635
636 /* don't forget the byte alignment */
637 cpcusb_align_buffer_alignment(&obuf[4]);
638
639 /* setup a the 4 byte header */
640 obuf[0] = obuf[1] = obuf[2] = obuf[3] = 0;
641
642 /* this urb was already set up, except for this write size */
643 wrUrb->urb->transfer_buffer_length = bytes_written + 4;
644
645 /* send the data out the bulk port */
646 /* a character device write uses GFP_KERNEL,
647 unless a spinlock is held */
648 retval = usb_submit_urb(wrUrb->urb, GFP_KERNEL);
649 if (retval) {
650 atomic_set(&wrUrb->busy, 0); /* release urb */
651 err("%s - failed submitting write urb, error %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700652 __func__, retval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700653 } else {
654 retval = bytes_written;
655 }
656
657exit:
658 /* unlock the device */
659 up(&card->sem);
660
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700661 dbg("%s - leaved", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700662
663 return retval;
664}
665
666/*
667 * callback for interrupt IN urb
668 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700669static void cpcusb_read_interrupt_callback(struct urb *urb)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700670{
671 CPC_USB_T *card = (CPC_USB_T *) urb->context;
672 int retval;
673 unsigned long flags;
674
675 spin_lock_irqsave(&card->slock, flags);
676
677 if (!card->present) {
678 spin_unlock_irqrestore(&card->slock, flags);
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700679 info("%s - no such device", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700680 return;
681 }
682
683 switch (urb->status) {
684 case 0: /* success */
685 card->free_slots = card->intr_in_buffer[1];
686 break;
687 case -ECONNRESET:
688 case -ENOENT:
689 case -ESHUTDOWN:
690 /* urb was killed */
691 spin_unlock_irqrestore(&card->slock, flags);
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700692 dbg("%s - intr urb killed", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700693 return;
694 default:
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700695 info("%s - nonzero urb status %d", __func__, urb->status);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700696 break;
697 }
698
699 retval = usb_submit_urb(urb, GFP_ATOMIC);
700 if (retval) {
701 err("%s - failed resubmitting intr urb, error %d",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700702 __func__, retval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700703 }
704
705 spin_unlock_irqrestore(&card->slock, flags);
706 wake_up_interruptible(card->chan->CPCWait_q);
707
708 return;
709}
710
711#define UN_SHIFT 1
712#define CPCMSG_HEADER_LEN_FIRMWARE 11
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700713static inline int cpcusb_unalign_and_copy_buffy(unsigned char *out,
714 unsigned char *in)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700715{
716 unsigned int i, j;
717
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700718 for (i = 0; i < 3; i++)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700719 out[i] = in[i];
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700720
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700721 for (j = 0; j < (in[1] + (CPCMSG_HEADER_LEN_FIRMWARE - 3)); j++)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700722 out[j + i + UN_SHIFT] = in[j + i];
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700723
724 return i + j;
725}
726
727/*
728 * callback for bulk IN urb
729 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700730static void cpcusb_read_bulk_callback(struct urb *urb)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700731{
732 CPC_USB_T *card = (CPC_USB_T *) urb->context;
733 CPC_CHAN_T *chan;
734 unsigned char *ibuf = urb->transfer_buffer;
735 int retval, msgCnt, start, again = 0;
736 unsigned long flags;
737
738 if (!card) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700739 err("%s - device object lost", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700740 return;
741 }
742
743 spin_lock_irqsave(&card->slock, flags);
744
745 if (!card->present) {
746 spin_unlock_irqrestore(&card->slock, flags);
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700747 info("%s - no such device", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700748 return;
749 }
750
751 switch (urb->status) {
752 case 0: /* success */
753 break;
754 case -ECONNRESET:
755 case -ENOENT:
756 case -ESHUTDOWN:
757 /* urb was killed */
758 spin_unlock_irqrestore(&card->slock, flags);
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700759 dbg("%s - read urb killed", __func__);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700760 return;
761 default:
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700762 info("%s - nonzero urb status %d", __func__, urb->status);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700763 break;
764 }
765
766 if (urb->actual_length) {
767 msgCnt = ibuf[0] & ~0x80;
768 again = ibuf[0] & 0x80;
769
770 /* we have a 4 byte header */
771 start = 4;
772 chan = card->chan;
773 while (msgCnt) {
774 if (!(IsBufferFull(card->chan))) {
775 start +=
776 cpcusb_unalign_and_copy_buffy((unsigned char *)
777 &chan->buf[chan->iidx], &ibuf[start]);
778
779 if (start > urb->transfer_buffer_length) {
780 err("%d > %d", start, urb->transfer_buffer_length);
781 break;
782 }
783
784 chan->WnR = 0;
785 chan->iidx = (chan->iidx + 1) % CPC_MSG_BUF_CNT;
786 msgCnt--;
787 } else {
788 break;
789 }
790 }
791 }
792
793 usb_fill_bulk_urb(urb, card->udev,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700794 usb_rcvbulkpipe(card->udev, card->num_bulk_in),
795 urb->transfer_buffer,
796 urb->transfer_buffer_length,
797 cpcusb_read_bulk_callback, card);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700798
799 retval = usb_submit_urb(urb, GFP_ATOMIC);
800
801 if (retval) {
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700802 err("%s - failed resubmitting read urb, error %d", __func__, retval);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700803 }
804
805 spin_unlock_irqrestore(&card->slock, flags);
806
807 wake_up_interruptible(card->chan->CPCWait_q);
808}
809
810/*
811 * callback for bulk IN urb
812 */
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700813static void cpcusb_write_bulk_callback(struct urb *urb)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700814{
815 CPC_USB_T *card = (CPC_USB_T *) urb->context;
816 unsigned long flags;
817 int j;
818
819 spin_lock_irqsave(&card->slock, flags);
820
821 /* find this urb */
822 for (j = 0; j < CPC_USB_URB_CNT; j++) {
823 if (card->wrUrbs[j].urb == urb) {
824 dbg("URB found no. %d", j);
825 /* notify anyone waiting that the write has finished */
826 complete(&card->wrUrbs[j].finished);
827 atomic_set(&card->wrUrbs[j].busy, 0);
828 break;
829 }
830 }
831
832 switch (urb->status) {
833 case 0: /* success */
834 break;
835 case -ECONNRESET:
836 case -ENOENT:
837 case -ESHUTDOWN:
838 /* urb was killed */
839 spin_unlock_irqrestore(&card->slock, flags);
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700840 dbg("%s - write urb no. %d killed", __func__, j);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700841 return;
842 default:
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700843 info("%s - nonzero urb status %d", __func__, urb->status);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700844 break;
845 }
846
847 spin_unlock_irqrestore(&card->slock, flags);
848
849 wake_up_interruptible(card->chan->CPCWait_q);
850}
851
852static inline int cpcusb_get_free_slot(void)
853{
854 int i;
855
856 for (i = 0; i < CPC_USB_CARD_CNT; i++) {
857 if (!CPCUSB_Table[i])
858 return i;
859 }
860
861 return -1;
862}
863
864/*
865 * probe function for new CPC-USB devices
866 */
867static int cpcusb_probe(struct usb_interface *interface,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700868 const struct usb_device_id *id)
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700869{
870 CPC_USB_T *card = NULL;
871 CPC_CHAN_T *chan = NULL;
872
873 struct usb_device *udev = interface_to_usbdev(interface);
874 struct usb_host_interface *iface_desc;
875 struct usb_endpoint_descriptor *endpoint;
876
877 int i, j, retval = -ENOMEM, slot;
878
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700879 slot = cpcusb_get_free_slot();
880 if (slot < 0) {
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700881 info("No more devices supported");
882 return -ENOMEM;
883 }
884
885 /* allocate memory for our device state and initialize it */
886 card = kzalloc(sizeof(CPC_USB_T), GFP_KERNEL);
887 if (!card) {
888 err("Out of memory");
889 return -ENOMEM;
890 }
891 CPCUSB_Table[slot] = card;
892
893 /* allocate and initialize the channel struct */
894 card->chan = kmalloc(sizeof(CPC_CHAN_T), GFP_KERNEL);
Julia Lawalla3d97c92009-05-20 09:17:11 +0200895 if (!card->chan) {
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700896 kfree(card);
897 err("Out of memory");
898 return -ENOMEM;
899 }
900
901 chan = card->chan;
902 memset(chan, 0, sizeof(CPC_CHAN_T));
903 ResetBuffer(chan);
904
905 init_MUTEX(&card->sem);
906 spin_lock_init(&card->slock);
907
908 card->udev = udev;
909 card->interface = interface;
910 if (udev->descriptor.iSerialNumber) {
911 usb_string(udev, udev->descriptor.iSerialNumber, card->serialNumber,
912 128);
913 info("Serial %s", card->serialNumber);
914 }
915
916 card->productId = udev->descriptor.idProduct;
917 info("Product %s",
918 card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID ?
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700919 "CPC-USB/ARM7" : "CPC-USB/M16C");
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700920
921 /* set up the endpoint information */
922 /* check out the endpoints */
923 /* use only the first bulk-in and bulk-out endpoints */
924 iface_desc = &interface->altsetting[0];
925 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
926 endpoint = &iface_desc->endpoint[i].desc;
927
928 if (!card->num_intr_in &&
929 (endpoint->bEndpointAddress & USB_DIR_IN) &&
930 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
931 == USB_ENDPOINT_XFER_INT)) {
932 card->intr_in_urb = usb_alloc_urb(0, GFP_KERNEL);
933 card->num_intr_in = 1;
934
935 if (!card->intr_in_urb) {
936 err("No free urbs available");
937 goto error;
938 }
939
940 dbg("intr_in urb %d", card->num_intr_in);
941 }
942
943 if (!card->num_bulk_in &&
944 (endpoint->bEndpointAddress & USB_DIR_IN) &&
945 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
946 == USB_ENDPOINT_XFER_BULK)) {
947 card->num_bulk_in = 2;
948 for (j = 0; j < CPC_USB_URB_CNT; j++) {
949 card->urbs[j].size = endpoint->wMaxPacketSize;
950 card->urbs[j].urb = usb_alloc_urb(0, GFP_KERNEL);
951 if (!card->urbs[j].urb) {
952 err("No free urbs available");
953 goto error;
954 }
955 card->urbs[j].buffer =
956 usb_buffer_alloc(udev,
957 card->urbs[j].size,
958 GFP_KERNEL,
959 &card->urbs[j].urb->transfer_dma);
960 if (!card->urbs[j].buffer) {
961 err("Couldn't allocate bulk_in_buffer");
962 goto error;
963 }
964 }
965 info("%s - %d reading URB's allocated",
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700966 __func__, CPC_USB_URB_CNT);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700967 }
968
969 if (!card->num_bulk_out &&
970 !(endpoint->bEndpointAddress & USB_DIR_IN) &&
971 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
972 == USB_ENDPOINT_XFER_BULK)) {
973
974 card->num_bulk_out = 2;
975
976 for (j = 0; j < CPC_USB_URB_CNT; j++) {
977 card->wrUrbs[j].size =
978 endpoint->wMaxPacketSize;
979 card->wrUrbs[j].urb =
980 usb_alloc_urb(0, GFP_KERNEL);
981 if (!card->wrUrbs[j].urb) {
982 err("No free urbs available");
983 goto error;
984 }
985 card->wrUrbs[j].buffer = usb_buffer_alloc(udev,
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -0700986 card->wrUrbs[j].size, GFP_KERNEL,
987 &card->wrUrbs[j].urb->transfer_dma);
Sebastian Haase0ce8a72009-05-14 20:46:12 -0700988
989 if (!card->wrUrbs[j].buffer) {
990 err("Couldn't allocate bulk_out_buffer");
991 goto error;
992 }
993
994 usb_fill_bulk_urb(card->wrUrbs[j].urb, udev,
995 usb_sndbulkpipe(udev, endpoint->bEndpointAddress),
996 card->wrUrbs[j].buffer,
997 card->wrUrbs[j].size,
998 cpcusb_write_bulk_callback,
999 card);
1000 }
1001
Greg Kroah-Hartman0f064b52009-05-14 21:13:51 -07001002 info("%s - %d writing URB's allocated", __func__, CPC_USB_URB_CNT);
Sebastian Haase0ce8a72009-05-14 20:46:12 -07001003 }
1004 }
1005
1006 if (!(card->num_bulk_in && card->num_bulk_out)) {
1007 err("Couldn't find both bulk-in and bulk-out endpoints");
1008 goto error;
1009 }
1010
1011 /* allow device read, write and ioctl */
1012 card->present = 1;
1013
1014 /* we can register the device now, as it is ready */
1015 usb_set_intfdata(interface, card);
1016 retval = usb_register_dev(interface, &cpcusb_class);
1017
1018 if (retval) {
1019 /* something prevented us from registering this driver */
1020 err("Not able to get a minor for this device.");
1021 usb_set_intfdata(interface, NULL);
1022 goto error;
1023 }
1024
1025 card->chan->minor = card->minor = interface->minor;
1026
1027 chan->buf = vmalloc(sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT);
1028 if (chan->buf == NULL) {
1029 err("Out of memory");
1030 retval = -ENOMEM;
1031 goto error;
1032 }
Alexander Beregalov5e23f3e2009-05-21 15:44:46 +04001033 info("Allocated memory for %d messages (%lu kbytes)",
Greg Kroah-Hartmand01c3c82009-06-04 11:29:54 -07001034 CPC_MSG_BUF_CNT, (long unsigned int)(sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT) / 1000);
Sebastian Haase0ce8a72009-05-14 20:46:12 -07001035 memset(chan->buf, 0, sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT);
1036
1037 ResetBuffer(chan);
1038
1039 card->chan->CPCWait_q = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
1040 if (!card->chan->CPCWait_q) {
1041 err("Out of memory");
1042 retval = -ENOMEM;
1043 goto error;
1044 }
1045 init_waitqueue_head(card->chan->CPCWait_q);
1046
1047 CPCUSB_Table[slot] = card;
1048 card->idx = slot;
1049 CPCUsbCnt++;
1050
1051 /* let the user know what node this device is now attached to */
1052 info("Device now attached to USB-%d", card->minor);
1053 return 0;
1054
1055error:
1056 for (j = 0; j < CPC_USB_URB_CNT; j++) {
1057 if (card->urbs[j].buffer) {
1058 usb_buffer_free(card->udev, card->urbs[j].size,
1059 card->urbs[j].buffer,
1060 card->urbs[j].urb->transfer_dma);
1061 card->urbs[j].buffer = NULL;
1062 }
1063 if (card->urbs[j].urb) {
1064 usb_free_urb(card->urbs[j].urb);
1065 card->urbs[j].urb = NULL;
1066 }
1067 }
1068
1069 cpcusb_delete(card);
1070 return retval;
1071}
1072
1073/*
1074 * called by the usb core when the device is removed from the system
1075 */
1076static void cpcusb_disconnect(struct usb_interface *interface)
1077{
1078 CPC_USB_T *card = NULL;
1079 int minor, j;
1080
1081 /* prevent races with open() */
1082 down(&disconnect_sem);
1083
1084 card = usb_get_intfdata(interface);
1085 usb_set_intfdata(interface, NULL);
1086
1087 down(&card->sem);
1088
1089 /* prevent device read, write and ioctl */
1090 card->present = 0;
1091
1092 minor = card->minor;
1093
1094 /* free all urbs and their buffers */
1095 for (j = 0; j < CPC_USB_URB_CNT; j++) {
1096 /* terminate an ongoing write */
1097 if (atomic_read(&card->wrUrbs[j].busy)) {
1098 usb_kill_urb(card->wrUrbs[j].urb);
1099 wait_for_completion(&card->wrUrbs[j].finished);
1100 }
1101 usb_buffer_free(card->udev, card->wrUrbs[j].size,
1102 card->wrUrbs[j].buffer,
1103 card->wrUrbs[j].urb->transfer_dma);
1104 usb_free_urb(card->wrUrbs[j].urb);
1105 }
1106 info("%d write URBs freed", CPC_USB_URB_CNT);
1107
1108 /* free all urbs and their buffers */
1109 for (j = 0; j < CPC_USB_URB_CNT; j++) {
1110 usb_buffer_free(card->udev, card->urbs[j].size,
1111 card->urbs[j].buffer,
1112 card->urbs[j].urb->transfer_dma);
1113 usb_free_urb(card->urbs[j].urb);
1114 }
1115 info("%d read URBs freed", CPC_USB_URB_CNT);
1116 usb_free_urb(card->intr_in_urb);
1117
1118 /* give back our minor */
1119 usb_deregister_dev(interface, &cpcusb_class);
1120
1121 up(&card->sem);
1122
1123 /* if the device is opened, cpcusb_release will clean this up */
1124 if (!card->open)
1125 cpcusb_delete(card);
1126 else
1127 wake_up_interruptible(card->chan->CPCWait_q);
1128
1129 up(&disconnect_sem);
1130
1131 CPCUsbCnt--;
1132 info("USB-%d now disconnected", minor);
1133}
1134
1135static int __init CPCUsb_Init(void)
1136{
1137 int result, i;
1138
1139 info(DRIVER_DESC " v" DRIVER_VERSION);
1140 info("Build on " __DATE__ " at " __TIME__);
1141
1142 for (i = 0; i < CPC_USB_CARD_CNT; i++)
1143 CPCUSB_Table[i] = 0;
1144
1145 /* register this driver with the USB subsystem */
1146 result = usb_register(&cpcusb_driver);
1147 if (result) {
1148 err("usb_register failed. Error number %d", result);
1149 return result;
1150 }
1151
1152 procDir = proc_mkdir(CPC_USB_PROC_DIR, NULL);
1153 if (!procDir) {
1154 err("Could not create proc entry");
1155 } else {
Sebastian Haase0ce8a72009-05-14 20:46:12 -07001156 procEntry = create_proc_read_entry("info", 0444, procDir,
1157 cpcusb_proc_read_info,
1158 NULL);
1159 if (!procEntry) {
1160 err("Could not create proc entry %s", CPC_USB_PROC_DIR "/info");
1161 remove_proc_entry(CPC_USB_PROC_DIR, NULL);
1162 procDir = NULL;
Sebastian Haase0ce8a72009-05-14 20:46:12 -07001163 }
1164 }
1165
1166 return 0;
1167}
1168
1169static void __exit CPCUsb_Exit(void)
1170{
1171 wait_event(rmmodWq, !atomic_read(&useCount));
1172
1173 /* deregister this driver with the USB subsystem */
1174 usb_deregister(&cpcusb_driver);
1175
1176 if (procDir) {
1177 if (procEntry)
1178 remove_proc_entry("info", procDir);
1179 remove_proc_entry(CPC_USB_PROC_DIR, NULL);
1180 }
1181}
1182
1183module_init(CPCUsb_Init);
1184module_exit(CPCUsb_Exit);