/** \file sja1000.c * * SJA1000 CAN driver for Linux 2.4.x * * \author Cristiano Brudna, 2001, 2002, 2003 * \author Hubert Piontek, 2003 * * \date 2001, 2002, 2003 * * University of Ulm, Germany * * * This driver was originally Written for the PCAN-Dongle board (with * a SJA1000 CAN controller) for the pararalel port of the PC. * It Operates in the EPP mode. * * For compilation, this driver uses a file called "Rules.make" which * comes with the book "Linux Device Drivers" by Alessandro Rubini and * Jonathan Corbet, published by O'Reilly & Associates. * * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* pull in some definitions like registers and ioctl() commands */ #include "sja1000.h" /** \brief Interrupt to use; default is defined in sja1000.h. Can be given as a module parameter */ int irq = IRQ; /** \brief Base address of the parallel port to use; default is defined in sja1000.h. Can be given as a module parameter */ int port = BASE_ADDR; #define DRIVER_VERSION "CAN Bus driver for SJA1000 V1.8.1" MODULE_AUTHOR("Cristiano Brudna "); MODULE_DESCRIPTION(DRIVER_VERSION); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(irq, "The IRQ (default IRQ " DEF_IRQ_STR ")"); MODULE_PARM(port, "i"); MODULE_PARM_DESC(port, "The base I/O port (default " DEF_BA_STR ")"); int can_w(enum can_registers, unsigned char); int can_r(enum can_registers); /** \brief Pre-defined bit timings */ bus_param baud_tab[] = { {0, 0x00, 0x14}, /* 1 Mbit/s */ {1, 0x00, 0x1c}, /* 500 kbit/s */ {2, 0x01, 0x1c}, /* 250 kbit/s */ {3, 0x03, 0x1c}, /* 125 kbit/s */ {4, 0x18, 0x1c}, /* 20 kbit/s */ }; /** \brief Device descriptor */ CAN_Dev dev; /** \brief Timestamp of the last transmited message */ struct timeval transmit_timestamp; /** \brief Structure used to get timestamps */ struct timeval time; /** \brief Wait queues (for tasks) used in blocking mode */ DECLARE_WAIT_QUEUE_HEAD(inq); DECLARE_WAIT_QUEUE_HEAD(outq); /** \brief Print a small welcome message */ static void show_can_version(void) { printk( DRIVER_VERSION " loaded\n" ); } int can_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; len += sprintf(buf+len, "\nCAN SJA1000\n" DRIVER_VERSION "\n" ); len += sprintf(buf+len, "Port 0x%x, IRQ%d\n", port, irq); len += sprintf(buf+len, "Baudrate: 0x%02x 0x%02x \n", baud_tab[dev.baud_rate].bt0, baud_tab[dev.baud_rate].bt1); len += sprintf(buf+len, "RX error counter: %d\n", can_r(RX_ERROR_COUNTER)); len += sprintf(buf+len, "TX error counter: %d\n", can_r(TX_ERROR_COUNTER)); *eof = 1; return len; } static void can_create_proc() { create_proc_read_entry("can", 0 /* default mode */, NULL /* parent dir */, can_read_procmem, NULL /* client data */); } static void can_remove_proc() { /* no problem if it was not registered */ remove_proc_entry("can", NULL /* parent dir */); } static void read_from_SJA1000(void) { int ff, rtr, dlc, i; unsigned char frame_info; if((can_r(STATUS) & 0x01) == 1) { if(dev.nm_rb < BUFFER_SIZE) { frame_info = can_r(FRAME_INFORMATION); ff = (frame_info >> 7); /* Extract the frame format */ rtr = ((frame_info & 0x40) >> 6); /* Extract the remote transmition request bit */ dlc = (frame_info & 0x0f); /* Extract the Data Length Code */ if(dlc > 8) dlc = 8; dev.read_buf[dev.wp_rb].len = dlc; dev.read_buf[dev.wp_rb].rtr = rtr; if(ff == EXTENDED) { /* extended frame */ dev.read_buf[dev.wp_rb].type = EXTENDED; dev.read_buf[dev.wp_rb].id = (can_r(IDENTIFIER) << 21) | (can_r(IDENTIFIER+1) << 13) | (can_r(IDENTIFIER+2) << 5) | (can_r(IDENTIFIER+3) >> 3); for(i=0; i> 5); for(i=0; i 0) { if((can_r(STATUS) & 0x04) != 0) { /* SJA1000 released to write */ can_w( FRAME_INFORMATION, (dev.write_buf[dev.rp_wb].len | (dev.write_buf[dev.rp_wb].type << 7)) ); if(dev.write_buf[dev.rp_wb].type == EXTENDED) { can_w(IDENTIFIER, (dev.write_buf[dev.rp_wb].id >> 21) ); can_w((IDENTIFIER + 1), (dev.write_buf[dev.rp_wb].id >> 13) ); can_w((IDENTIFIER + 2), (dev.write_buf[dev.rp_wb].id >> 5) ); can_w((IDENTIFIER + 3), (dev.write_buf[dev.rp_wb].id << 3) ); dlc = dev.write_buf[dev.rp_wb].len; /* Write the Data Length Code */ if(dlc > 8) dlc = 8; for(i=0; i> 3) ); can_w((IDENTIFIER + 1), (dev.write_buf[dev.rp_wb].id << 5) ); dlc = dev.write_buf[dev.rp_wb].len; /* Write the Data Length Code */ if(dlc > 8) dlc = 8; for(i=0; i 0) return -EBUSY; /* device already open */ dev.count++; /* Request IRQ */ result = request_irq(irq, can_interrupt, SA_INTERRUPT, "can", NULL); if(result) { printk(KERN_INFO "CAN: can't get assigned IRQ%d\n", irq); return -EBUSY; } can_w(MODE, 0x01); /* RESET Mode */ for(a=0; a<1000; a++); /* Delay */ can_w(CLOCK_DIVIDER, 0x80); /* PeliCAN MODE */ for(a=0; a<1000; a++); /* Delay */ can_w(INTERRUPT_ENABLE, 0xaf); /* Define handled interrupts */ can_w(BUS_TIMING_0, 0x00); /* Set bus timming for 1Mbit/s */ can_w(BUS_TIMING_1, 0x14); /* Set bus Timming for 1Mit/s */ can_w(OUTPUT_CONTROL, 0xda); /* Define Output Mode (IMPORTANT: depends on the transceiver and way it is connected*/ can_w(RX_ERROR_COUNTER, 0); /* Clear the reception error counter */ can_w(TX_ERROR_COUNTER, 0); /* Clear the transmission error counter */ can_w(FRAME_INFORMATION, 0xff); /* Define acceptance code */ can_w(FRAME_INFORMATION+1, 0xff); can_w(FRAME_INFORMATION+2, 0xff); can_w(FRAME_INFORMATION+3, 0xff); can_w(ACCEPTANCE_MASK, 0xff); /* Define acceptance mask to don't care */ can_w(ACCEPTANCE_MASK+1, 0xff); can_w(ACCEPTANCE_MASK+2, 0xff); can_w(ACCEPTANCE_MASK+3, 0xff); can_w(MODE, 0x08); /* Deactivate RESET, single acceptance filter */ dev.active_passive_status = ACTIVE; can_w(COMMAND, 0x0c); /* Clear the buffer */ ir = can_r(INTERRUPT); /* Release Interupts */ /* Device information */ dev.baud_rate = B1000; dev.frame_mode = EXTENDED; dev.nm_rb = 0; /* 0 messages in the read buffer */ dev.wp_rb = 0; /* initial write position in the read buffer */ dev.rp_rb =0; /* initial read position in the read buffer */ dev.nm_wb = 0; /* 0 messages in the write buffer */ dev.wp_wb = 0; /* initial write position in the write buffer */ dev.rp_wb =0; /* initial read position in the write buffer */ return 0; } int can_release(struct inode *inode, struct file *filp) { can_w(INTERRUPT_ENABLE, 0x0); /* Disable SJA1000 interrupts */ free_irq(irq, NULL); dev.count--; return 0; } ssize_t can_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { int pos; if(dev.nm_rb == 0) { /* No messages in the buffer */ if(filp->f_flags & O_NONBLOCK) return -EAGAIN; /* If nonblocking mode return -EAGAIN */ interruptible_sleep_on(&inq); /* If blocking mode put it to sleep */ if(signal_pending(current)) return -ERESTARTSYS; } pos = dev.rp_rb; /* Copy 1 message to user space */ if(dev.nm_rb > 0) { /* at least one message in the buffer */ copy_to_user(buf, &dev.read_buf[pos], MSG_LENGTH); /* Copy message to buf */ dev.nm_rb--; dev.rp_rb++; if(dev.rp_rb == dev.wp_rb) { /* Buffer empty */ dev.rp_rb = 0; dev.wp_rb = 0; } return MSG_LENGTH; } else return -EAGAIN; /* No messages available */ } ssize_t can_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { int pos; pos = dev.wp_wb; if(dev.nm_wb == BUFFER_SIZE) { /* If buffer full */ if(filp->f_flags & O_NONBLOCK) return -EAGAIN; /* If nonblocking mode return -EAGAIN (try again) */ interruptible_sleep_on(&outq); /* If blocking mode put it to sleep */ if(signal_pending(current)) return -ERESTARTSYS; } if(dev.nm_wb < BUFFER_SIZE) { /* Buffer released to write */ copy_from_user(&dev.write_buf[pos], buf, MSG_LENGTH); /* Copy frame from user area to the kernel (driver) area */ dev.nm_wb++; dev.wp_wb++; write_to_SJA1000(); return MSG_LENGTH; } else return -EAGAIN; } unsigned int can_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; poll_wait(filp, &inq, wait); poll_wait(filp, &outq, wait); if(dev.nm_rb > 0) /* at least one message in the buffer */ mask |= POLLIN | POLLRDNORM; /* readable */ if(dev.nm_wb < BUFFER_SIZE) /* at least one message in the buffer */ mask |= POLLOUT | POLLWRNORM; /* readable */ return mask; } int can_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg0) { int a, err=0; int arg; canconfig *cf; get_user(arg, (int *)arg0); /* Extract the type and number bitfields, and don't decode * wrong cmds: return EINVAL before verify_area() */ if(_IOC_TYPE(cmd) != CAN_IOC_MAGIC) return -EINVAL; if(_IOC_NR(cmd) > CAN_IOC_MAXNR) return -EINVAL; /* * The direction is a bitmask, and VERIFY_WRITE catches R/W * transfers. `Type' is user oriented, while * access_ok is kernel oriented, so the concept of "read" and * "write" is reversed */ if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg0, _IOC_SIZE(cmd)); else if(_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg0, _IOC_SIZE(cmd)); if(err) return -EFAULT; switch(cmd) { case CAN_IOCSBAUD: /* Set baudrate of the bus */ if((arg >= 0) && (arg <= 4)) { can_w(MODE, 0x01); /* RESET Mode */ for(a=0; a<1000; a++); can_w(BUS_TIMING_0, baud_tab[arg].bt0); can_w(BUS_TIMING_1, baud_tab[arg].bt1); can_w(MODE, STANDARD_MODE); /* Define Interrupt Mask, deactivate RESET */ dev.baud_rate = arg; return 0; } case CAN_IOCSAMASK: /* Set Acceptance Mask */ can_w(MODE, 0x01); for(a=0; a<1000; a++); can_w(ACCEPTANCE_MASK+3, (unsigned char)arg); can_w(ACCEPTANCE_MASK+2, (unsigned char)(arg >> 8)); can_w(ACCEPTANCE_MASK+1, (unsigned char)(arg >> 16)); can_w(ACCEPTANCE_MASK, (unsigned char)(arg >> 24)); can_w(MODE, STANDARD_MODE); return 0; case CAN_IOCSACODE: /* Set Acceptance Code */ can_w(MODE, 0x01); for(a=0; a<1000; a++); can_w(FRAME_INFORMATION+3, (unsigned char)arg); can_w(FRAME_INFORMATION+2, (unsigned char)(arg >> 8)); can_w(FRAME_INFORMATION+1, (unsigned char)(arg >> 16)); can_w(FRAME_INFORMATION, (unsigned char)(arg >> 24)); can_w(MODE, STANDARD_MODE); return 0; case CAN_IOCCRBUF: /* Clear the read buffer */ dev.nm_rb = 0; /* 0 messages in the read buffer */ dev.wp_rb = 0; /* initial write position in the read buffer */ dev.rp_rb =0; /* initial read position in the read buffer */ return 0; case CAN_IOCCWBUF: /* Clear the read buffer */ dev.nm_wb = 0; /* 0 messages in the write buffer */ dev.wp_wb = 0; /* initial write position in the write buffer */ dev.rp_wb =0; /* initial read position in the write buffer */ return 0; case CAN_IOCRREG: /* Read SJA1000 register */ return can_r((unsigned char)arg); case CAN_IOCRTTS: /* Read last transmit timestamp */ copy_to_user((struct timeval *)arg0, &transmit_timestamp, sizeof(struct timeval)); return 0; case CAN_IOCSACTIVE: /* set active mode */ can_w(MODE, 0x08); /* Deactivate RESET, single acceptance filter */ can_w(RX_ERROR_COUNTER, 0); /* Clear the reception error counter */ can_w(TX_ERROR_COUNTER, 0); /* Clear the transmission error counter */ printk("CAN: entering active mode\n"); dev.active_passive_status = ACTIVE; return 0; case CAN_IOCSPASSIVE: /* set passive mode */ can_w(MODE, 0x0A); /* Deactivate RESET, single acceptance filter */ printk("CAN: entering passive mode\n"); dev.active_passive_status = PASSIVE; return 0; case CAN_IOCRAPS: /* read active/passive status */ return dev.active_passive_status; case CAN_IOCSBTR: /* set bit timing registers */ cf = (canconfig *)arg0; can_w(MODE, 0x01); /* RESET Mode */ for(a=0; a<1000; a++); can_w(BUS_TIMING_0, cf->bt0); can_w(BUS_TIMING_1, cf->bt1); can_w(MODE, STANDARD_MODE); /* Define Interrupt Mask, deactivate RESET */ return 1; default: /* redundant */ return -EINVAL; } return 0; } struct file_operations can_fops = { read: can_read, write: can_write, ioctl: can_ioctl, open: can_open, release: can_release, poll: can_poll, owner: THIS_MODULE, /* avoid the module from being unloaded when someone is still accessing the driver */ }; int can_init(void) { int result; result = check_region(port, NUMBER_OF_PORTS); if(result) { printk(KERN_INFO "CAN: can't get I/O port address 0x%x\n", port); return -EBUSY; } request_region(port, NUMBER_OF_PORTS, "can"); result = register_chrdev(CAN_MAJOR, "can", &can_fops); if(result < 0) { printk("CAN: Couldn't register can driver\n"); goto fail_check_region; } dev.count = 0; show_can_version(); can_create_proc(); return result; /* ugly, but it is the only way */ fail_check_region: release_region(port, NUMBER_OF_PORTS); /* fail_regiter_chrdev: unregister_chrdev(CAN_MAJOR, "can"); */ return -EBUSY; } void can_cleanup(void) { unregister_chrdev(CAN_MAJOR, "can"); release_region(port, NUMBER_OF_PORTS); can_remove_proc(); printk(DRIVER_VERSION); printk(" unloaded\n"); } /** * Low level routines for access through the paralel port * This driver operates with the paralel port in the EPP mode. * The parallel port must be set to EPP mode in the BIOS. * * Theory of operation: * A read/write cycle from/to the can dongle is composed of two steps. * First, the address of the register to read/write is transferred. * Secondly, the value of the register is read/written. * * To destinguish a read from a write cycle, the MSB of the byte written * in the first step is used. If it is 0, then the second byte will be written, * if it is 1, then the second byte will be read. * * For handshaking, the can dongle is using 5 control lines of the * parallel port, namely bits 4-0 of the control port: * -> Enable IRQ via ACK => ??? * -> Select Printer => ispEN * -> Initialize Printer => x * -> Auto Linefeed => Mode * -> Strobe => Strb * * Bit 4 should always be set to 1. * ispEN should be set to 1 at all times while using the dongle; it probably enables the outputs of the glue logic inside the dongle. * x should also be set to 1 at all times. * Mode selects between Nibble (0) and Bidirectional (1) Mode of the dongle. * Strb will signal the glue logic, when to read/write a byte. A high-to-low transition will read the address, and a low-to-high transition * will read/write the data. * In Nibble Mode, data bit 6 is used to select the nibble, but better forget about that. * * A write cycle to the SJA1000 is done like this: * - put the control lines ispEN, x, Mode and Strb to the starting pattern of 1101 * - put the register address to the data lines with the MSB set to 0 for a write cycle * - pull Strb to low (will make the dongle read the register address and r/w control bit) * and pull Mode to high to enable 8 Bit transfers * - put the register value to the data lines * - pull Strb to high (will make the dongle read the register value) * * A read cycle to the SJA1000 is done like this: * - put the control lines ispEN, x, Mode and Strb to the starting pattern of 1111 * - put the register address to the data lines with the MSB set to 1 for a read cycle * - pull Strb low (will make the dongle read the register address and r/w control bit) * and set the parallel port to tristate mode (Bit 5 = 1 in the control port) * - read the data from the parallel port (and hope that the dongle was fast enough) * - pull Strb back to high */ int can_w(enum can_registers id, unsigned char value) { // 0x1D = SPP_ENABLE_IRQ_VIA_ACK | SPP_SELECT_PRINTER | SPP_INITIALIZE_PRINTER | SPP_STROBE // 0x1E = SPP_ENABLE_IRQ_VIA_ACK | SPP_SELECT_PRINTER | SPP_INITIALIZE_PRINTER | SPP_AUTO_LINEFEED // 0x1F = SPP_ENABLE_IRQ_VIA_ACK | SPP_SELECT_PRINTER | SPP_INITIALIZE_PRINTER | SPP_AUTO_LINEFEED | SPP_STROBE // // 0x1D Reg 0x1E Val 0x1F // __________________________________________________________________________________ // EnIRQ #########/ // __________________________________________________________________________________ // Select #########/ // __________________________________________________________________________________ // Init #########/ // _____________________________________________________________ // Linefeed #########\____________________/ // ____________________ ___________________________________________ // Strobe #########/ \_________________/ // // Data[] ####################><================><==================================================== /* step 1 - write register address */ WR_PP_CONTROL( DONGLE_STANDARD ); // original: 0x1d!!! is this one ok??? FIXME WR_REGISTER( id, DONGLE_WRITE_CYCLE ); WR_PP_CONTROL( DONGLE_WRITE_ADDRESS ); /* step 2 - write data */ outb( value, PP_DATA ); WR_PP_CONTROL( DONGLE_STANDARD ); return 0; } int can_r(enum can_registers id) { unsigned char value; /* step 1 - write register address */ WR_PP_CONTROL( DONGLE_STANDARD ); WR_REGISTER( id, DONGLE_READ_CYCLE ); WR_PP_CONTROL( DONGLE_WRITE_ADDRESS | DONGLE_READ_CYCLE ); /* step 2 - read data */ value = inb( PP_DATA ); WR_PP_CONTROL( DONGLE_STANDARD ); return value; } module_init(can_init); module_exit(can_cleanup);