diff options
author | Sebastian Haas <haas@ems-wuensche.com> | 2009-05-14 23:46:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-19 14:00:52 -0400 |
commit | e0ce8a7265fec155f97438c80dedd7f01ff0055f (patch) | |
tree | 1ff115e081d6771835cc4f7f6ea7bc39a51627ae /drivers | |
parent | 6456f0b7683c9b82ca3f3e4f0aec15b9d2966561 (diff) |
Staging: add cpc-usb driver to the staging tree
This is a CPC CAN USB driver.
Just some comments:
cpcusb.h and cpc-usb_drv.c: Essential driver source code
sja2m16c_2.c: Helper for converting bitrate timings
cpc.h: Structures and definition needed to communicate with the device
From: Sebastian Haas <haas@ems-wuensche.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/cpc-usb/cpc-usb_drv.c | 1232 | ||||
-rw-r--r-- | drivers/staging/cpc-usb/cpc.h | 440 | ||||
-rw-r--r-- | drivers/staging/cpc-usb/cpc_int.h | 85 | ||||
-rw-r--r-- | drivers/staging/cpc-usb/cpcusb.h | 86 | ||||
-rw-r--r-- | drivers/staging/cpc-usb/sja2m16c.h | 41 | ||||
-rw-r--r-- | drivers/staging/cpc-usb/sja2m16c_2.c | 452 |
6 files changed, 2336 insertions, 0 deletions
diff --git a/drivers/staging/cpc-usb/cpc-usb_drv.c b/drivers/staging/cpc-usb/cpc-usb_drv.c new file mode 100644 index 000000000000..a08c6655b86b --- /dev/null +++ b/drivers/staging/cpc-usb/cpc-usb_drv.c | |||
@@ -0,0 +1,1232 @@ | |||
1 | /* | ||
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 | |||
31 | #include <linux/version.h> | ||
32 | |||
33 | /* usb_kill_urb has been introduced in kernel version 2.6.8 (RC2) */ | ||
34 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)) | ||
35 | #define usb_kill_urb usb_unlink_urb | ||
36 | #endif | ||
37 | |||
38 | #ifdef CONFIG_PROC_FS | ||
39 | # include <linux/proc_fs.h> | ||
40 | #endif | ||
41 | |||
42 | #include "cpc.h" | ||
43 | |||
44 | #include "cpc_int.h" | ||
45 | #include "cpcusb.h" | ||
46 | |||
47 | #include "sja2m16c.h" | ||
48 | |||
49 | /* Version Information */ | ||
50 | #define DRIVER_AUTHOR "Sebastian Haas <haas@ems-wuensche.com>" | ||
51 | #define DRIVER_DESC "CPC-USB Driver for Linux Kernel 2.6" | ||
52 | #define DRIVER_VERSION CPC_DRIVER_VERSION " (CDKL v" CDKL_VERSION ")" | ||
53 | |||
54 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
55 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
56 | MODULE_VERSION(DRIVER_VERSION); | ||
57 | MODULE_LICENSE("GPL v2"); | ||
58 | |||
59 | /* Define these values to match your devices */ | ||
60 | #define USB_CPCUSB_VENDOR_ID 0x12D6 | ||
61 | |||
62 | #define USB_CPCUSB_M16C_PRODUCT_ID 0x0888 | ||
63 | #define USB_CPCUSB_LPC2119_PRODUCT_ID 0x0444 | ||
64 | |||
65 | #ifndef CONFIG_PROC_FS | ||
66 | #error "PROCFS needed" | ||
67 | #endif | ||
68 | |||
69 | #define CPC_USB_PROC_DIR CPC_PROC_DIR "cpc-usb" | ||
70 | |||
71 | static struct proc_dir_entry *procDir = NULL; | ||
72 | static struct proc_dir_entry *procEntry = NULL; | ||
73 | |||
74 | /* Module parameters */ | ||
75 | static int debug = 0; | ||
76 | module_param(debug, int, S_IRUGO); | ||
77 | |||
78 | /* table of devices that work with this driver */ | ||
79 | static struct usb_device_id cpcusb_table[] = { | ||
80 | {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_M16C_PRODUCT_ID)}, | ||
81 | {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_LPC2119_PRODUCT_ID)}, | ||
82 | {} /* Terminating entry */ | ||
83 | }; | ||
84 | |||
85 | MODULE_DEVICE_TABLE(usb, cpcusb_table); | ||
86 | |||
87 | /* use to prevent kernel panic if driver is unloaded | ||
88 | * while a programm has still open the device | ||
89 | */ | ||
90 | DECLARE_WAIT_QUEUE_HEAD(rmmodWq); | ||
91 | atomic_t useCount; | ||
92 | |||
93 | static CPC_USB_T *CPCUSB_Table[CPC_USB_CARD_CNT] = { 0 }; | ||
94 | static unsigned int CPCUsbCnt = 0; | ||
95 | |||
96 | /* prevent races between open() and disconnect() */ | ||
97 | static DECLARE_MUTEX(disconnect_sem); | ||
98 | |||
99 | /* local function prototypes */ | ||
100 | static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count, | ||
101 | loff_t * ppos); | ||
102 | static ssize_t cpcusb_write(struct file *file, const char *buffer, | ||
103 | size_t count, loff_t * ppos); | ||
104 | static unsigned int cpcusb_poll(struct file *file, poll_table * wait); | ||
105 | static int cpcusb_open(struct inode *inode, struct file *file); | ||
106 | static int cpcusb_release(struct inode *inode, struct file *file); | ||
107 | |||
108 | static int cpcusb_probe(struct usb_interface *interface, | ||
109 | const struct usb_device_id *id); | ||
110 | static void cpcusb_disconnect(struct usb_interface *interface); | ||
111 | |||
112 | static void cpcusb_read_bulk_callback(struct urb *urb | ||
113 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
114 | , struct pt_regs *regs | ||
115 | #endif | ||
116 | ); | ||
117 | static void cpcusb_write_bulk_callback(struct urb *urb | ||
118 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
119 | , struct pt_regs *regs | ||
120 | #endif | ||
121 | ); | ||
122 | static void cpcusb_read_interrupt_callback(struct urb *urb | ||
123 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
124 | , struct pt_regs *regs | ||
125 | #endif | ||
126 | ); | ||
127 | |||
128 | static int cpcusb_setup_intrep(CPC_USB_T * card); | ||
129 | |||
130 | static struct file_operations cpcusb_fops = { | ||
131 | /* | ||
132 | * The owner field is part of the module-locking | ||
133 | * mechanism. The idea is that the kernel knows | ||
134 | * which module to increment the use-counter of | ||
135 | * BEFORE it calls the device's open() function. | ||
136 | * This also means that the kernel can decrement | ||
137 | * the use-counter again before calling release() | ||
138 | * or should the open() function fail. | ||
139 | */ | ||
140 | .owner = THIS_MODULE, | ||
141 | |||
142 | .read = cpcusb_read, | ||
143 | .write = cpcusb_write, | ||
144 | .poll = cpcusb_poll, | ||
145 | .open = cpcusb_open, | ||
146 | .release = cpcusb_release, | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * usb class driver info in order to get a minor number from the usb core, | ||
151 | * and to have the device registered with devfs and the driver core | ||
152 | */ | ||
153 | static struct usb_class_driver cpcusb_class = { | ||
154 | .name = "usb/cpc_usb%d", | ||
155 | .fops = &cpcusb_fops, | ||
156 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) | ||
157 | .mode = | ||
158 | S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | | ||
159 | S_IWOTH, | ||
160 | #endif | ||
161 | .minor_base = CPC_USB_BASE_MNR, | ||
162 | }; | ||
163 | |||
164 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
165 | static struct usb_driver cpcusb_driver = { | ||
166 | #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14)) | ||
167 | .owner = THIS_MODULE, | ||
168 | #endif | ||
169 | .name = "cpc-usb", | ||
170 | .probe = cpcusb_probe, | ||
171 | .disconnect = cpcusb_disconnect, | ||
172 | .id_table = cpcusb_table, | ||
173 | }; | ||
174 | |||
175 | static int cpcusb_create_info_output(char *buf) | ||
176 | { | ||
177 | int i = 0, j; | ||
178 | |||
179 | for (j = 0; j < CPC_USB_CARD_CNT; j++) { | ||
180 | if (CPCUSB_Table[j]) { | ||
181 | CPC_USB_T *card = CPCUSB_Table[j]; | ||
182 | CPC_CHAN_T *chan = card->chan; | ||
183 | |||
184 | /* MINOR CHANNELNO BUSNO SLOTNO */ | ||
185 | i += sprintf(&buf[i], "%d %s\n", chan->minor, | ||
186 | card->serialNumber); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | return i; | ||
191 | } | ||
192 | |||
193 | static int cpcusb_proc_read_info(char *page, char **start, off_t off, | ||
194 | int count, int *eof, void *data) | ||
195 | { | ||
196 | int len = cpcusb_create_info_output(page); | ||
197 | |||
198 | if (len <= off + count) | ||
199 | *eof = 1; | ||
200 | *start = page + off; | ||
201 | len -= off; | ||
202 | if (len > count) | ||
203 | len = count; | ||
204 | if (len < 0) | ||
205 | len = 0; | ||
206 | |||
207 | return len; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * Remove CPC-USB and cleanup | ||
212 | */ | ||
213 | static inline void cpcusb_delete(CPC_USB_T * card) | ||
214 | { | ||
215 | if (card) { | ||
216 | if (card->chan) { | ||
217 | if (card->chan->buf) | ||
218 | vfree(card->chan->buf); | ||
219 | |||
220 | if (card->chan->CPCWait_q) | ||
221 | kfree(card->chan->CPCWait_q); | ||
222 | |||
223 | kfree(card->chan); | ||
224 | } | ||
225 | |||
226 | CPCUSB_Table[card->idx] = NULL; | ||
227 | kfree(card); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * setup the interrupt IN endpoint of a specific CPC-USB device | ||
233 | */ | ||
234 | static int cpcusb_setup_intrep(CPC_USB_T * card) | ||
235 | { | ||
236 | int retval = 0; | ||
237 | struct usb_endpoint_descriptor *ep; | ||
238 | |||
239 | ep = &card->interface->altsetting[0].endpoint[card->num_intr_in].desc; | ||
240 | |||
241 | card->intr_in_buffer[0] = 0; | ||
242 | card->free_slots = 15; /* initial size */ | ||
243 | |||
244 | /* setup the urb */ | ||
245 | usb_fill_int_urb(card->intr_in_urb, card->udev, | ||
246 | usb_rcvintpipe(card->udev, card->num_intr_in), | ||
247 | card->intr_in_buffer, | ||
248 | sizeof(card->intr_in_buffer), | ||
249 | cpcusb_read_interrupt_callback, | ||
250 | card, | ||
251 | ep->bInterval); | ||
252 | |||
253 | card->intr_in_urb->status = 0; /* needed! */ | ||
254 | |||
255 | /* submit the urb */ | ||
256 | retval = usb_submit_urb(card->intr_in_urb, GFP_KERNEL); | ||
257 | |||
258 | if (retval) { | ||
259 | err("%s - failed submitting intr urb, error %d", __FUNCTION__, retval); | ||
260 | } | ||
261 | |||
262 | return retval; | ||
263 | } | ||
264 | |||
265 | static int cpcusb_open(struct inode *inode, struct file *file) | ||
266 | { | ||
267 | CPC_USB_T *card = NULL; | ||
268 | struct usb_interface *interface; | ||
269 | int subminor; | ||
270 | int j, retval = 0; | ||
271 | |||
272 | subminor = iminor(inode); | ||
273 | |||
274 | /* prevent disconnects */ | ||
275 | down(&disconnect_sem); | ||
276 | |||
277 | interface = usb_find_interface(&cpcusb_driver, subminor); | ||
278 | if (!interface) { | ||
279 | err("%s - error, can't find device for minor %d", | ||
280 | __FUNCTION__, subminor); | ||
281 | retval = CPC_ERR_NO_INTERFACE_PRESENT; | ||
282 | goto exit_no_device; | ||
283 | } | ||
284 | |||
285 | card = usb_get_intfdata(interface); | ||
286 | if (!card) { | ||
287 | retval = CPC_ERR_NO_INTERFACE_PRESENT; | ||
288 | goto exit_no_device; | ||
289 | } | ||
290 | |||
291 | /* lock this device */ | ||
292 | down(&card->sem); | ||
293 | |||
294 | /* increment our usage count for the driver */ | ||
295 | if (card->open) { | ||
296 | dbg("device already opened"); | ||
297 | retval = CPC_ERR_CHANNEL_ALREADY_OPEN; | ||
298 | goto exit_on_error; | ||
299 | } | ||
300 | |||
301 | /* save our object in the file's private structure */ | ||
302 | file->private_data = card; | ||
303 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
304 | usb_fill_bulk_urb(card->urbs[j].urb, card->udev, | ||
305 | usb_rcvbulkpipe(card->udev, card->num_bulk_in), | ||
306 | card->urbs[j].buffer, card->urbs[j].size, | ||
307 | cpcusb_read_bulk_callback, card); | ||
308 | |||
309 | retval = usb_submit_urb(card->urbs[j].urb, GFP_KERNEL); | ||
310 | |||
311 | if (retval) { | ||
312 | err("%s - failed submitting read urb, error %d", | ||
313 | __FUNCTION__, retval); | ||
314 | retval = CPC_ERR_TRANSMISSION_FAILED; | ||
315 | goto exit_on_error; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | info("%s - %d URB's submitted", __FUNCTION__, j); | ||
320 | |||
321 | ResetBuffer(card->chan); | ||
322 | |||
323 | cpcusb_setup_intrep(card); | ||
324 | card->open = 1; | ||
325 | |||
326 | atomic_inc(&useCount); | ||
327 | |||
328 | exit_on_error: | ||
329 | /* unlock this device */ | ||
330 | up(&card->sem); | ||
331 | |||
332 | exit_no_device: | ||
333 | up(&disconnect_sem); | ||
334 | |||
335 | return retval; | ||
336 | } | ||
337 | |||
338 | static unsigned int cpcusb_poll(struct file *file, poll_table * wait) | ||
339 | { | ||
340 | CPC_USB_T *card = (CPC_USB_T *) file->private_data; | ||
341 | unsigned int retval = 0; | ||
342 | |||
343 | if (!card) { | ||
344 | err("%s - device object lost", __FUNCTION__); | ||
345 | return -EIO; | ||
346 | } | ||
347 | |||
348 | poll_wait(file, card->chan->CPCWait_q, wait); | ||
349 | |||
350 | if (IsBufferNotEmpty(card->chan) || !(card->present)) | ||
351 | retval |= (POLLIN | POLLRDNORM); | ||
352 | |||
353 | if (card->free_slots) | ||
354 | retval |= (POLLOUT | POLLWRNORM); | ||
355 | |||
356 | return retval; | ||
357 | } | ||
358 | |||
359 | static int cpcusb_release(struct inode *inode, struct file *file) | ||
360 | { | ||
361 | CPC_USB_T *card = (CPC_USB_T *) file->private_data; | ||
362 | int j, retval = 0; | ||
363 | |||
364 | if (card == NULL) { | ||
365 | dbg("%s - object is NULL", __FUNCTION__); | ||
366 | return CPC_ERR_NO_INTERFACE_PRESENT; | ||
367 | } | ||
368 | |||
369 | /* lock our device */ | ||
370 | down(&card->sem); | ||
371 | |||
372 | if (!card->open) { | ||
373 | dbg("%s - device not opened", __FUNCTION__); | ||
374 | retval = CPC_ERR_NO_INTERFACE_PRESENT; | ||
375 | goto exit_not_opened; | ||
376 | } | ||
377 | |||
378 | /* if device wasn't unplugged kill all urbs */ | ||
379 | if (card->present) { | ||
380 | /* kill read urbs */ | ||
381 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
382 | usb_kill_urb(card->urbs[j].urb); | ||
383 | } | ||
384 | |||
385 | /* kill irq urb */ | ||
386 | usb_kill_urb(card->intr_in_urb); | ||
387 | |||
388 | /* kill write urbs */ | ||
389 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
390 | if (atomic_read(&card->wrUrbs[j].busy)) { | ||
391 | usb_kill_urb(card->wrUrbs[j].urb); | ||
392 | wait_for_completion(&card->wrUrbs[j].finished); | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | atomic_dec(&useCount); | ||
398 | |||
399 | /* last process detached */ | ||
400 | if (atomic_read(&useCount) == 0) { | ||
401 | wake_up(&rmmodWq); | ||
402 | } | ||
403 | |||
404 | if (!card->present && card->open) { | ||
405 | /* the device was unplugged before the file was released */ | ||
406 | up(&card->sem); | ||
407 | cpcusb_delete(card); | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | card->open = 0; | ||
412 | |||
413 | exit_not_opened: | ||
414 | up(&card->sem); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count, | ||
420 | loff_t * ppos) | ||
421 | { | ||
422 | CPC_USB_T *card = (CPC_USB_T *) file->private_data; | ||
423 | CPC_CHAN_T *chan; | ||
424 | int retval = 0; | ||
425 | |||
426 | if (count < sizeof(CPC_MSG_T)) | ||
427 | return CPC_ERR_UNKNOWN; | ||
428 | |||
429 | /* check if can read from the given address */ | ||
430 | if (!access_ok(VERIFY_WRITE, buffer, count)) | ||
431 | return CPC_ERR_UNKNOWN; | ||
432 | |||
433 | /* lock this object */ | ||
434 | down(&card->sem); | ||
435 | |||
436 | /* verify that the device wasn't unplugged */ | ||
437 | if (!card->present) { | ||
438 | up(&card->sem); | ||
439 | return CPC_ERR_NO_INTERFACE_PRESENT; | ||
440 | } | ||
441 | |||
442 | if (IsBufferEmpty(card->chan)) { | ||
443 | retval = 0; | ||
444 | } else { | ||
445 | chan = card->chan; | ||
446 | |||
447 | #if 0 | ||
448 | /* convert LPC2119 params back to SJA1000 params */ | ||
449 | if (card->deviceRevision >= 0x0200 | ||
450 | && chan->buf[chan->oidx].type == CPC_MSG_T_CAN_PRMS) { | ||
451 | LPC2119_TO_SJA1000_Params(&chan->buf[chan->oidx]); | ||
452 | } | ||
453 | #endif | ||
454 | |||
455 | if (copy_to_user(buffer, &chan->buf[chan->oidx], count) != 0) { | ||
456 | retval = CPC_ERR_IO_TRANSFER; | ||
457 | } else { | ||
458 | chan->oidx = (chan->oidx + 1) % CPC_MSG_BUF_CNT; | ||
459 | chan->WnR = 1; | ||
460 | retval = sizeof(CPC_MSG_T); | ||
461 | } | ||
462 | } | ||
463 | // spin_unlock_irqrestore(&card->slock, flags); | ||
464 | |||
465 | /* unlock the device */ | ||
466 | up(&card->sem); | ||
467 | |||
468 | return retval; | ||
469 | } | ||
470 | |||
471 | #define SHIFT 1 | ||
472 | static void inline cpcusb_align_buffer_alignment(unsigned char *buf) | ||
473 | { | ||
474 | // CPC-USB uploads packed bytes. | ||
475 | CPC_MSG_T *cpc = (CPC_MSG_T *) buf; | ||
476 | unsigned int i; | ||
477 | |||
478 | for (i = 0; i < cpc->length + (2 * sizeof(unsigned long)); i++) { | ||
479 | ((unsigned char *) &cpc->msgid)[1 + i] = | ||
480 | ((unsigned char *) &cpc->msgid)[1 + SHIFT + i]; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | static int cpc_get_buffer_count(CPC_CHAN_T * chan) | ||
485 | { | ||
486 | // check the buffer parameters | ||
487 | if (chan->iidx == chan->oidx) | ||
488 | return !chan->WnR ? CPC_MSG_BUF_CNT : 0; | ||
489 | else if (chan->iidx >= chan->oidx) | ||
490 | return (chan->iidx - chan->oidx) % CPC_MSG_BUF_CNT; | ||
491 | |||
492 | return (chan->iidx + CPC_MSG_BUF_CNT - chan->oidx) % CPC_MSG_BUF_CNT; | ||
493 | } | ||
494 | |||
495 | static ssize_t cpcusb_write(struct file *file, const char *buffer, | ||
496 | size_t count, loff_t * ppos) | ||
497 | { | ||
498 | CPC_USB_T *card = (CPC_USB_T *) file->private_data; | ||
499 | CPC_USB_WRITE_URB_T *wrUrb = NULL; | ||
500 | |||
501 | ssize_t bytes_written = 0; | ||
502 | int retval = 0; | ||
503 | int j; | ||
504 | |||
505 | unsigned char *obuf = NULL; | ||
506 | unsigned char type = 0; | ||
507 | CPC_MSG_T *info = NULL; | ||
508 | |||
509 | dbg("%s - entered minor %d, count = %d, present = %d", | ||
510 | __FUNCTION__, card->minor, count, card->present); | ||
511 | |||
512 | if (count > sizeof(CPC_MSG_T)) | ||
513 | return CPC_ERR_UNKNOWN; | ||
514 | |||
515 | /* check if can read from the given address */ | ||
516 | if (!access_ok(VERIFY_READ, buffer, count)) | ||
517 | return CPC_ERR_UNKNOWN; | ||
518 | |||
519 | /* lock this object */ | ||
520 | down(&card->sem); | ||
521 | |||
522 | /* verify that the device wasn't unplugged */ | ||
523 | if (!card->present) { | ||
524 | retval = CPC_ERR_NO_INTERFACE_PRESENT; | ||
525 | goto exit; | ||
526 | } | ||
527 | |||
528 | /* verify that we actually have some data to write */ | ||
529 | if (count == 0) { | ||
530 | dbg("%s - write request of 0 bytes", __FUNCTION__); | ||
531 | goto exit; | ||
532 | } | ||
533 | |||
534 | if (card->free_slots <= 5) { | ||
535 | info = (CPC_MSG_T *) buffer; | ||
536 | |||
537 | if (info->type != CPC_CMD_T_CLEAR_CMD_QUEUE | ||
538 | || card->free_slots <= 0) { | ||
539 | dbg("%s - send buffer full please try again %d", | ||
540 | __FUNCTION__, card->free_slots); | ||
541 | retval = CPC_ERR_CAN_NO_TRANSMIT_BUF; | ||
542 | goto exit; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | /* Find a free write urb */ | ||
547 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
548 | if (!atomic_read(&card->wrUrbs[j].busy)) { | ||
549 | wrUrb = &card->wrUrbs[j]; /* remember found URB */ | ||
550 | atomic_set(&wrUrb->busy, 1); /* lock this URB */ | ||
551 | init_completion(&wrUrb->finished); /* init completion */ | ||
552 | dbg("WR URB no. %d started", j); | ||
553 | break; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* don't found write urb say error */ | ||
558 | if (!wrUrb) { | ||
559 | dbg("%s - no free send urb available", __FUNCTION__); | ||
560 | retval = CPC_ERR_CAN_NO_TRANSMIT_BUF; | ||
561 | goto exit; | ||
562 | } | ||
563 | dbg("URB write req"); | ||
564 | |||
565 | obuf = (unsigned char *) wrUrb->urb->transfer_buffer; | ||
566 | |||
567 | /* copy the data from userspace into our transfer buffer; | ||
568 | * this is the only copy required. | ||
569 | */ | ||
570 | if (copy_from_user(&obuf[4], buffer, count) != 0) { | ||
571 | atomic_set(&wrUrb->busy, 0); /* release urb */ | ||
572 | retval = CPC_ERR_IO_TRANSFER; | ||
573 | goto exit; | ||
574 | } | ||
575 | |||
576 | /* check if it is a DRIVER information message, so we can | ||
577 | * response to that message and not the USB | ||
578 | */ | ||
579 | info = (CPC_MSG_T *) & obuf[4]; | ||
580 | |||
581 | bytes_written = 11 + info->length; | ||
582 | if (bytes_written >= wrUrb->size) { | ||
583 | retval = CPC_ERR_IO_TRANSFER; | ||
584 | goto exit; | ||
585 | } | ||
586 | |||
587 | switch (info->type) { | ||
588 | case CPC_CMD_T_CLEAR_MSG_QUEUE: | ||
589 | ResetBuffer(card->chan); | ||
590 | break; | ||
591 | |||
592 | case CPC_CMD_T_INQ_MSG_QUEUE_CNT: | ||
593 | retval = cpc_get_buffer_count(card->chan); | ||
594 | atomic_set(&wrUrb->busy, 0); | ||
595 | |||
596 | goto exit; | ||
597 | |||
598 | case CPC_CMD_T_INQ_INFO: | ||
599 | if (info->msg.info.source == CPC_INFOMSG_T_DRIVER) { | ||
600 | /* release urb cause we'll use it for driver | ||
601 | * information | ||
602 | */ | ||
603 | atomic_set(&wrUrb->busy, 0); | ||
604 | if (IsBufferFull(card->chan)) { | ||
605 | retval = CPC_ERR_IO_TRANSFER; | ||
606 | goto exit; | ||
607 | } | ||
608 | |||
609 | /* it is a driver information request message and we have | ||
610 | * free rx slots to store the response | ||
611 | */ | ||
612 | type = info->msg.info.type; | ||
613 | info = &card->chan->buf[card->chan->iidx]; | ||
614 | |||
615 | info->type = CPC_MSG_T_INFO; | ||
616 | info->msg.info.source = CPC_INFOMSG_T_DRIVER; | ||
617 | info->msg.info.type = type; | ||
618 | |||
619 | switch (type) { | ||
620 | case CPC_INFOMSG_T_VERSION: | ||
621 | info->length = strlen(CPC_DRIVER_VERSION) + 2; | ||
622 | sprintf(info->msg.info.msg, "%s\n", | ||
623 | CPC_DRIVER_VERSION); | ||
624 | break; | ||
625 | |||
626 | case CPC_INFOMSG_T_SERIAL: | ||
627 | info->length = strlen(CPC_DRIVER_SERIAL) + 2; | ||
628 | sprintf(info->msg.info.msg, "%s\n", | ||
629 | CPC_DRIVER_SERIAL); | ||
630 | break; | ||
631 | |||
632 | default: | ||
633 | info->length = 2; | ||
634 | info->msg.info.type = | ||
635 | CPC_INFOMSG_T_UNKNOWN_TYPE; | ||
636 | } | ||
637 | |||
638 | card->chan->WnR = 0; | ||
639 | card->chan->iidx = | ||
640 | (card->chan->iidx + 1) % CPC_MSG_BUF_CNT; | ||
641 | |||
642 | retval = info->length; | ||
643 | goto exit; | ||
644 | } | ||
645 | break; | ||
646 | case CPC_CMD_T_CAN_PRMS: | ||
647 | /* Check the controller type. If it's the new CPC-USB, make sure if these are SJA1000 params */ | ||
648 | if (info->msg.canparams.cc_type != SJA1000 | ||
649 | && info->msg.canparams.cc_type != M16C_BASIC | ||
650 | && (card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID | ||
651 | && info->msg.canparams.cc_type != SJA1000)) { | ||
652 | /* don't forget to release the urb */ | ||
653 | atomic_set(&wrUrb->busy, 0); | ||
654 | retval = CPC_ERR_WRONG_CONTROLLER_TYPE; | ||
655 | goto exit; | ||
656 | } | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | /* just convert the params if it is an old CPC-USB with M16C controller */ | ||
661 | if (card->productId == USB_CPCUSB_M16C_PRODUCT_ID) { | ||
662 | /* if it is a parameter message convert it from SJA1000 controller | ||
663 | * settings to M16C Basic controller settings | ||
664 | */ | ||
665 | SJA1000_TO_M16C_BASIC_Params((CPC_MSG_T *) & obuf[4]); | ||
666 | } | ||
667 | |||
668 | /* don't forget the byte alignment */ | ||
669 | cpcusb_align_buffer_alignment(&obuf[4]); | ||
670 | |||
671 | /* setup a the 4 byte header */ | ||
672 | obuf[0] = obuf[1] = obuf[2] = obuf[3] = 0; | ||
673 | |||
674 | /* this urb was already set up, except for this write size */ | ||
675 | wrUrb->urb->transfer_buffer_length = bytes_written + 4; | ||
676 | |||
677 | /* send the data out the bulk port */ | ||
678 | /* a character device write uses GFP_KERNEL, | ||
679 | unless a spinlock is held */ | ||
680 | retval = usb_submit_urb(wrUrb->urb, GFP_KERNEL); | ||
681 | if (retval) { | ||
682 | atomic_set(&wrUrb->busy, 0); /* release urb */ | ||
683 | err("%s - failed submitting write urb, error %d", | ||
684 | __FUNCTION__, retval); | ||
685 | } else { | ||
686 | retval = bytes_written; | ||
687 | } | ||
688 | |||
689 | exit: | ||
690 | /* unlock the device */ | ||
691 | up(&card->sem); | ||
692 | |||
693 | dbg("%s - leaved", __FUNCTION__); | ||
694 | |||
695 | return retval; | ||
696 | } | ||
697 | |||
698 | /* | ||
699 | * callback for interrupt IN urb | ||
700 | */ | ||
701 | static void cpcusb_read_interrupt_callback(struct urb *urb | ||
702 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
703 | , struct pt_regs *regs | ||
704 | #endif | ||
705 | ) | ||
706 | { | ||
707 | CPC_USB_T *card = (CPC_USB_T *) urb->context; | ||
708 | int retval; | ||
709 | unsigned long flags; | ||
710 | |||
711 | spin_lock_irqsave(&card->slock, flags); | ||
712 | |||
713 | if (!card->present) { | ||
714 | spin_unlock_irqrestore(&card->slock, flags); | ||
715 | info("%s - no such device", __FUNCTION__); | ||
716 | return; | ||
717 | } | ||
718 | |||
719 | switch (urb->status) { | ||
720 | case 0: /* success */ | ||
721 | card->free_slots = card->intr_in_buffer[1]; | ||
722 | break; | ||
723 | case -ECONNRESET: | ||
724 | case -ENOENT: | ||
725 | case -ESHUTDOWN: | ||
726 | /* urb was killed */ | ||
727 | spin_unlock_irqrestore(&card->slock, flags); | ||
728 | dbg("%s - intr urb killed", __FUNCTION__); | ||
729 | return; | ||
730 | default: | ||
731 | info("%s - nonzero urb status %d", __FUNCTION__, urb->status); | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
736 | if (retval) { | ||
737 | err("%s - failed resubmitting intr urb, error %d", | ||
738 | __FUNCTION__, retval); | ||
739 | } | ||
740 | |||
741 | spin_unlock_irqrestore(&card->slock, flags); | ||
742 | wake_up_interruptible(card->chan->CPCWait_q); | ||
743 | |||
744 | return; | ||
745 | } | ||
746 | |||
747 | #define UN_SHIFT 1 | ||
748 | #define CPCMSG_HEADER_LEN_FIRMWARE 11 | ||
749 | static int inline cpcusb_unalign_and_copy_buffy(unsigned char *out, | ||
750 | unsigned char *in) | ||
751 | { | ||
752 | unsigned int i, j; | ||
753 | |||
754 | for (i = 0; i < 3; i++) { | ||
755 | out[i] = in[i]; | ||
756 | } | ||
757 | |||
758 | for (j = 0; j < (in[1] + (CPCMSG_HEADER_LEN_FIRMWARE - 3)); j++) { | ||
759 | out[j + i + UN_SHIFT] = in[j + i]; | ||
760 | } | ||
761 | |||
762 | return i + j; | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * callback for bulk IN urb | ||
767 | */ | ||
768 | static void cpcusb_read_bulk_callback(struct urb *urb | ||
769 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
770 | , struct pt_regs *regs | ||
771 | #endif | ||
772 | ) | ||
773 | { | ||
774 | CPC_USB_T *card = (CPC_USB_T *) urb->context; | ||
775 | CPC_CHAN_T *chan; | ||
776 | unsigned char *ibuf = urb->transfer_buffer; | ||
777 | int retval, msgCnt, start, again = 0; | ||
778 | unsigned long flags; | ||
779 | |||
780 | if (!card) { | ||
781 | err("%s - device object lost", __FUNCTION__); | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | spin_lock_irqsave(&card->slock, flags); | ||
786 | |||
787 | if (!card->present) { | ||
788 | spin_unlock_irqrestore(&card->slock, flags); | ||
789 | info("%s - no such device", __FUNCTION__); | ||
790 | return; | ||
791 | } | ||
792 | |||
793 | switch (urb->status) { | ||
794 | case 0: /* success */ | ||
795 | break; | ||
796 | case -ECONNRESET: | ||
797 | case -ENOENT: | ||
798 | case -ESHUTDOWN: | ||
799 | /* urb was killed */ | ||
800 | spin_unlock_irqrestore(&card->slock, flags); | ||
801 | dbg("%s - read urb killed", __FUNCTION__); | ||
802 | return; | ||
803 | default: | ||
804 | info("%s - nonzero urb status %d", __FUNCTION__, urb->status); | ||
805 | break; | ||
806 | } | ||
807 | |||
808 | if (urb->actual_length) { | ||
809 | msgCnt = ibuf[0] & ~0x80; | ||
810 | again = ibuf[0] & 0x80; | ||
811 | |||
812 | /* we have a 4 byte header */ | ||
813 | start = 4; | ||
814 | chan = card->chan; | ||
815 | while (msgCnt) { | ||
816 | if (!(IsBufferFull(card->chan))) { | ||
817 | start += | ||
818 | cpcusb_unalign_and_copy_buffy((unsigned char *) | ||
819 | &chan->buf[chan->iidx], &ibuf[start]); | ||
820 | |||
821 | if (start > urb->transfer_buffer_length) { | ||
822 | err("%d > %d", start, urb->transfer_buffer_length); | ||
823 | break; | ||
824 | } | ||
825 | |||
826 | chan->WnR = 0; | ||
827 | chan->iidx = (chan->iidx + 1) % CPC_MSG_BUF_CNT; | ||
828 | msgCnt--; | ||
829 | } else { | ||
830 | break; | ||
831 | } | ||
832 | } | ||
833 | } | ||
834 | |||
835 | usb_fill_bulk_urb(urb, card->udev, | ||
836 | usb_rcvbulkpipe(card->udev, card->num_bulk_in), | ||
837 | urb->transfer_buffer, | ||
838 | urb->transfer_buffer_length, | ||
839 | cpcusb_read_bulk_callback, card); | ||
840 | |||
841 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
842 | |||
843 | if (retval) { | ||
844 | err("%s - failed resubmitting read urb, error %d", __FUNCTION__, retval); | ||
845 | } | ||
846 | |||
847 | spin_unlock_irqrestore(&card->slock, flags); | ||
848 | |||
849 | wake_up_interruptible(card->chan->CPCWait_q); | ||
850 | } | ||
851 | |||
852 | /* | ||
853 | * callback for bulk IN urb | ||
854 | */ | ||
855 | static void cpcusb_write_bulk_callback(struct urb *urb | ||
856 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) | ||
857 | , struct pt_regs *regs | ||
858 | #endif | ||
859 | ) | ||
860 | { | ||
861 | CPC_USB_T *card = (CPC_USB_T *) urb->context; | ||
862 | unsigned long flags; | ||
863 | int j; | ||
864 | |||
865 | spin_lock_irqsave(&card->slock, flags); | ||
866 | |||
867 | /* find this urb */ | ||
868 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
869 | if (card->wrUrbs[j].urb == urb) { | ||
870 | dbg("URB found no. %d", j); | ||
871 | /* notify anyone waiting that the write has finished */ | ||
872 | complete(&card->wrUrbs[j].finished); | ||
873 | atomic_set(&card->wrUrbs[j].busy, 0); | ||
874 | break; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | switch (urb->status) { | ||
879 | case 0: /* success */ | ||
880 | break; | ||
881 | case -ECONNRESET: | ||
882 | case -ENOENT: | ||
883 | case -ESHUTDOWN: | ||
884 | /* urb was killed */ | ||
885 | spin_unlock_irqrestore(&card->slock, flags); | ||
886 | dbg("%s - write urb no. %d killed", __FUNCTION__, j); | ||
887 | return; | ||
888 | default: | ||
889 | info("%s - nonzero urb status %d", __FUNCTION__, urb->status); | ||
890 | break; | ||
891 | } | ||
892 | |||
893 | spin_unlock_irqrestore(&card->slock, flags); | ||
894 | |||
895 | wake_up_interruptible(card->chan->CPCWait_q); | ||
896 | } | ||
897 | |||
898 | static inline int cpcusb_get_free_slot(void) | ||
899 | { | ||
900 | int i; | ||
901 | |||
902 | for (i = 0; i < CPC_USB_CARD_CNT; i++) { | ||
903 | if (!CPCUSB_Table[i]) | ||
904 | return i; | ||
905 | } | ||
906 | |||
907 | return -1; | ||
908 | } | ||
909 | |||
910 | /* | ||
911 | * probe function for new CPC-USB devices | ||
912 | */ | ||
913 | static int cpcusb_probe(struct usb_interface *interface, | ||
914 | const struct usb_device_id *id) | ||
915 | { | ||
916 | CPC_USB_T *card = NULL; | ||
917 | CPC_CHAN_T *chan = NULL; | ||
918 | |||
919 | struct usb_device *udev = interface_to_usbdev(interface); | ||
920 | struct usb_host_interface *iface_desc; | ||
921 | struct usb_endpoint_descriptor *endpoint; | ||
922 | |||
923 | int i, j, retval = -ENOMEM, slot; | ||
924 | |||
925 | if ((slot = cpcusb_get_free_slot()) < 0) { | ||
926 | info("No more devices supported"); | ||
927 | return -ENOMEM; | ||
928 | } | ||
929 | |||
930 | /* allocate memory for our device state and initialize it */ | ||
931 | card = kzalloc(sizeof(CPC_USB_T), GFP_KERNEL); | ||
932 | if (!card) { | ||
933 | err("Out of memory"); | ||
934 | return -ENOMEM; | ||
935 | } | ||
936 | CPCUSB_Table[slot] = card; | ||
937 | |||
938 | /* allocate and initialize the channel struct */ | ||
939 | card->chan = kmalloc(sizeof(CPC_CHAN_T), GFP_KERNEL); | ||
940 | if (!card) { | ||
941 | kfree(card); | ||
942 | err("Out of memory"); | ||
943 | return -ENOMEM; | ||
944 | } | ||
945 | |||
946 | chan = card->chan; | ||
947 | memset(chan, 0, sizeof(CPC_CHAN_T)); | ||
948 | ResetBuffer(chan); | ||
949 | |||
950 | init_MUTEX(&card->sem); | ||
951 | spin_lock_init(&card->slock); | ||
952 | |||
953 | card->udev = udev; | ||
954 | card->interface = interface; | ||
955 | if (udev->descriptor.iSerialNumber) { | ||
956 | usb_string(udev, udev->descriptor.iSerialNumber, card->serialNumber, | ||
957 | 128); | ||
958 | info("Serial %s", card->serialNumber); | ||
959 | } | ||
960 | |||
961 | card->productId = udev->descriptor.idProduct; | ||
962 | info("Product %s", | ||
963 | card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID ? | ||
964 | "CPC-USB/ARM7" : "CPC-USB/M16C"); | ||
965 | |||
966 | /* set up the endpoint information */ | ||
967 | /* check out the endpoints */ | ||
968 | /* use only the first bulk-in and bulk-out endpoints */ | ||
969 | iface_desc = &interface->altsetting[0]; | ||
970 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | ||
971 | endpoint = &iface_desc->endpoint[i].desc; | ||
972 | |||
973 | if (!card->num_intr_in && | ||
974 | (endpoint->bEndpointAddress & USB_DIR_IN) && | ||
975 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
976 | == USB_ENDPOINT_XFER_INT)) { | ||
977 | card->intr_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
978 | card->num_intr_in = 1; | ||
979 | |||
980 | if (!card->intr_in_urb) { | ||
981 | err("No free urbs available"); | ||
982 | goto error; | ||
983 | } | ||
984 | |||
985 | dbg("intr_in urb %d", card->num_intr_in); | ||
986 | } | ||
987 | |||
988 | if (!card->num_bulk_in && | ||
989 | (endpoint->bEndpointAddress & USB_DIR_IN) && | ||
990 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
991 | == USB_ENDPOINT_XFER_BULK)) { | ||
992 | card->num_bulk_in = 2; | ||
993 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
994 | card->urbs[j].size = endpoint->wMaxPacketSize; | ||
995 | card->urbs[j].urb = usb_alloc_urb(0, GFP_KERNEL); | ||
996 | if (!card->urbs[j].urb) { | ||
997 | err("No free urbs available"); | ||
998 | goto error; | ||
999 | } | ||
1000 | card->urbs[j].buffer = | ||
1001 | usb_buffer_alloc(udev, | ||
1002 | card->urbs[j].size, | ||
1003 | GFP_KERNEL, | ||
1004 | &card->urbs[j].urb->transfer_dma); | ||
1005 | if (!card->urbs[j].buffer) { | ||
1006 | err("Couldn't allocate bulk_in_buffer"); | ||
1007 | goto error; | ||
1008 | } | ||
1009 | } | ||
1010 | info("%s - %d reading URB's allocated", | ||
1011 | __FUNCTION__, CPC_USB_URB_CNT); | ||
1012 | } | ||
1013 | |||
1014 | if (!card->num_bulk_out && | ||
1015 | !(endpoint->bEndpointAddress & USB_DIR_IN) && | ||
1016 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
1017 | == USB_ENDPOINT_XFER_BULK)) { | ||
1018 | |||
1019 | card->num_bulk_out = 2; | ||
1020 | |||
1021 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
1022 | card->wrUrbs[j].size = | ||
1023 | endpoint->wMaxPacketSize; | ||
1024 | card->wrUrbs[j].urb = | ||
1025 | usb_alloc_urb(0, GFP_KERNEL); | ||
1026 | if (!card->wrUrbs[j].urb) { | ||
1027 | err("No free urbs available"); | ||
1028 | goto error; | ||
1029 | } | ||
1030 | card->wrUrbs[j].buffer = usb_buffer_alloc(udev, | ||
1031 | card->wrUrbs[j].size, GFP_KERNEL, | ||
1032 | &card->wrUrbs[j].urb->transfer_dma); | ||
1033 | |||
1034 | if (!card->wrUrbs[j].buffer) { | ||
1035 | err("Couldn't allocate bulk_out_buffer"); | ||
1036 | goto error; | ||
1037 | } | ||
1038 | |||
1039 | usb_fill_bulk_urb(card->wrUrbs[j].urb, udev, | ||
1040 | usb_sndbulkpipe(udev, endpoint->bEndpointAddress), | ||
1041 | card->wrUrbs[j].buffer, | ||
1042 | card->wrUrbs[j].size, | ||
1043 | cpcusb_write_bulk_callback, | ||
1044 | card); | ||
1045 | } | ||
1046 | |||
1047 | info("%s - %d writing URB's allocated", __FUNCTION__, CPC_USB_URB_CNT); | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | if (!(card->num_bulk_in && card->num_bulk_out)) { | ||
1052 | err("Couldn't find both bulk-in and bulk-out endpoints"); | ||
1053 | goto error; | ||
1054 | } | ||
1055 | |||
1056 | /* allow device read, write and ioctl */ | ||
1057 | card->present = 1; | ||
1058 | |||
1059 | /* we can register the device now, as it is ready */ | ||
1060 | usb_set_intfdata(interface, card); | ||
1061 | retval = usb_register_dev(interface, &cpcusb_class); | ||
1062 | |||
1063 | if (retval) { | ||
1064 | /* something prevented us from registering this driver */ | ||
1065 | err("Not able to get a minor for this device."); | ||
1066 | usb_set_intfdata(interface, NULL); | ||
1067 | goto error; | ||
1068 | } | ||
1069 | |||
1070 | card->chan->minor = card->minor = interface->minor; | ||
1071 | |||
1072 | chan->buf = vmalloc(sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT); | ||
1073 | if (chan->buf == NULL) { | ||
1074 | err("Out of memory"); | ||
1075 | retval = -ENOMEM; | ||
1076 | goto error; | ||
1077 | } | ||
1078 | info("Allocated memory for %d messages (%d kbytes)", | ||
1079 | CPC_MSG_BUF_CNT, (sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT) / 1000); | ||
1080 | memset(chan->buf, 0, sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT); | ||
1081 | |||
1082 | ResetBuffer(chan); | ||
1083 | |||
1084 | card->chan->CPCWait_q = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | ||
1085 | if (!card->chan->CPCWait_q) { | ||
1086 | err("Out of memory"); | ||
1087 | retval = -ENOMEM; | ||
1088 | goto error; | ||
1089 | } | ||
1090 | init_waitqueue_head(card->chan->CPCWait_q); | ||
1091 | |||
1092 | CPCUSB_Table[slot] = card; | ||
1093 | card->idx = slot; | ||
1094 | CPCUsbCnt++; | ||
1095 | |||
1096 | /* let the user know what node this device is now attached to */ | ||
1097 | info("Device now attached to USB-%d", card->minor); | ||
1098 | return 0; | ||
1099 | |||
1100 | error: | ||
1101 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
1102 | if (card->urbs[j].buffer) { | ||
1103 | usb_buffer_free(card->udev, card->urbs[j].size, | ||
1104 | card->urbs[j].buffer, | ||
1105 | card->urbs[j].urb->transfer_dma); | ||
1106 | card->urbs[j].buffer = NULL; | ||
1107 | } | ||
1108 | if (card->urbs[j].urb) { | ||
1109 | usb_free_urb(card->urbs[j].urb); | ||
1110 | card->urbs[j].urb = NULL; | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | cpcusb_delete(card); | ||
1115 | return retval; | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | * called by the usb core when the device is removed from the system | ||
1120 | */ | ||
1121 | static void cpcusb_disconnect(struct usb_interface *interface) | ||
1122 | { | ||
1123 | CPC_USB_T *card = NULL; | ||
1124 | int minor, j; | ||
1125 | |||
1126 | /* prevent races with open() */ | ||
1127 | down(&disconnect_sem); | ||
1128 | |||
1129 | card = usb_get_intfdata(interface); | ||
1130 | usb_set_intfdata(interface, NULL); | ||
1131 | |||
1132 | down(&card->sem); | ||
1133 | |||
1134 | /* prevent device read, write and ioctl */ | ||
1135 | card->present = 0; | ||
1136 | |||
1137 | minor = card->minor; | ||
1138 | |||
1139 | /* free all urbs and their buffers */ | ||
1140 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
1141 | /* terminate an ongoing write */ | ||
1142 | if (atomic_read(&card->wrUrbs[j].busy)) { | ||
1143 | usb_kill_urb(card->wrUrbs[j].urb); | ||
1144 | wait_for_completion(&card->wrUrbs[j].finished); | ||
1145 | } | ||
1146 | usb_buffer_free(card->udev, card->wrUrbs[j].size, | ||
1147 | card->wrUrbs[j].buffer, | ||
1148 | card->wrUrbs[j].urb->transfer_dma); | ||
1149 | usb_free_urb(card->wrUrbs[j].urb); | ||
1150 | } | ||
1151 | info("%d write URBs freed", CPC_USB_URB_CNT); | ||
1152 | |||
1153 | /* free all urbs and their buffers */ | ||
1154 | for (j = 0; j < CPC_USB_URB_CNT; j++) { | ||
1155 | usb_buffer_free(card->udev, card->urbs[j].size, | ||
1156 | card->urbs[j].buffer, | ||
1157 | card->urbs[j].urb->transfer_dma); | ||
1158 | usb_free_urb(card->urbs[j].urb); | ||
1159 | } | ||
1160 | info("%d read URBs freed", CPC_USB_URB_CNT); | ||
1161 | usb_free_urb(card->intr_in_urb); | ||
1162 | |||
1163 | /* give back our minor */ | ||
1164 | usb_deregister_dev(interface, &cpcusb_class); | ||
1165 | |||
1166 | up(&card->sem); | ||
1167 | |||
1168 | /* if the device is opened, cpcusb_release will clean this up */ | ||
1169 | if (!card->open) | ||
1170 | cpcusb_delete(card); | ||
1171 | else | ||
1172 | wake_up_interruptible(card->chan->CPCWait_q); | ||
1173 | |||
1174 | up(&disconnect_sem); | ||
1175 | |||
1176 | CPCUsbCnt--; | ||
1177 | info("USB-%d now disconnected", minor); | ||
1178 | } | ||
1179 | |||
1180 | static int __init CPCUsb_Init(void) | ||
1181 | { | ||
1182 | int result, i; | ||
1183 | |||
1184 | info(DRIVER_DESC " v" DRIVER_VERSION); | ||
1185 | info("Build on " __DATE__ " at " __TIME__); | ||
1186 | |||
1187 | for (i = 0; i < CPC_USB_CARD_CNT; i++) | ||
1188 | CPCUSB_Table[i] = 0; | ||
1189 | |||
1190 | /* register this driver with the USB subsystem */ | ||
1191 | result = usb_register(&cpcusb_driver); | ||
1192 | if (result) { | ||
1193 | err("usb_register failed. Error number %d", result); | ||
1194 | return result; | ||
1195 | } | ||
1196 | |||
1197 | procDir = proc_mkdir(CPC_USB_PROC_DIR, NULL); | ||
1198 | if (!procDir) { | ||
1199 | err("Could not create proc entry"); | ||
1200 | } else { | ||
1201 | procDir->owner = THIS_MODULE; | ||
1202 | procEntry = create_proc_read_entry("info", 0444, procDir, | ||
1203 | cpcusb_proc_read_info, | ||
1204 | NULL); | ||
1205 | if (!procEntry) { | ||
1206 | err("Could not create proc entry %s", CPC_USB_PROC_DIR "/info"); | ||
1207 | remove_proc_entry(CPC_USB_PROC_DIR, NULL); | ||
1208 | procDir = NULL; | ||
1209 | } else { | ||
1210 | procEntry->owner = THIS_MODULE; | ||
1211 | } | ||
1212 | } | ||
1213 | |||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static void __exit CPCUsb_Exit(void) | ||
1218 | { | ||
1219 | wait_event(rmmodWq, !atomic_read(&useCount)); | ||
1220 | |||
1221 | /* deregister this driver with the USB subsystem */ | ||
1222 | usb_deregister(&cpcusb_driver); | ||
1223 | |||
1224 | if (procDir) { | ||
1225 | if (procEntry) | ||
1226 | remove_proc_entry("info", procDir); | ||
1227 | remove_proc_entry(CPC_USB_PROC_DIR, NULL); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | module_init(CPCUsb_Init); | ||
1232 | module_exit(CPCUsb_Exit); | ||
diff --git a/drivers/staging/cpc-usb/cpc.h b/drivers/staging/cpc-usb/cpc.h new file mode 100644 index 000000000000..ed8cb34d4763 --- /dev/null +++ b/drivers/staging/cpc-usb/cpc.h | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * CPC CAN Interface Definitions | ||
3 | * | ||
4 | * Copyright (C) 2000-2008 EMS Dr. Thomas Wuensche | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, but | ||
7 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
9 | */ | ||
10 | #ifndef CPC_HEADER | ||
11 | #define CPC_HEADER | ||
12 | |||
13 | // the maximum length of the union members within a CPC_MSG | ||
14 | // this value can be defined by the customer, but has to be | ||
15 | // >= 64 bytes | ||
16 | // however, if not defined before, we set a length of 64 byte | ||
17 | #if !defined(CPC_MSG_LEN) || (CPC_MSG_LEN < 64) | ||
18 | #undef CPC_MSG_LEN | ||
19 | #define CPC_MSG_LEN 64 | ||
20 | #endif | ||
21 | |||
22 | // check the operating system used | ||
23 | #ifdef _WIN32 // running a Windows OS | ||
24 | |||
25 | // define basic types on Windows platforms | ||
26 | #ifdef _MSC_VER // Visual Studio | ||
27 | typedef unsigned __int8 u8; | ||
28 | typedef unsigned __int16 u16; | ||
29 | typedef unsigned __int32 u32; | ||
30 | #else // Borland Compiler | ||
31 | typedef unsigned char u8; | ||
32 | typedef unsigned short u16; | ||
33 | typedef unsigned int u32; | ||
34 | #endif | ||
35 | // on Windows OS we use a byte alignment of 1 | ||
36 | #pragma pack(push, 1) | ||
37 | |||
38 | // set the calling conventions for the library function calls | ||
39 | #define CALL_CONV __stdcall | ||
40 | #else | ||
41 | // Kernel headers already define this types | ||
42 | #ifndef __KERNEL__ | ||
43 | // define basic types | ||
44 | typedef unsigned char u8; | ||
45 | typedef unsigned short u16; | ||
46 | typedef unsigned int u32; | ||
47 | #endif | ||
48 | |||
49 | // Linux does not use this calling convention | ||
50 | #define CALL_CONV | ||
51 | #endif | ||
52 | |||
53 | // Transmission of events from CPC interfaces to PC can be individually | ||
54 | // controlled per event type. Default state is: don't transmit | ||
55 | // Control values are constructed by bit-or of Subject and Action | ||
56 | // and passed to CPC_Control() | ||
57 | |||
58 | // Control-Values for CPC_Control() Command Subject Selection | ||
59 | #define CONTR_CAN_Message 0x04 | ||
60 | #define CONTR_Busload 0x08 | ||
61 | #define CONTR_CAN_State 0x0C | ||
62 | #define CONTR_SendAck 0x10 | ||
63 | #define CONTR_Filter 0x14 | ||
64 | #define CONTR_CmdQueue 0x18 // reserved, do not use | ||
65 | #define CONTR_BusError 0x1C | ||
66 | |||
67 | // Control Command Actions | ||
68 | #define CONTR_CONT_OFF 0 | ||
69 | #define CONTR_CONT_ON 1 | ||
70 | #define CONTR_SING_ON 2 | ||
71 | // CONTR_SING_ON doesn't change CONTR_CONT_ON state, so it should be | ||
72 | // read as: transmit at least once | ||
73 | |||
74 | // defines for confirmed request | ||
75 | #define DO_NOT_CONFIRM 0 | ||
76 | #define DO_CONFIRM 1 | ||
77 | |||
78 | // event flags | ||
79 | #define EVENT_READ 0x01 | ||
80 | #define EVENT_WRITE 0x02 | ||
81 | |||
82 | // Messages from CPC to PC contain a message object type field. | ||
83 | // The following message types are sent by CPC and can be used in | ||
84 | // handlers, others should be ignored. | ||
85 | #define CPC_MSG_T_RESYNC 0 // Normally to be ignored | ||
86 | #define CPC_MSG_T_CAN 1 // CAN data frame | ||
87 | #define CPC_MSG_T_BUSLOAD 2 // Busload message | ||
88 | #define CPC_MSG_T_STRING 3 // Normally to be ignored | ||
89 | #define CPC_MSG_T_CONTI 4 // Normally to be ignored | ||
90 | #define CPC_MSG_T_MEM 7 // Normally not to be handled | ||
91 | #define CPC_MSG_T_RTR 8 // CAN remote frame | ||
92 | #define CPC_MSG_T_TXACK 9 // Send acknowledge | ||
93 | #define CPC_MSG_T_POWERUP 10 // Power-up message | ||
94 | #define CPC_MSG_T_CMD_NO 11 // Normally to be ignored | ||
95 | #define CPC_MSG_T_CAN_PRMS 12 // Actual CAN parameters | ||
96 | #define CPC_MSG_T_ABORTED 13 // Command aborted message | ||
97 | #define CPC_MSG_T_CANSTATE 14 // CAN state message | ||
98 | #define CPC_MSG_T_RESET 15 // used to reset CAN-Controller | ||
99 | #define CPC_MSG_T_XCAN 16 // XCAN data frame | ||
100 | #define CPC_MSG_T_XRTR 17 // XCAN remote frame | ||
101 | #define CPC_MSG_T_INFO 18 // information strings | ||
102 | #define CPC_MSG_T_CONTROL 19 // used for control of interface/driver behaviour | ||
103 | #define CPC_MSG_T_CONFIRM 20 // response type for confirmed requests | ||
104 | #define CPC_MSG_T_OVERRUN 21 // response type for overrun conditions | ||
105 | #define CPC_MSG_T_KEEPALIVE 22 // response type for keep alive conditions | ||
106 | #define CPC_MSG_T_CANERROR 23 // response type for bus error conditions | ||
107 | #define CPC_MSG_T_DISCONNECTED 24 // response type for a disconnected interface | ||
108 | #define CPC_MSG_T_ERR_COUNTER 25 // RX/TX error counter of CAN controller | ||
109 | |||
110 | #define CPC_MSG_T_FIRMWARE 100 // response type for USB firmware download | ||
111 | |||
112 | // Messages from the PC to the CPC interface contain a command field | ||
113 | // Most of the command types are wrapped by the library functions and have therefore | ||
114 | // normally not to be used. | ||
115 | // However, programmers who wish to circumvent the library and talk directly | ||
116 | // to the drivers (mainly Linux programmers) can use the following | ||
117 | // command types: | ||
118 | |||
119 | #define CPC_CMD_T_CAN 1 // CAN data frame | ||
120 | #define CPC_CMD_T_CONTROL 3 // used for control of interface/driver behaviour | ||
121 | #define CPC_CMD_T_CAN_PRMS 6 // set CAN parameters | ||
122 | #define CPC_CMD_T_CLEARBUF 8 // clears input queue; this is depricated, use CPC_CMD_T_CLEAR_MSG_QUEUE instead | ||
123 | #define CPC_CMD_T_INQ_CAN_PARMS 11 // inquire actual CAN parameters | ||
124 | #define CPC_CMD_T_FILTER_PRMS 12 // set filter parameter | ||
125 | #define CPC_CMD_T_RTR 13 // CAN remote frame | ||
126 | #define CPC_CMD_T_CANSTATE 14 // CAN state message | ||
127 | #define CPC_CMD_T_XCAN 15 // XCAN data frame | ||
128 | #define CPC_CMD_T_XRTR 16 // XCAN remote frame | ||
129 | #define CPC_CMD_T_RESET 17 // used to reset CAN-Controller | ||
130 | #define CPC_CMD_T_INQ_INFO 18 // miscellanous information strings | ||
131 | #define CPC_CMD_T_OPEN_CHAN 19 // open a channel | ||
132 | #define CPC_CMD_T_CLOSE_CHAN 20 // close a channel | ||
133 | #define CPC_CMD_T_CNTBUF 21 // this is depricated, use CPC_CMD_T_INQ_MSG_QUEUE_CNT instead | ||
134 | #define CPC_CMD_T_CAN_EXIT 200 // exit the CAN (disable interrupts; reset bootrate; reset output_cntr; mode = 1) | ||
135 | |||
136 | #define CPC_CMD_T_INQ_MSG_QUEUE_CNT CPC_CMD_T_CNTBUF // inquires the count of elements in the message queue | ||
137 | #define CPC_CMD_T_INQ_ERR_COUNTER 25 // request the CAN controllers error counter | ||
138 | #define CPC_CMD_T_CLEAR_MSG_QUEUE CPC_CMD_T_CLEARBUF // clear CPC_MSG queue | ||
139 | #define CPC_CMD_T_CLEAR_CMD_QUEUE 28 // clear CPC_CMD queue | ||
140 | #define CPC_CMD_T_FIRMWARE 100 // reserved, must not be used | ||
141 | #define CPC_CMD_T_USB_RESET 101 // reserved, must not be used | ||
142 | #define CPC_CMD_T_WAIT_NOTIFY 102 // reserved, must not be used | ||
143 | #define CPC_CMD_T_WAIT_SETUP 103 // reserved, must not be used | ||
144 | #define CPC_CMD_T_ABORT 255 // Normally not to be used | ||
145 | |||
146 | // definitions for CPC_MSG_T_INFO | ||
147 | // information sources | ||
148 | #define CPC_INFOMSG_T_UNKNOWN_SOURCE 0 | ||
149 | #define CPC_INFOMSG_T_INTERFACE 1 | ||
150 | #define CPC_INFOMSG_T_DRIVER 2 | ||
151 | #define CPC_INFOMSG_T_LIBRARY 3 | ||
152 | |||
153 | // information types | ||
154 | #define CPC_INFOMSG_T_UNKNOWN_TYPE 0 | ||
155 | #define CPC_INFOMSG_T_VERSION 1 | ||
156 | #define CPC_INFOMSG_T_SERIAL 2 | ||
157 | |||
158 | // definitions for controller types | ||
159 | #define PCA82C200 1 // Philips basic CAN controller, replaced by SJA1000 | ||
160 | #define SJA1000 2 // Philips basic CAN controller | ||
161 | #define AN82527 3 // Intel full CAN controller | ||
162 | #define M16C_BASIC 4 // M16C controller running in basic CAN (not full CAN) mode | ||
163 | |||
164 | // channel open error codes | ||
165 | #define CPC_ERR_NO_FREE_CHANNEL -1 // no more free space within the channel array | ||
166 | #define CPC_ERR_CHANNEL_ALREADY_OPEN -2 // the channel is already open | ||
167 | #define CPC_ERR_CHANNEL_NOT_ACTIVE -3 // access to a channel not active failed | ||
168 | #define CPC_ERR_NO_DRIVER_PRESENT -4 // no driver at the location searched by the library | ||
169 | #define CPC_ERR_NO_INIFILE_PRESENT -5 // the library could not find the inifile | ||
170 | #define CPC_ERR_WRONG_PARAMETERS -6 // wrong parameters in the inifile | ||
171 | #define CPC_ERR_NO_INTERFACE_PRESENT -7 // 1. The specified interface is not connected | ||
172 | // 2. The interface (mostly CPC-USB) was disconnected upon operation | ||
173 | #define CPC_ERR_NO_MATCHING_CHANNEL -8 // the driver couldn't find a matching channel | ||
174 | #define CPC_ERR_NO_BUFFER_AVAILABLE -9 // the driver couldn't allocate buffer for messages | ||
175 | #define CPC_ERR_NO_INTERRUPT -10 // the requested interrupt couldn't be claimed | ||
176 | #define CPC_ERR_NO_MATCHING_INTERFACE -11 // no interface type related to this channel was found | ||
177 | #define CPC_ERR_NO_RESOURCES -12 // the requested resources could not be claimed | ||
178 | #define CPC_ERR_SOCKET -13 // error concerning TCP sockets | ||
179 | |||
180 | // init error codes | ||
181 | #define CPC_ERR_WRONG_CONTROLLER_TYPE -14 // wrong CAN controller type within initialization | ||
182 | #define CPC_ERR_NO_RESET_MODE -15 // the controller could not be set into reset mode | ||
183 | #define CPC_ERR_NO_CAN_ACCESS -16 // the CAN controller could not be accessed | ||
184 | |||
185 | // transmit error codes | ||
186 | #define CPC_ERR_CAN_WRONG_ID -20 // the provided CAN id is too big | ||
187 | #define CPC_ERR_CAN_WRONG_LENGTH -21 // the provided CAN length is too long | ||
188 | #define CPC_ERR_CAN_NO_TRANSMIT_BUF -22 // the transmit buffer was occupied | ||
189 | #define CPC_ERR_CAN_TRANSMIT_TIMEOUT -23 // The message could not be sent within a | ||
190 | // specified time | ||
191 | |||
192 | // other error codes | ||
193 | #define CPC_ERR_SERVICE_NOT_SUPPORTED -30 // the requested service is not supported by the interface | ||
194 | #define CPC_ERR_IO_TRANSFER -31 // a transmission error down to the driver occurred | ||
195 | #define CPC_ERR_TRANSMISSION_FAILED -32 // a transmission error down to the interface occurred | ||
196 | #define CPC_ERR_TRANSMISSION_TIMEOUT -33 // a timeout occurred within transmission to the interface | ||
197 | #define CPC_ERR_OP_SYS_NOT_SUPPORTED -35 // the operating system is not supported | ||
198 | #define CPC_ERR_UNKNOWN -40 // an unknown error ocurred (mostly IOCTL errors) | ||
199 | |||
200 | #define CPC_ERR_LOADING_DLL -50 // the library 'cpcwin.dll' could not be loaded | ||
201 | #define CPC_ERR_ASSIGNING_FUNCTION -51 // the specified function could not be assigned | ||
202 | #define CPC_ERR_DLL_INITIALIZATION -52 // the DLL was not initialized correctly | ||
203 | #define CPC_ERR_MISSING_LICFILE -55 // the file containing the licenses does not exist | ||
204 | #define CPC_ERR_MISSING_LICENSE -56 // a required license was not found | ||
205 | |||
206 | // CAN state bit values. Ignore any bits not listed | ||
207 | #define CPC_CAN_STATE_BUSOFF 0x80 | ||
208 | #define CPC_CAN_STATE_ERROR 0x40 | ||
209 | |||
210 | // Mask to help ignore undefined bits | ||
211 | #define CPC_CAN_STATE_MASK 0xc0 | ||
212 | |||
213 | // CAN-Message representation in a CPC_MSG | ||
214 | // Message object type is CPC_MSG_T_CAN or CPC_MSG_T_RTR | ||
215 | // or CPC_MSG_T_XCAN or CPC_MSG_T_XRTR | ||
216 | typedef struct CPC_CAN_MSG { | ||
217 | u32 id; | ||
218 | u8 length; | ||
219 | u8 msg[8]; | ||
220 | } CPC_CAN_MSG_T; | ||
221 | |||
222 | |||
223 | // representation of the CAN parameters for the PCA82C200 controller | ||
224 | typedef struct CPC_PCA82C200_PARAMS { | ||
225 | u8 acc_code; // Acceptance-code for receive, Standard: 0 | ||
226 | u8 acc_mask; // Acceptance-mask for receive, Standard: 0xff (everything) | ||
227 | u8 btr0; // Bus-timing register 0 | ||
228 | u8 btr1; // Bus-timing register 1 | ||
229 | u8 outp_contr; // Output-control register | ||
230 | } CPC_PCA82C200_PARAMS_T; | ||
231 | |||
232 | // representation of the CAN parameters for the SJA1000 controller | ||
233 | typedef struct CPC_SJA1000_PARAMS { | ||
234 | u8 mode; // enables single or dual acceptance filtering | ||
235 | u8 acc_code0; // Acceptance-code for receive, Standard: 0 | ||
236 | u8 acc_code1; | ||
237 | u8 acc_code2; | ||
238 | u8 acc_code3; | ||
239 | u8 acc_mask0; // Acceptance-mask for receive, Standard: 0xff (everything) | ||
240 | u8 acc_mask1; | ||
241 | u8 acc_mask2; | ||
242 | u8 acc_mask3; | ||
243 | u8 btr0; // Bus-timing register 0 | ||
244 | u8 btr1; // Bus-timing register 1 | ||
245 | u8 outp_contr; // Output-control register | ||
246 | } CPC_SJA1000_PARAMS_T; | ||
247 | |||
248 | // representation of the CAN parameters for the M16C controller | ||
249 | // in basic CAN mode (means no full CAN) | ||
250 | typedef struct CPC_M16C_BASIC_PARAMS { | ||
251 | u8 con0; | ||
252 | u8 con1; | ||
253 | u8 ctlr0; | ||
254 | u8 ctlr1; | ||
255 | u8 clk; | ||
256 | u8 acc_std_code0; | ||
257 | u8 acc_std_code1; | ||
258 | u8 acc_ext_code0; | ||
259 | u8 acc_ext_code1; | ||
260 | u8 acc_ext_code2; | ||
261 | u8 acc_ext_code3; | ||
262 | u8 acc_std_mask0; | ||
263 | u8 acc_std_mask1; | ||
264 | u8 acc_ext_mask0; | ||
265 | u8 acc_ext_mask1; | ||
266 | u8 acc_ext_mask2; | ||
267 | u8 acc_ext_mask3; | ||
268 | } CPC_M16C_BASIC_PARAMS_T; | ||
269 | |||
270 | // CAN params message representation | ||
271 | typedef struct CPC_CAN_PARAMS { | ||
272 | u8 cc_type; // represents the controller type | ||
273 | union { | ||
274 | CPC_M16C_BASIC_PARAMS_T m16c_basic; | ||
275 | CPC_SJA1000_PARAMS_T sja1000; | ||
276 | CPC_PCA82C200_PARAMS_T pca82c200; | ||
277 | } cc_params; | ||
278 | } CPC_CAN_PARAMS_T; | ||
279 | |||
280 | // the following structures are slightly different for Windows and Linux | ||
281 | // To be able to use the 'Select' mechanism with Linux the application | ||
282 | // needs to know the devices file desciptor. | ||
283 | // This mechanism is not implemented within Windows and the file descriptor | ||
284 | // is therefore not needed | ||
285 | #ifdef _WIN32 | ||
286 | |||
287 | // CAN init params message representation | ||
288 | typedef struct CPC_INIT_PARAMS { | ||
289 | CPC_CAN_PARAMS_T canparams; | ||
290 | } CPC_INIT_PARAMS_T; | ||
291 | |||
292 | #else// Linux | ||
293 | |||
294 | // CHAN init params representation | ||
295 | typedef struct CPC_CHAN_PARAMS { | ||
296 | int fd; | ||
297 | } CPC_CHAN_PARAMS_T; | ||
298 | |||
299 | // CAN init params message representation | ||
300 | typedef struct CPC_INIT_PARAMS { | ||
301 | CPC_CHAN_PARAMS_T chanparams; | ||
302 | CPC_CAN_PARAMS_T canparams; | ||
303 | } CPC_INIT_PARAMS_T; | ||
304 | |||
305 | #endif | ||
306 | |||
307 | // structure for confirmed message handling | ||
308 | typedef struct CPC_CONFIRM { | ||
309 | u8 result; // error code | ||
310 | } CPC_CONFIRM_T; | ||
311 | |||
312 | // structure for information requests | ||
313 | typedef struct CPC_INFO { | ||
314 | u8 source; // interface, driver or library | ||
315 | u8 type; // version or serial number | ||
316 | char msg[CPC_MSG_LEN - 2]; // string holding the requested information | ||
317 | } CPC_INFO_T; | ||
318 | |||
319 | // OVERRUN /////////////////////////////////////// | ||
320 | // In general two types of overrun may occur. | ||
321 | // A hardware overrun, where the CAN controller | ||
322 | // lost a message, because the interrupt was | ||
323 | // not handled before the next messgae comes in. | ||
324 | // Or a software overrun, where i.e. a received | ||
325 | // message could not be stored in the CPC_MSG | ||
326 | // buffer. | ||
327 | |||
328 | // After a software overrun has occurred | ||
329 | // we wait until we have CPC_OVR_GAP slots | ||
330 | // free in the CPC_MSG buffer. | ||
331 | #define CPC_OVR_GAP 10 | ||
332 | |||
333 | // Two types of software overrun may occur. | ||
334 | // A received CAN message or a CAN state event | ||
335 | // can cause an overrun. | ||
336 | // Note: A CPC_CMD which would normally store | ||
337 | // its result immediately in the CPC_MSG | ||
338 | // queue may fail, because the message queue is full. | ||
339 | // This will not generate an overrun message, but | ||
340 | // will halt command execution, until this command | ||
341 | // is able to store its message in the message queue. | ||
342 | #define CPC_OVR_EVENT_CAN 0x01 | ||
343 | #define CPC_OVR_EVENT_CANSTATE 0x02 | ||
344 | #define CPC_OVR_EVENT_BUSERROR 0x04 | ||
345 | |||
346 | // If the CAN controller lost a message | ||
347 | // we indicate it with the highest bit | ||
348 | // set in the count field. | ||
349 | #define CPC_OVR_HW 0x80 | ||
350 | |||
351 | // structure for overrun conditions | ||
352 | typedef struct { | ||
353 | u8 event; | ||
354 | u8 count; | ||
355 | } CPC_OVERRUN_T; | ||
356 | |||
357 | // CAN errors //////////////////////////////////// | ||
358 | // Each CAN controller type has different | ||
359 | // registers to record errors. | ||
360 | // Therefor a structure containing the specific | ||
361 | // errors is set up for each controller here | ||
362 | |||
363 | // SJA1000 error structure | ||
364 | // see the SJA1000 datasheet for detailed | ||
365 | // explanation of the registers | ||
366 | typedef struct CPC_SJA1000_CAN_ERROR { | ||
367 | u8 ecc; // error capture code register | ||
368 | u8 rxerr; // RX error counter register | ||
369 | u8 txerr; // TX error counter register | ||
370 | } CPC_SJA1000_CAN_ERROR_T; | ||
371 | |||
372 | // M16C error structure | ||
373 | // see the M16C datasheet for detailed | ||
374 | // explanation of the registers | ||
375 | typedef struct CPC_M16C_CAN_ERROR { | ||
376 | u8 tbd; // to be defined | ||
377 | } CPC_M16C_CAN_ERROR_T; | ||
378 | |||
379 | // structure for CAN error conditions | ||
380 | #define CPC_CAN_ECODE_ERRFRAME 0x01 | ||
381 | typedef struct CPC_CAN_ERROR { | ||
382 | u8 ecode; | ||
383 | struct { | ||
384 | u8 cc_type; // CAN controller type | ||
385 | union { | ||
386 | CPC_SJA1000_CAN_ERROR_T sja1000; | ||
387 | CPC_M16C_CAN_ERROR_T m16c; | ||
388 | } regs; | ||
389 | } cc; | ||
390 | } CPC_CAN_ERROR_T; | ||
391 | |||
392 | // Structure containing RX/TX error counter. | ||
393 | // This structure is used to request the | ||
394 | // values of the CAN controllers TX and RX | ||
395 | // error counter. | ||
396 | typedef struct CPC_CAN_ERR_COUNTER { | ||
397 | u8 rx; | ||
398 | u8 tx; | ||
399 | } CPC_CAN_ERR_COUNTER_T; | ||
400 | |||
401 | // If this flag is set, transmissions from PC to CPC are protected against loss | ||
402 | #define CPC_SECURE_TO_CPC 0x01 | ||
403 | |||
404 | // If this flag is set, transmissions from CPC to PC are protected against loss | ||
405 | #define CPC_SECURE_TO_PC 0x02 | ||
406 | |||
407 | // If this flag is set, the CAN-transmit buffer is checked to be free before sending a message | ||
408 | #define CPC_SECURE_SEND 0x04 | ||
409 | |||
410 | // If this flag is set, the transmission complete flag is checked | ||
411 | // after sending a message | ||
412 | // THIS IS CURRENTLY ONLY IMPLEMENTED IN THE PASSIVE INTERFACE DRIVERS | ||
413 | #define CPC_SECURE_TRANSMIT 0x08 | ||
414 | |||
415 | // main message type used between library and application | ||
416 | typedef struct CPC_MSG { | ||
417 | u8 type; // type of message | ||
418 | u8 length; // length of data within union 'msg' | ||
419 | u8 msgid; // confirmation handle | ||
420 | u32 ts_sec; // timestamp in seconds | ||
421 | u32 ts_nsec; // timestamp in nano seconds | ||
422 | union { | ||
423 | u8 generic[CPC_MSG_LEN]; | ||
424 | CPC_CAN_MSG_T canmsg; | ||
425 | CPC_CAN_PARAMS_T canparams; | ||
426 | CPC_CONFIRM_T confirmation; | ||
427 | CPC_INFO_T info; | ||
428 | CPC_OVERRUN_T overrun; | ||
429 | CPC_CAN_ERROR_T error; | ||
430 | CPC_CAN_ERR_COUNTER_T err_counter; | ||
431 | u8 busload; | ||
432 | u8 canstate; | ||
433 | } msg; | ||
434 | } CPC_MSG_T; | ||
435 | |||
436 | #ifdef _WIN32 | ||
437 | #pragma pack(pop) // reset the byte alignment | ||
438 | #endif | ||
439 | |||
440 | #endif // CPC_HEADER | ||
diff --git a/drivers/staging/cpc-usb/cpc_int.h b/drivers/staging/cpc-usb/cpc_int.h new file mode 100644 index 000000000000..dfdbed1c1f96 --- /dev/null +++ b/drivers/staging/cpc-usb/cpc_int.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * CPCLIB | ||
3 | * | ||
4 | * Copyright (C) 2000-2008 EMS Dr. Thomas Wuensche | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, but | ||
7 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
9 | * | ||
10 | */ | ||
11 | #ifndef CPC_INT_H | ||
12 | #define CPC_INT_H | ||
13 | |||
14 | #include <linux/wait.h> | ||
15 | |||
16 | #define CPC_MSG_BUF_CNT 1500 | ||
17 | |||
18 | #ifdef CONFIG_PROC_FS | ||
19 | # define CPC_PROC_DIR "driver/" | ||
20 | #endif | ||
21 | |||
22 | #undef dbg | ||
23 | #undef err | ||
24 | #undef info | ||
25 | |||
26 | /* Use our own dbg macro */ | ||
27 | #define dbg(format, arg...) do { if (debug) printk( KERN_INFO format "\n" , ## arg); } while (0) | ||
28 | #define err(format, arg...) do { printk( KERN_INFO "ERROR " format "\n" , ## arg); } while (0) | ||
29 | #define info(format, arg...) do { printk( KERN_INFO format "\n" , ## arg); } while (0) | ||
30 | |||
31 | /* Macros help using of our buffers */ | ||
32 | #define IsBufferFull(x) (!(x)->WnR) && ((x)->iidx == (x)->oidx) | ||
33 | #define IsBufferEmpty(x) ((x)->WnR) && ((x)->iidx == (x)->oidx) | ||
34 | #define IsBufferNotEmpty(x) (!(x)->WnR) || ((x)->iidx != (x)->oidx) | ||
35 | #define ResetBuffer(x) do { (x)->oidx = (x)->iidx=0; (x)->WnR = 1; } while(0); | ||
36 | |||
37 | #define CPC_BufWriteAllowed ((chan->oidx != chan->iidx) || chan->WnR) | ||
38 | |||
39 | typedef void (*chan_write_byte_t) (void *chan, unsigned int reg, | ||
40 | unsigned char val); | ||
41 | typedef unsigned char (*chan_read_byte_t) (void *chan, unsigned int reg); | ||
42 | |||
43 | typedef struct CPC_CHAN { | ||
44 | void __iomem * canBase; // base address of SJA1000 | ||
45 | chan_read_byte_t read_byte; // CAN controller read access routine | ||
46 | chan_write_byte_t write_byte; // CAN controller write access routine | ||
47 | CPC_MSG_T *buf; // buffer for CPC msg | ||
48 | unsigned int iidx; | ||
49 | unsigned int oidx; | ||
50 | unsigned int WnR; | ||
51 | unsigned int minor; | ||
52 | unsigned int locked; | ||
53 | unsigned int irqDisabled; | ||
54 | |||
55 | unsigned char cpcCtrlCANMessage; | ||
56 | unsigned char cpcCtrlCANState; | ||
57 | unsigned char cpcCtrlBUSState; | ||
58 | |||
59 | unsigned char controllerType; | ||
60 | |||
61 | unsigned long ovrTimeSec; | ||
62 | unsigned long ovrTimeNSec; | ||
63 | unsigned long ovrLockedBuffer; | ||
64 | CPC_OVERRUN_T ovr; | ||
65 | |||
66 | /* for debugging only */ | ||
67 | unsigned int handledIrqs; | ||
68 | unsigned int lostMessages; | ||
69 | |||
70 | unsigned int sentStdCan; | ||
71 | unsigned int sentExtCan; | ||
72 | unsigned int sentStdRtr; | ||
73 | unsigned int sentExtRtr; | ||
74 | |||
75 | unsigned int recvStdCan; | ||
76 | unsigned int recvExtCan; | ||
77 | unsigned int recvStdRtr; | ||
78 | unsigned int recvExtRtr; | ||
79 | |||
80 | wait_queue_head_t *CPCWait_q; | ||
81 | |||
82 | void *private; | ||
83 | } CPC_CHAN_T; | ||
84 | |||
85 | #endif | ||
diff --git a/drivers/staging/cpc-usb/cpcusb.h b/drivers/staging/cpc-usb/cpcusb.h new file mode 100644 index 000000000000..e5273ddd9e0a --- /dev/null +++ b/drivers/staging/cpc-usb/cpcusb.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /* Header for CPC-USB Driver ******************** | ||
2 | * Copyright 1999, 2000, 2001 | ||
3 | * | ||
4 | * Company: EMS Dr. Thomas Wuensche | ||
5 | * Sonnenhang 3 | ||
6 | * 85304 Ilmmuenster | ||
7 | * Phone: +49-8441-490260 | ||
8 | * Fax: +49-8441-81860 | ||
9 | * email: support@ems-wuensche.com | ||
10 | * WWW: www.ems-wuensche.com | ||
11 | */ | ||
12 | |||
13 | #ifndef CPCUSB_H | ||
14 | #define CPCUSB_H | ||
15 | |||
16 | #undef err | ||
17 | #undef dbg | ||
18 | #undef info | ||
19 | |||
20 | /* Use our own dbg macro */ | ||
21 | #define dbg(format, arg...) do { if (debug) printk(KERN_INFO "CPC-USB: " format "\n" , ## arg); } while (0) | ||
22 | #define info(format, arg...) do { printk(KERN_INFO "CPC-USB: " format "\n" , ## arg); } while (0) | ||
23 | #define err(format, arg...) do { printk(KERN_INFO "CPC-USB(ERROR): " format "\n" , ## arg); } while (0) | ||
24 | |||
25 | #define CPC_USB_CARD_CNT 4 | ||
26 | |||
27 | typedef struct CPC_USB_READ_URB { | ||
28 | unsigned char *buffer; /* the buffer to send data */ | ||
29 | size_t size; /* the size of the send buffer */ | ||
30 | struct urb *urb; /* the urb used to send data */ | ||
31 | } CPC_USB_READ_URB_T; | ||
32 | |||
33 | typedef struct CPC_USB_WRITE_URB { | ||
34 | unsigned char *buffer; /* the buffer to send data */ | ||
35 | size_t size; /* the size of the send buffer */ | ||
36 | struct urb *urb; /* the urb used to send data */ | ||
37 | atomic_t busy; /* true if write urb is busy */ | ||
38 | struct completion finished; /* wait for the write to finish */ | ||
39 | } CPC_USB_WRITE_URB_T; | ||
40 | |||
41 | #define CPC_USB_URB_CNT 10 | ||
42 | |||
43 | typedef struct CPC_USB { | ||
44 | struct usb_device *udev; /* save off the usb device pointer */ | ||
45 | struct usb_interface *interface; /* the interface for this device */ | ||
46 | unsigned char minor; /* the starting minor number for this device */ | ||
47 | unsigned char num_ports; /* the number of ports this device has */ | ||
48 | int num_intr_in; /* number of interrupt in endpoints we have */ | ||
49 | int num_bulk_in; /* number of bulk in endpoints we have */ | ||
50 | int num_bulk_out; /* number of bulk out endpoints we have */ | ||
51 | |||
52 | CPC_USB_READ_URB_T urbs[CPC_USB_URB_CNT]; | ||
53 | |||
54 | unsigned char intr_in_buffer[4]; /* interrupt transfer buffer */ | ||
55 | struct urb *intr_in_urb; /* interrupt transfer urb */ | ||
56 | |||
57 | CPC_USB_WRITE_URB_T wrUrbs[CPC_USB_URB_CNT]; | ||
58 | |||
59 | int open; /* if the port is open or not */ | ||
60 | int present; /* if the device is not disconnected */ | ||
61 | struct semaphore sem; /* locks this structure */ | ||
62 | |||
63 | int free_slots; /* free send slots of CPC-USB */ | ||
64 | int idx; | ||
65 | |||
66 | spinlock_t slock; | ||
67 | |||
68 | char serialNumber[128]; /* serial number */ | ||
69 | int productId; /* product id to differ between M16C and LPC2119 */ | ||
70 | CPC_CHAN_T *chan; | ||
71 | } CPC_USB_T; | ||
72 | |||
73 | #define CPCTable CPCUSB_Table | ||
74 | |||
75 | #define CPC_DRIVER_VERSION "0.724" | ||
76 | #define CPC_DRIVER_SERIAL "not applicable" | ||
77 | |||
78 | #define OBUF_SIZE 255 // 4096 | ||
79 | |||
80 | /* read timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */ | ||
81 | #define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */ | ||
82 | #define RD_EXPIRE 12 /* Number of attempts to wait X seconds */ | ||
83 | |||
84 | #define CPC_USB_BASE_MNR 0 /* CPC-USB start at minor 0 */ | ||
85 | |||
86 | #endif | ||
diff --git a/drivers/staging/cpc-usb/sja2m16c.h b/drivers/staging/cpc-usb/sja2m16c.h new file mode 100644 index 000000000000..bd453e270559 --- /dev/null +++ b/drivers/staging/cpc-usb/sja2m16c.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef SJA2M16C_H | ||
2 | #define SJA2M16C_H | ||
3 | |||
4 | #include "cpc.h" | ||
5 | |||
6 | #define BAUDRATE_TOLERANCE_PERCENT 1 | ||
7 | #define SAMPLEPOINT_TOLERANCE_PERCENT 5 | ||
8 | #define SAMPLEPOINT_UPPER_LIMIT 88 | ||
9 | |||
10 | // M16C parameters | ||
11 | typedef struct FIELD_C0CONR { | ||
12 | unsigned int brp:4; | ||
13 | unsigned int sam:1; | ||
14 | unsigned int pr:3; | ||
15 | unsigned int dummy:8; | ||
16 | } FIELD_C0CONR_T; | ||
17 | typedef struct FIELD_C1CONR { | ||
18 | unsigned int ph1:3; | ||
19 | unsigned int ph2:3; | ||
20 | unsigned int sjw:2; | ||
21 | unsigned int dummy:8; | ||
22 | } FIELD_C1CONR_T; | ||
23 | typedef union C0CONR { | ||
24 | unsigned char c0con; | ||
25 | FIELD_C0CONR_T bc0con; | ||
26 | } C0CONR_T; | ||
27 | typedef union C1CONR { | ||
28 | unsigned char c1con; | ||
29 | FIELD_C1CONR_T bc1con; | ||
30 | } C1CONR_T; | ||
31 | |||
32 | #define SJA_TSEG1 ((pParams->btr1 & 0x0f)+1) | ||
33 | #define SJA_TSEG2 (((pParams->btr1 & 0x70)>>4)+1) | ||
34 | #define SJA_BRP ((pParams->btr0 & 0x3f)+1) | ||
35 | #define SJA_SJW ((pParams->btr0 & 0xc0)>>6) | ||
36 | #define SJA_SAM ((pParams->btr1 & 0x80)>>7) | ||
37 | int baudrate_m16c(int clk, int brp, int pr, int ph1, int ph2); | ||
38 | int samplepoint_m16c(int brp, int pr, int ph1, int ph2); | ||
39 | int SJA1000_TO_M16C_BASIC_Params(CPC_MSG_T * pMsg); | ||
40 | |||
41 | #endif /* */ | ||
diff --git a/drivers/staging/cpc-usb/sja2m16c_2.c b/drivers/staging/cpc-usb/sja2m16c_2.c new file mode 100644 index 000000000000..bf0230fb7780 --- /dev/null +++ b/drivers/staging/cpc-usb/sja2m16c_2.c | |||
@@ -0,0 +1,452 @@ | |||
1 | /**************************************************************************** | ||
2 | * | ||
3 | * Copyright (c) 2003,2004 by EMS Dr. Thomas Wuensche | ||
4 | * | ||
5 | * - All rights reserved - | ||
6 | * | ||
7 | * This code is provided "as is" without warranty of any kind, either | ||
8 | * expressed or implied, including but not limited to the liability | ||
9 | * concerning the freedom from material defects, the fitness for parti- | ||
10 | * cular purposes or the freedom of proprietary rights of third parties. | ||
11 | * | ||
12 | ***************************************************************************** | ||
13 | * Module name.: cpcusb | ||
14 | ***************************************************************************** | ||
15 | * Include file: cpc.h | ||
16 | ***************************************************************************** | ||
17 | * Project.....: Windows Driver Development Kit | ||
18 | * Filename....: sja2m16c.cpp | ||
19 | * Authors.....: (GU) Gerhard Uttenthaler | ||
20 | * (CS) Christian Schoett | ||
21 | ***************************************************************************** | ||
22 | * Short descr.: converts baudrate between SJA1000 and M16C | ||
23 | ***************************************************************************** | ||
24 | * Description.: handles the baudrate conversion from SJA1000 parameters to | ||
25 | * M16C parameters | ||
26 | ***************************************************************************** | ||
27 | * Address : EMS Dr. Thomas Wuensche | ||
28 | * Sonnenhang 3 | ||
29 | * D-85304 Ilmmuenster | ||
30 | * Tel. : +49-8441-490260 | ||
31 | * Fax. : +49-8441-81860 | ||
32 | * email: support@ems-wuensche.com | ||
33 | ***************************************************************************** | ||
34 | * History | ||
35 | ***************************************************************************** | ||
36 | * Version Date Auth Remark | ||
37 | * | ||
38 | * 01.00 ?? GU - initial release | ||
39 | * 01.10 ?????????? CS - adapted to fit into the USB Windows driver | ||
40 | * 02.00 18.08.2004 GU - improved the baudrate calculating algorithm | ||
41 | * - implemented acceptance filtering | ||
42 | * 02.10 10.09.2004 CS - adapted to fit into the USB Windows driver | ||
43 | ***************************************************************************** | ||
44 | * ToDo's | ||
45 | ***************************************************************************** | ||
46 | */ | ||
47 | |||
48 | /****************************************************************************/ | ||
49 | /* I N C L U D E S | ||
50 | */ | ||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/errno.h> | ||
53 | #include <linux/init.h> | ||
54 | #include <linux/slab.h> | ||
55 | #include <linux/vmalloc.h> | ||
56 | #include <linux/module.h> | ||
57 | #include <linux/poll.h> | ||
58 | #include <linux/smp_lock.h> | ||
59 | #include <linux/completion.h> | ||
60 | #include <asm/uaccess.h> | ||
61 | #include <linux/usb.h> | ||
62 | |||
63 | #include "cpc.h" | ||
64 | #include "cpc_int.h" | ||
65 | #include "cpcusb.h" | ||
66 | |||
67 | #include "sja2m16c.h" | ||
68 | |||
69 | /*********************************************************************/ | ||
70 | int baudrate_m16c(int clk, int brp, int pr, int ph1, int ph2) | ||
71 | { | ||
72 | return (16000000 / (1 << clk)) / 2 / (brp + 1) / (1 + pr + 1 + | ||
73 | ph1 + 1 + ph2 + | ||
74 | 1); | ||
75 | } | ||
76 | |||
77 | |||
78 | /*********************************************************************/ | ||
79 | int samplepoint_m16c(int brp, int pr, int ph1, int ph2) | ||
80 | { | ||
81 | return (100 * (1 + pr + 1 + ph1 + 1)) / (1 + pr + 1 + ph1 + 1 + | ||
82 | ph2 + 1); | ||
83 | } | ||
84 | |||
85 | |||
86 | /**************************************************************************** | ||
87 | * Function.....: SJA1000_TO_M16C_BASIC_Params | ||
88 | * | ||
89 | * Task.........: This routine converts SJA1000 CAN btr parameters into M16C | ||
90 | * parameters based on the sample point and the error. In | ||
91 | * addition it converts the acceptance filter parameters to | ||
92 | * suit the M16C parameters | ||
93 | * | ||
94 | * Parameters...: None | ||
95 | * | ||
96 | * Return values: None | ||
97 | * | ||
98 | * Comments.....: | ||
99 | ***************************************************************************** | ||
100 | * History | ||
101 | ***************************************************************************** | ||
102 | * 19.01.2005 CS - modifed the conversion of SJA1000 filter params into | ||
103 | * M16C params. Due to compatibility reasons with the | ||
104 | * older 82C200 CAN controller the SJA1000 | ||
105 | ****************************************************************************/ | ||
106 | int SJA1000_TO_M16C_BASIC_Params(CPC_MSG_T * in) | ||
107 | { | ||
108 | int sjaBaudrate; | ||
109 | int sjaSamplepoint; | ||
110 | int *baudrate_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] | ||
111 | int *samplepoint_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] | ||
112 | int baudrate_error_merk; | ||
113 | int clk, brp, pr, ph1, ph2; | ||
114 | int clk_merk, brp_merk, pr_merk, ph1_merk, ph2_merk; | ||
115 | int index; | ||
116 | unsigned char acc_code0, acc_code1, acc_code2, acc_code3; | ||
117 | unsigned char acc_mask0, acc_mask1, acc_mask2, acc_mask3; | ||
118 | CPC_MSG_T * out; | ||
119 | C0CONR_T c0con; | ||
120 | C1CONR_T c1con; | ||
121 | int tmpAccCode; | ||
122 | int tmpAccMask; | ||
123 | |||
124 | // we have to convert the parameters into M16C parameters | ||
125 | CPC_SJA1000_PARAMS_T * pParams; | ||
126 | |||
127 | // check if the type is CAN parameters and if we have to convert the given params | ||
128 | if (in->type != CPC_CMD_T_CAN_PRMS | ||
129 | || in->msg.canparams.cc_type != SJA1000) | ||
130 | return 0; | ||
131 | pParams = | ||
132 | (CPC_SJA1000_PARAMS_T *) & in->msg.canparams.cc_params.sja1000; | ||
133 | acc_code0 = pParams->acc_code0; | ||
134 | acc_code1 = pParams->acc_code1; | ||
135 | acc_code2 = pParams->acc_code2; | ||
136 | acc_code3 = pParams->acc_code3; | ||
137 | acc_mask0 = pParams->acc_mask0; | ||
138 | acc_mask1 = pParams->acc_mask1; | ||
139 | acc_mask2 = pParams->acc_mask2; | ||
140 | acc_mask3 = pParams->acc_mask3; | ||
141 | |||
142 | #ifdef _DEBUG_OUTPUT_CAN_PARAMS | ||
143 | info("acc_code0: %2.2Xh\n", acc_code0); | ||
144 | info("acc_code1: %2.2Xh\n", acc_code1); | ||
145 | info("acc_code2: %2.2Xh\n", acc_code2); | ||
146 | info("acc_code3: %2.2Xh\n", acc_code3); | ||
147 | info("acc_mask0: %2.2Xh\n", acc_mask0); | ||
148 | info("acc_mask1: %2.2Xh\n", acc_mask1); | ||
149 | info("acc_mask2: %2.2Xh\n", acc_mask2); | ||
150 | info("acc_mask3: %2.2Xh\n", acc_mask3); | ||
151 | |||
152 | #endif /* */ | ||
153 | if (! | ||
154 | (baudrate_error = | ||
155 | (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { | ||
156 | err("Could not allocate memory\n"); | ||
157 | return -3; | ||
158 | } | ||
159 | if (! | ||
160 | (samplepoint_error = | ||
161 | (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { | ||
162 | err("Could not allocate memory\n"); | ||
163 | vfree(baudrate_error); | ||
164 | return -3; | ||
165 | } | ||
166 | memset(baudrate_error, 0xff, sizeof(baudrate_error)); | ||
167 | memset(samplepoint_error, 0xff, sizeof(baudrate_error)); | ||
168 | sjaBaudrate = | ||
169 | 16000000 / 2 / SJA_BRP / (1 + SJA_TSEG1 + SJA_TSEG2); | ||
170 | sjaSamplepoint = | ||
171 | 100 * (1 + SJA_TSEG1) / (1 + SJA_TSEG1 + SJA_TSEG2); | ||
172 | if (sjaBaudrate == 0) { | ||
173 | vfree(baudrate_error); | ||
174 | vfree(samplepoint_error); | ||
175 | return -2; | ||
176 | } | ||
177 | |||
178 | #ifdef _DEBUG_OUTPUT_CAN_PARAMS | ||
179 | info("\nStarting SJA CAN params\n"); | ||
180 | info("-------------------------\n"); | ||
181 | info("TS1 : %2.2Xh TS2 : %2.2Xh\n", SJA_TSEG1, SJA_TSEG2); | ||
182 | info("BTR0 : %2.2Xh BTR1: %2.2Xh\n", pParams->btr0, | ||
183 | pParams->btr1); | ||
184 | info("Baudrate: %d.%dkBaud\n", sjaBaudrate / 1000, | ||
185 | sjaBaudrate % 1000); | ||
186 | info("Sample P: 0.%d\n", sjaSamplepoint); | ||
187 | info("\n"); | ||
188 | |||
189 | #endif /* */ | ||
190 | c0con.bc0con.sam = SJA_SAM; | ||
191 | c1con.bc1con.sjw = SJA_SJW; | ||
192 | |||
193 | // calculate errors for all baudrates | ||
194 | index = 0; | ||
195 | for (clk = 0; clk < 5; clk++) { | ||
196 | for (brp = 0; brp < 16; brp++) { | ||
197 | for (pr = 0; pr < 8; pr++) { | ||
198 | for (ph1 = 0; ph1 < 8; ph1++) { | ||
199 | for (ph2 = 0; ph2 < 8; ph2++) { | ||
200 | baudrate_error[index] = | ||
201 | 100 * | ||
202 | abs(baudrate_m16c | ||
203 | (clk, brp, pr, ph1, | ||
204 | ph2) - | ||
205 | sjaBaudrate) / | ||
206 | sjaBaudrate; | ||
207 | samplepoint_error[index] = | ||
208 | abs(samplepoint_m16c | ||
209 | (brp, pr, ph1, | ||
210 | ph2) - | ||
211 | sjaSamplepoint); | ||
212 | |||
213 | #if 0 | ||
214 | info | ||
215 | ("Baudrate : %d kBaud\n", | ||
216 | baudrate_m16c(clk, | ||
217 | brp, pr, | ||
218 | ph1, | ||
219 | ph2)); | ||
220 | info | ||
221 | ("Baudrate Error: %d\n", | ||
222 | baudrate_error | ||
223 | [index]); | ||
224 | info | ||
225 | ("Sample P Error: %d\n", | ||
226 | samplepoint_error | ||
227 | [index]); | ||
228 | info | ||
229 | ("clk : %d\n", | ||
230 | clk); | ||
231 | |||
232 | #endif /* */ | ||
233 | index++; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | // mark all baudrate_error entries which are outer limits | ||
241 | index = 0; | ||
242 | for (clk = 0; clk < 5; clk++) { | ||
243 | for (brp = 0; brp < 16; brp++) { | ||
244 | for (pr = 0; pr < 8; pr++) { | ||
245 | for (ph1 = 0; ph1 < 8; ph1++) { | ||
246 | for (ph2 = 0; ph2 < 8; ph2++) { | ||
247 | if ((baudrate_error[index] | ||
248 | > | ||
249 | BAUDRATE_TOLERANCE_PERCENT) | ||
250 | || | ||
251 | (samplepoint_error | ||
252 | [index] > | ||
253 | SAMPLEPOINT_TOLERANCE_PERCENT) | ||
254 | || | ||
255 | (samplepoint_m16c | ||
256 | (brp, pr, ph1, | ||
257 | ph2) > | ||
258 | SAMPLEPOINT_UPPER_LIMIT)) | ||
259 | { | ||
260 | baudrate_error | ||
261 | [index] = -1; | ||
262 | } else | ||
263 | if (((1 + pr + 1 + | ||
264 | ph1 + 1 + ph2 + | ||
265 | 1) < 8) | ||
266 | || | ||
267 | ((1 + pr + 1 + | ||
268 | ph1 + 1 + ph2 + | ||
269 | 1) > 25)) { | ||
270 | baudrate_error | ||
271 | [index] = -1; | ||
272 | } | ||
273 | |||
274 | #if 0 | ||
275 | else { | ||
276 | info | ||
277 | ("Baudrate : %d kBaud\n", | ||
278 | baudrate_m16c | ||
279 | (clk, brp, pr, | ||
280 | ph1, ph2)); | ||
281 | info | ||
282 | ("Baudrate Error: %d\n", | ||
283 | baudrate_error | ||
284 | [index]); | ||
285 | info | ||
286 | ("Sample P Error: %d\n", | ||
287 | samplepoint_error | ||
288 | [index]); | ||
289 | } | ||
290 | |||
291 | #endif /* */ | ||
292 | index++; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | |||
299 | // find list of minimum of baudrate_error within unmarked entries | ||
300 | clk_merk = brp_merk = pr_merk = ph1_merk = ph2_merk = 0; | ||
301 | baudrate_error_merk = 100; | ||
302 | index = 0; | ||
303 | for (clk = 0; clk < 5; clk++) { | ||
304 | for (brp = 0; brp < 16; brp++) { | ||
305 | for (pr = 0; pr < 8; pr++) { | ||
306 | for (ph1 = 0; ph1 < 8; ph1++) { | ||
307 | for (ph2 = 0; ph2 < 8; ph2++) { | ||
308 | if (baudrate_error[index] | ||
309 | != -1) { | ||
310 | if (baudrate_error | ||
311 | [index] < | ||
312 | baudrate_error_merk) | ||
313 | { | ||
314 | baudrate_error_merk | ||
315 | = | ||
316 | baudrate_error | ||
317 | [index]; | ||
318 | brp_merk = | ||
319 | brp; | ||
320 | pr_merk = | ||
321 | pr; | ||
322 | ph1_merk = | ||
323 | ph1; | ||
324 | ph2_merk = | ||
325 | ph2; | ||
326 | clk_merk = | ||
327 | clk; | ||
328 | |||
329 | #if 0 | ||
330 | info | ||
331 | ("brp: %2.2Xh pr: %2.2Xh ph1: %2.2Xh ph2: %2.2Xh\n", | ||
332 | brp, | ||
333 | pr, | ||
334 | ph1, | ||
335 | ph2); | ||
336 | info | ||
337 | ("Baudrate : %d kBaud\n", | ||
338 | baudrate_m16c | ||
339 | (clk, | ||
340 | brp, | ||
341 | pr, | ||
342 | ph1, | ||
343 | ph2)); | ||
344 | info | ||
345 | ("Baudrate Error: %d\n", | ||
346 | baudrate_error | ||
347 | [index]); | ||
348 | info | ||
349 | ("Sample P Error: %d\n", | ||
350 | samplepoint_error | ||
351 | [index]); | ||
352 | |||
353 | #endif /* */ | ||
354 | } | ||
355 | } | ||
356 | index++; | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | if (baudrate_error_merk == 100) { | ||
363 | info("ERROR: Could not convert CAN init parameter\n"); | ||
364 | vfree(baudrate_error); | ||
365 | vfree(samplepoint_error); | ||
366 | return -1; | ||
367 | } | ||
368 | |||
369 | // setting m16c CAN parameter | ||
370 | c0con.bc0con.brp = brp_merk; | ||
371 | c0con.bc0con.pr = pr_merk; | ||
372 | c1con.bc1con.ph1 = ph1_merk; | ||
373 | c1con.bc1con.ph2 = ph2_merk; | ||
374 | |||
375 | #ifdef _DEBUG_OUTPUT_CAN_PARAMS | ||
376 | info("\nResulting M16C CAN params\n"); | ||
377 | info("-------------------------\n"); | ||
378 | info("clk : %2.2Xh\n", clk_merk); | ||
379 | info("ph1 : %2.2Xh ph2: %2.2Xh\n", c1con.bc1con.ph1 + 1, | ||
380 | c1con.bc1con.ph2 + 1); | ||
381 | info("pr : %2.2Xh brp: %2.2Xh\n", c0con.bc0con.pr + 1, | ||
382 | c0con.bc0con.brp + 1); | ||
383 | info("sjw : %2.2Xh sam: %2.2Xh\n", c1con.bc1con.sjw, | ||
384 | c0con.bc0con.sam); | ||
385 | info("co1 : %2.2Xh co0: %2.2Xh\n", c1con.c1con, c0con.c0con); | ||
386 | info("Baudrate: %d.%dBaud\n", | ||
387 | baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, | ||
388 | c1con.bc1con.ph1, c1con.bc1con.ph2) / 1000, | ||
389 | baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, | ||
390 | c1con.bc1con.ph1, c1con.bc1con.ph2) % 1000); | ||
391 | info("Sample P: 0.%d\n", | ||
392 | samplepoint_m16c(c0con.bc0con.brp, c0con.bc0con.pr, | ||
393 | c1con.bc1con.ph1, c1con.bc1con.ph2)); | ||
394 | info("\n"); | ||
395 | |||
396 | #endif /* */ | ||
397 | out = in; | ||
398 | out->type = 6; | ||
399 | out->length = sizeof(CPC_M16C_BASIC_PARAMS_T) + 1; | ||
400 | out->msg.canparams.cc_type = M16C_BASIC; | ||
401 | out->msg.canparams.cc_params.m16c_basic.con0 = c0con.c0con; | ||
402 | out->msg.canparams.cc_params.m16c_basic.con1 = c1con.c1con; | ||
403 | out->msg.canparams.cc_params.m16c_basic.ctlr0 = 0x4C; | ||
404 | out->msg.canparams.cc_params.m16c_basic.ctlr1 = 0x00; | ||
405 | out->msg.canparams.cc_params.m16c_basic.clk = clk_merk; | ||
406 | out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = | ||
407 | acc_code0; | ||
408 | out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = acc_code1; | ||
409 | |||
410 | // info("code0: 0x%2.2X, code1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_code0, out->msg.canparams.cc_params.m16c_basic.acc_std_code1); | ||
411 | tmpAccCode = (acc_code1 >> 5) + (acc_code0 << 3); | ||
412 | out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = | ||
413 | (unsigned char) tmpAccCode; | ||
414 | out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = | ||
415 | (unsigned char) (tmpAccCode >> 8); | ||
416 | |||
417 | // info("code0: 0x%2.2X, code1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_code0, out->msg.canparams.cc_params.m16c_basic.acc_std_code1); | ||
418 | out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = | ||
419 | ~acc_mask0; | ||
420 | out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = | ||
421 | ~acc_mask1; | ||
422 | |||
423 | // info("mask0: 0x%2.2X, mask1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_mask0, out->msg.canparams.cc_params.m16c_basic.acc_std_mask1); | ||
424 | tmpAccMask = ((acc_mask1) >> 5) + ((acc_mask0) << 3); | ||
425 | |||
426 | // info("tmpAccMask: 0x%4.4X\n", tmpAccMask); | ||
427 | out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = | ||
428 | (unsigned char) ~tmpAccMask; | ||
429 | out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = | ||
430 | (unsigned char) ~(tmpAccMask >> 8); | ||
431 | |||
432 | // info("mask0: 0x%2.2X, mask1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_mask0, out->msg.canparams.cc_params.m16c_basic.acc_std_mask1); | ||
433 | out->msg.canparams.cc_params.m16c_basic.acc_ext_code0 = | ||
434 | (unsigned char) tmpAccCode; | ||
435 | out->msg.canparams.cc_params.m16c_basic.acc_ext_code1 = | ||
436 | (unsigned char) (tmpAccCode >> 8); | ||
437 | out->msg.canparams.cc_params.m16c_basic.acc_ext_code2 = acc_code2; | ||
438 | out->msg.canparams.cc_params.m16c_basic.acc_ext_code3 = acc_code3; | ||
439 | out->msg.canparams.cc_params.m16c_basic.acc_ext_mask0 = | ||
440 | (unsigned char) ~tmpAccMask; | ||
441 | out->msg.canparams.cc_params.m16c_basic.acc_ext_mask1 = | ||
442 | (unsigned char) ~(tmpAccMask >> 8); | ||
443 | out->msg.canparams.cc_params.m16c_basic.acc_ext_mask2 = | ||
444 | ~acc_mask2; | ||
445 | out->msg.canparams.cc_params.m16c_basic.acc_ext_mask3 = | ||
446 | ~acc_mask3; | ||
447 | vfree(baudrate_error); | ||
448 | vfree(samplepoint_error); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | |||