| /**************************************************************************** |
| * |
| * Copyright (c) 2003,2004 by EMS Dr. Thomas Wuensche |
| * |
| * - All rights reserved - |
| * |
| * This code is provided "as is" without warranty of any kind, either |
| * expressed or implied, including but not limited to the liability |
| * concerning the freedom from material defects, the fitness for parti- |
| * cular purposes or the freedom of proprietary rights of third parties. |
| * |
| ***************************************************************************** |
| * Module name.: cpcusb |
| ***************************************************************************** |
| * Include file: cpc.h |
| ***************************************************************************** |
| * Project.....: Windows Driver Development Kit |
| * Filename....: sja2m16c.cpp |
| * Authors.....: (GU) Gerhard Uttenthaler |
| * (CS) Christian Schoett |
| ***************************************************************************** |
| * Short descr.: converts baudrate between SJA1000 and M16C |
| ***************************************************************************** |
| * Description.: handles the baudrate conversion from SJA1000 parameters to |
| * M16C parameters |
| ***************************************************************************** |
| * Address : EMS Dr. Thomas Wuensche |
| * Sonnenhang 3 |
| * D-85304 Ilmmuenster |
| * Tel. : +49-8441-490260 |
| * Fax. : +49-8441-81860 |
| * email: support@ems-wuensche.com |
| ***************************************************************************** |
| * History |
| ***************************************************************************** |
| * Version Date Auth Remark |
| * |
| * 01.00 ?? GU - initial release |
| * 01.10 ?????????? CS - adapted to fit into the USB Windows driver |
| * 02.00 18.08.2004 GU - improved the baudrate calculating algorithm |
| * - implemented acceptance filtering |
| * 02.10 10.09.2004 CS - adapted to fit into the USB Windows driver |
| ***************************************************************************** |
| * ToDo's |
| ***************************************************************************** |
| */ |
| |
| /****************************************************************************/ |
| /* I N C L U D E S |
| */ |
| #include <linux/kernel.h> |
| #include <linux/errno.h> |
| #include <linux/init.h> |
| #include <linux/slab.h> |
| #include <linux/vmalloc.h> |
| #include <linux/module.h> |
| #include <linux/poll.h> |
| #include <linux/smp_lock.h> |
| #include <linux/completion.h> |
| #include <asm/uaccess.h> |
| #include <linux/usb.h> |
| |
| #include "cpc.h" |
| #include "cpc_int.h" |
| #include "cpcusb.h" |
| |
| #include "sja2m16c.h" |
| |
| /*********************************************************************/ |
| int baudrate_m16c(int clk, int brp, int pr, int ph1, int ph2) |
| { |
| return (16000000 / (1 << clk)) / 2 / (brp + 1) / (1 + pr + 1 + |
| ph1 + 1 + ph2 + |
| 1); |
| } |
| |
| |
| /*********************************************************************/ |
| int samplepoint_m16c(int brp, int pr, int ph1, int ph2) |
| { |
| return (100 * (1 + pr + 1 + ph1 + 1)) / (1 + pr + 1 + ph1 + 1 + |
| ph2 + 1); |
| } |
| |
| |
| /**************************************************************************** |
| * Function.....: SJA1000_TO_M16C_BASIC_Params |
| * |
| * Task.........: This routine converts SJA1000 CAN btr parameters into M16C |
| * parameters based on the sample point and the error. In |
| * addition it converts the acceptance filter parameters to |
| * suit the M16C parameters |
| * |
| * Parameters...: None |
| * |
| * Return values: None |
| * |
| * Comments.....: |
| ***************************************************************************** |
| * History |
| ***************************************************************************** |
| * 19.01.2005 CS - modifed the conversion of SJA1000 filter params into |
| * M16C params. Due to compatibility reasons with the |
| * older 82C200 CAN controller the SJA1000 |
| ****************************************************************************/ |
| int SJA1000_TO_M16C_BASIC_Params(CPC_MSG_T * in) |
| { |
| int sjaBaudrate; |
| int sjaSamplepoint; |
| int *baudrate_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] |
| int *samplepoint_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] |
| int baudrate_error_merk; |
| int clk, brp, pr, ph1, ph2; |
| int clk_merk, brp_merk, pr_merk, ph1_merk, ph2_merk; |
| int index; |
| unsigned char acc_code0, acc_code1, acc_code2, acc_code3; |
| unsigned char acc_mask0, acc_mask1, acc_mask2, acc_mask3; |
| CPC_MSG_T * out; |
| C0CONR_T c0con; |
| C1CONR_T c1con; |
| int tmpAccCode; |
| int tmpAccMask; |
| |
| // we have to convert the parameters into M16C parameters |
| CPC_SJA1000_PARAMS_T * pParams; |
| |
| // check if the type is CAN parameters and if we have to convert the given params |
| if (in->type != CPC_CMD_T_CAN_PRMS |
| || in->msg.canparams.cc_type != SJA1000) |
| return 0; |
| pParams = |
| (CPC_SJA1000_PARAMS_T *) & in->msg.canparams.cc_params.sja1000; |
| acc_code0 = pParams->acc_code0; |
| acc_code1 = pParams->acc_code1; |
| acc_code2 = pParams->acc_code2; |
| acc_code3 = pParams->acc_code3; |
| acc_mask0 = pParams->acc_mask0; |
| acc_mask1 = pParams->acc_mask1; |
| acc_mask2 = pParams->acc_mask2; |
| acc_mask3 = pParams->acc_mask3; |
| |
| #ifdef _DEBUG_OUTPUT_CAN_PARAMS |
| info("acc_code0: %2.2Xh\n", acc_code0); |
| info("acc_code1: %2.2Xh\n", acc_code1); |
| info("acc_code2: %2.2Xh\n", acc_code2); |
| info("acc_code3: %2.2Xh\n", acc_code3); |
| info("acc_mask0: %2.2Xh\n", acc_mask0); |
| info("acc_mask1: %2.2Xh\n", acc_mask1); |
| info("acc_mask2: %2.2Xh\n", acc_mask2); |
| info("acc_mask3: %2.2Xh\n", acc_mask3); |
| |
| #endif /* */ |
| if (! |
| (baudrate_error = |
| (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { |
| err("Could not allocate memory\n"); |
| return -3; |
| } |
| if (! |
| (samplepoint_error = |
| (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { |
| err("Could not allocate memory\n"); |
| vfree(baudrate_error); |
| return -3; |
| } |
| memset(baudrate_error, 0xff, sizeof(baudrate_error)); |
| memset(samplepoint_error, 0xff, sizeof(baudrate_error)); |
| sjaBaudrate = |
| 16000000 / 2 / SJA_BRP / (1 + SJA_TSEG1 + SJA_TSEG2); |
| sjaSamplepoint = |
| 100 * (1 + SJA_TSEG1) / (1 + SJA_TSEG1 + SJA_TSEG2); |
| if (sjaBaudrate == 0) { |
| vfree(baudrate_error); |
| vfree(samplepoint_error); |
| return -2; |
| } |
| |
| #ifdef _DEBUG_OUTPUT_CAN_PARAMS |
| info("\nStarting SJA CAN params\n"); |
| info("-------------------------\n"); |
| info("TS1 : %2.2Xh TS2 : %2.2Xh\n", SJA_TSEG1, SJA_TSEG2); |
| info("BTR0 : %2.2Xh BTR1: %2.2Xh\n", pParams->btr0, |
| pParams->btr1); |
| info("Baudrate: %d.%dkBaud\n", sjaBaudrate / 1000, |
| sjaBaudrate % 1000); |
| info("Sample P: 0.%d\n", sjaSamplepoint); |
| info("\n"); |
| |
| #endif /* */ |
| c0con.bc0con.sam = SJA_SAM; |
| c1con.bc1con.sjw = SJA_SJW; |
| |
| // calculate errors for all baudrates |
| index = 0; |
| for (clk = 0; clk < 5; clk++) { |
| for (brp = 0; brp < 16; brp++) { |
| for (pr = 0; pr < 8; pr++) { |
| for (ph1 = 0; ph1 < 8; ph1++) { |
| for (ph2 = 0; ph2 < 8; ph2++) { |
| baudrate_error[index] = |
| 100 * |
| abs(baudrate_m16c |
| (clk, brp, pr, ph1, |
| ph2) - |
| sjaBaudrate) / |
| sjaBaudrate; |
| samplepoint_error[index] = |
| abs(samplepoint_m16c |
| (brp, pr, ph1, |
| ph2) - |
| sjaSamplepoint); |
| |
| #if 0 |
| info |
| ("Baudrate : %d kBaud\n", |
| baudrate_m16c(clk, |
| brp, pr, |
| ph1, |
| ph2)); |
| info |
| ("Baudrate Error: %d\n", |
| baudrate_error |
| [index]); |
| info |
| ("Sample P Error: %d\n", |
| samplepoint_error |
| [index]); |
| info |
| ("clk : %d\n", |
| clk); |
| |
| #endif /* */ |
| index++; |
| } |
| } |
| } |
| } |
| } |
| |
| // mark all baudrate_error entries which are outer limits |
| index = 0; |
| for (clk = 0; clk < 5; clk++) { |
| for (brp = 0; brp < 16; brp++) { |
| for (pr = 0; pr < 8; pr++) { |
| for (ph1 = 0; ph1 < 8; ph1++) { |
| for (ph2 = 0; ph2 < 8; ph2++) { |
| if ((baudrate_error[index] |
| > |
| BAUDRATE_TOLERANCE_PERCENT) |
| || |
| (samplepoint_error |
| [index] > |
| SAMPLEPOINT_TOLERANCE_PERCENT) |
| || |
| (samplepoint_m16c |
| (brp, pr, ph1, |
| ph2) > |
| SAMPLEPOINT_UPPER_LIMIT)) |
| { |
| baudrate_error |
| [index] = -1; |
| } else |
| if (((1 + pr + 1 + |
| ph1 + 1 + ph2 + |
| 1) < 8) |
| || |
| ((1 + pr + 1 + |
| ph1 + 1 + ph2 + |
| 1) > 25)) { |
| baudrate_error |
| [index] = -1; |
| } |
| |
| #if 0 |
| else { |
| info |
| ("Baudrate : %d kBaud\n", |
| baudrate_m16c |
| (clk, brp, pr, |
| ph1, ph2)); |
| info |
| ("Baudrate Error: %d\n", |
| baudrate_error |
| [index]); |
| info |
| ("Sample P Error: %d\n", |
| samplepoint_error |
| [index]); |
| } |
| |
| #endif /* */ |
| index++; |
| } |
| } |
| } |
| } |
| } |
| |
| // find list of minimum of baudrate_error within unmarked entries |
| clk_merk = brp_merk = pr_merk = ph1_merk = ph2_merk = 0; |
| baudrate_error_merk = 100; |
| index = 0; |
| for (clk = 0; clk < 5; clk++) { |
| for (brp = 0; brp < 16; brp++) { |
| for (pr = 0; pr < 8; pr++) { |
| for (ph1 = 0; ph1 < 8; ph1++) { |
| for (ph2 = 0; ph2 < 8; ph2++) { |
| if (baudrate_error[index] |
| != -1) { |
| if (baudrate_error |
| [index] < |
| baudrate_error_merk) |
| { |
| baudrate_error_merk |
| = |
| baudrate_error |
| [index]; |
| brp_merk = |
| brp; |
| pr_merk = |
| pr; |
| ph1_merk = |
| ph1; |
| ph2_merk = |
| ph2; |
| clk_merk = |
| clk; |
| |
| #if 0 |
| info |
| ("brp: %2.2Xh pr: %2.2Xh ph1: %2.2Xh ph2: %2.2Xh\n", |
| brp, |
| pr, |
| ph1, |
| ph2); |
| info |
| ("Baudrate : %d kBaud\n", |
| baudrate_m16c |
| (clk, |
| brp, |
| pr, |
| ph1, |
| ph2)); |
| info |
| ("Baudrate Error: %d\n", |
| baudrate_error |
| [index]); |
| info |
| ("Sample P Error: %d\n", |
| samplepoint_error |
| [index]); |
| |
| #endif /* */ |
| } |
| } |
| index++; |
| } |
| } |
| } |
| } |
| } |
| if (baudrate_error_merk == 100) { |
| info("ERROR: Could not convert CAN init parameter\n"); |
| vfree(baudrate_error); |
| vfree(samplepoint_error); |
| return -1; |
| } |
| |
| // setting m16c CAN parameter |
| c0con.bc0con.brp = brp_merk; |
| c0con.bc0con.pr = pr_merk; |
| c1con.bc1con.ph1 = ph1_merk; |
| c1con.bc1con.ph2 = ph2_merk; |
| |
| #ifdef _DEBUG_OUTPUT_CAN_PARAMS |
| info("\nResulting M16C CAN params\n"); |
| info("-------------------------\n"); |
| info("clk : %2.2Xh\n", clk_merk); |
| info("ph1 : %2.2Xh ph2: %2.2Xh\n", c1con.bc1con.ph1 + 1, |
| c1con.bc1con.ph2 + 1); |
| info("pr : %2.2Xh brp: %2.2Xh\n", c0con.bc0con.pr + 1, |
| c0con.bc0con.brp + 1); |
| info("sjw : %2.2Xh sam: %2.2Xh\n", c1con.bc1con.sjw, |
| c0con.bc0con.sam); |
| info("co1 : %2.2Xh co0: %2.2Xh\n", c1con.c1con, c0con.c0con); |
| info("Baudrate: %d.%dBaud\n", |
| baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, |
| c1con.bc1con.ph1, c1con.bc1con.ph2) / 1000, |
| baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, |
| c1con.bc1con.ph1, c1con.bc1con.ph2) % 1000); |
| info("Sample P: 0.%d\n", |
| samplepoint_m16c(c0con.bc0con.brp, c0con.bc0con.pr, |
| c1con.bc1con.ph1, c1con.bc1con.ph2)); |
| info("\n"); |
| |
| #endif /* */ |
| out = in; |
| out->type = 6; |
| out->length = sizeof(CPC_M16C_BASIC_PARAMS_T) + 1; |
| out->msg.canparams.cc_type = M16C_BASIC; |
| out->msg.canparams.cc_params.m16c_basic.con0 = c0con.c0con; |
| out->msg.canparams.cc_params.m16c_basic.con1 = c1con.c1con; |
| out->msg.canparams.cc_params.m16c_basic.ctlr0 = 0x4C; |
| out->msg.canparams.cc_params.m16c_basic.ctlr1 = 0x00; |
| out->msg.canparams.cc_params.m16c_basic.clk = clk_merk; |
| out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = |
| acc_code0; |
| out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = acc_code1; |
| |
| // 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); |
| tmpAccCode = (acc_code1 >> 5) + (acc_code0 << 3); |
| out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = |
| (unsigned char) tmpAccCode; |
| out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = |
| (unsigned char) (tmpAccCode >> 8); |
| |
| // 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); |
| out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = |
| ~acc_mask0; |
| out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = |
| ~acc_mask1; |
| |
| // 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); |
| tmpAccMask = ((acc_mask1) >> 5) + ((acc_mask0) << 3); |
| |
| // info("tmpAccMask: 0x%4.4X\n", tmpAccMask); |
| out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = |
| (unsigned char) ~tmpAccMask; |
| out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = |
| (unsigned char) ~(tmpAccMask >> 8); |
| |
| // 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); |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_code0 = |
| (unsigned char) tmpAccCode; |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_code1 = |
| (unsigned char) (tmpAccCode >> 8); |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_code2 = acc_code2; |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_code3 = acc_code3; |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_mask0 = |
| (unsigned char) ~tmpAccMask; |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_mask1 = |
| (unsigned char) ~(tmpAccMask >> 8); |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_mask2 = |
| ~acc_mask2; |
| out->msg.canparams.cc_params.m16c_basic.acc_ext_mask3 = |
| ~acc_mask3; |
| vfree(baudrate_error); |
| vfree(samplepoint_error); |
| return 0; |
| } |
| |
| |