📄 mcp2515funcs.c
字号:
DBGprint(DBG_DATA, ("refused baud[%d]=%d already set to %d", minor, baud, Baud[minor])); return -1; } DBGprint(DBG_DATA, ("baud[%d]=%d", minor, baud)); switch(baud) { case 10: i = 0; break; case 20: i = 1; break; case 50: i = 2; break; case 100: i = 3; break; case 125: i = 4; break; case 250: i = 5; break; case 500: i = 6; break; case 800: i = 7; break; case 1000: i = 8; break; default : custom = 1; } if(custom) { dev_info(&priv->dev, "%s, no custom bit register setting yet\n", __FUNCTION__); } else { mcp251x_write_reg(CNF1, (u8)CanTiming[i][0]); mcp251x_write_reg(CNF2, (u8)CanTiming[i][1]); mcp251x_write_reg(CNF3, (u8)(CanTiming[i][1] >> 8)); } DBGout(); return 0;}int CAN_StartChip(int minor){ DBGin(); RxErr[minor] = TxErr[minor] = 0L; /* empty error counters */ /* clear interrupts */ /* nothing to do ? */ /* Interrupts on Rx, TX, any Status change and data overrun */ /* The CANINTE register contains the individual interrupt enable bits * for each interrupt source. */ mcp251x_write_reg(CANINTE, CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE | CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE ); if(listenmode == 1 ) { mcp251x_write_reg(CANCTRL, CANCTRL_REQOP_LISTEN_ONLY); udelay(10); } else { mcp251x_write_reg(CANCTRL, CANCTRL_REQOP_NORMAL); while (mcp251x_read_reg(CANSTAT) & 0xE0) udelay(10); } /* Reset error conditions */ mcp251x_write_reg(EFLG, 0); DBGout(); return 0;}int CAN_StopChip(int minor){ DBGin(); /* FIXME: Issue CAN controller reset */ /* Disable and clear pending interrupts */ mcp251x_write_reg(CANINTE, 0x00); mcp251x_write_reg(CANINTF, 0x00); mcp251x_write_reg(CANCTRL, CANCTRL_REQOP_CONF); /* Wait for the device to enter config mode */ while ((mcp251x_read_reg(CANSTAT) & 0x80) == 0) udelay(10); DBGout(); return 0;}/* set value of the output control register */int CAN_SetOMode (int minor, int arg){ DBGin(); DBGprint(DBG_DATA,("[%d] outc=0x%x", minor, arg)); printk(KERN_INFO "no \"output mode\" to set\n"); DBGout(); return 0;}/*Listen-Only ModeIn listen-only mode, the CAN module is able to receive messageswithout giving an acknowledgment.Since the module does not influence the CAN bus in this modethe host device is capable of functioning like a monitoror for automatic bit-rate detection. must be done after CMD_START (CAN_StopChip) and before CMD_START (CAN_StartChip) MCP2515:Listen-only mode provides a means for the MCP2515 to receiveall messages (including messages with errors) by configuring theRXBnCTRL.RXM<1:0> bits.The Listen-only mode is activated by setting the mode request bitsin the CANCTRL register. bit 7-5 REQOP: Request Operation Mode bits <2:0> 000 = Set Normal Operation mode CANCTRL_REQOP_NORMAL 001 = Set Sleep mode 010 = Set Loopback mode 011 = Set Listen-only mode CANCTRL_REQOP_LISTEN_ONLY 100 = Set Configuration mode CANCTRL_REQOP_CONF All other values for REQOP bits are invalid and should not be used*/int CAN_SetListenOnlyMode(int minor, int arg){ DBGin(); if (arg) { /* switch to listen only mode */ mcp251x_write_reg(CANCTRL, CANCTRL_REQOP_LISTEN_ONLY); listenmode = 1; } else { /* switch to normal mode */ mcp251x_write_reg(CANCTRL, CANCTRL_REQOP_NORMAL); listenmode = 0; } /* while (mcp251x_read_reg(CANSTAT) & 0xE0) */ udelay(10); DBGout(); return 0;}/*The mask and filter registers can only be modifiedwhen the MCP2515 is in Configuration mode (seeSection 10.0 "Modes of Operation").Used is only Mask1 and Filter1 Extended Frame+---------------+-------------------------------------------------+|ID10 ID0 | EID17 EID0|+---------------+-------------------------------------------------+ Masks and Filters apply to the entire 29-bit ID field*/int CAN_SetMask(int minor, unsigned int code, unsigned int mask){struct mcp251x_priv *priv = &realone;//struct spi_device *spi = spidevice[minor]; DBGin(); dev_dbg(&priv->dev, "%s: not implemented\n", __FUNCTION__); DBGprint(DBG_DATA,("[%d] acc=0x%x mask=0x%x", minor, code, mask)); mcp251x_write_reg(RXM0SIDH, (u8)(mask >> 24)); mcp251x_write_reg(RXM0SIDL, (u8)(mask >> 16)); mcp251x_write_reg(RXM0EID8, (u8)(mask >> 8)); mcp251x_write_reg(RXM0EID0, (u8)(mask >> 0)); mcp251x_write_reg(RXF0SIDH, (u8)(code >> 24)); mcp251x_write_reg(RXF0SIDL, (u8)(code >> 16)); mcp251x_write_reg(RXF0EID8, (u8)(code >> 8)); mcp251x_write_reg(RXF0EID0, (u8)(code >> 0)); DBGout(); return 0;}/* CAN_SendMessage send a single CAN frame using SPI Blocktransfer */int CAN_SendMessage(int minor, canmsg_t *tx){ struct mcp251x_priv *priv = &realone; u8 *tx_buf = priv->spi_tx_buf; /* u8 *rx_buf = priv->spi_rx_buf; */ u32 sid, eid, ext, rtr; /* DBGin(); */ sid = tx->id & CAN_SFF_MASK; /* Standard ID */ eid = tx->id & CAN_EFF_MASK; /* Extended ID */ ext = (tx->flags & MSG_EXT) ? 1 : 0; /* Extended ID Enable */ rtr = (tx->flags & MSG_RTR) ? 1 : 0; /* Remote transmission */ down(&priv->spi_lock); tx_buf[0] = INSTRUCTION_LOAD_TXB(TRANSMIT_OBJ); if(ext) { tx_buf[1] = (eid >> 21) & 0xff; tx_buf[2] = ((eid >> 13) & 0xe0) + 0x08 + ((eid & 0x30000) >> 16); tx_buf[3] = (eid & 0xff00) >> 8; tx_buf[4] = (eid & 0xff); } else { tx_buf[1] = sid >> 3; tx_buf[2] = (sid << 5); } tx_buf[5] = (rtr << 6) | tx->length; /* copy data to spi buffer */ memcpy(tx_buf + 6, tx->data, tx->length); at91_spihw_rwn(priv->spi_tx_buf, priv->spi_rx_buf, 6 + CAN_FRAME_MAX_DATA_LEN); up(&priv->spi_lock);#if 1 down(&priv->spi_lock); at91_spihw_wr8(MCP_RTS_TX0);#ifdef CANSPI_USEKTHREAD udelay(500); /* test with busyloop do { tx_buf[0] = 0xA0; at91_spihw_rwn(priv->spi_tx_buf, priv->spi_rx_buf, 1); } while (rx_buf[0] & 0x04); */#endif up(&priv->spi_lock);#else mcp251x_write_reg(TXBCTRL(TRANSMIT_OBJ), TXBCTRL_TXREQ);#endif /* * Save last message that was sent. * Since can4linux 3.5 multiple processes can access * one CAN interface. On a CAN interrupt this message is copied into * the receive queue of each process that opened this same CAN interface. */ memcpy( (void *)&last_Tx_object[minor], (void *)tx, sizeof(canmsg_t)); /* DBGout(); */ return 0;}/* * Perform Vendor, that means sometimes CAN controller * or only board manufacturer specific initialization. * * Mainly it gets needed IO and IRQ ressources and initilaizes * special hardware functions. * * This code should normally be in the CAN_VendorInit() function * in a TARGET specific file target.c */int CAN_VendorInit (int minor){ DBGin(); /* SPI specific Tasks: * register the ISR * enable the PIO pins wher the CAN is connected to * * CAN interrupts are later enabled in * CAN_StartChip(minor) * according to can4linux rules */ if( IRQ[minor] > 0 || IRQ[minor] > MAX_IRQNUMBER ){ if( Can_RequestIrq(minor, IRQ[minor] , CAN_Interrupt) ) { printk("Can[%d]: Can't request IRQ %d \n", minor, IRQ[minor]); DBGout(); return -EBUSY; } } else { /* Invalid IRQ number in /proc/.../IRQ */ DBGout(); return -EBUSY; } listenmode = 0; /* sot NORMAL mode when opening the driver */ /* arrange the PIO interrupt on PB24 */ /* board-sbc9263.c */ DBGout(); return 0;}int Can_RequestIrq(int minor, int irq, irqreturn_t (*handler)(int, void *)){int err = 0; DBGin(); /* int request_irq(unsigned int irq, // interrupt number void (*handler)(int, void *, struct pt_regs *), // pointer to ISR irq, dev_id, registers on stack unsigned long irqflags, const char *devname, void *dev_id); dev_id - The device ID of this handler (see below). This parameter is usually set to NULL, but should be non-null if you wish to do IRQ sharing. This doesn't matter when hooking the interrupt, but is required so that, when free_irq() is called, the correct driver is unhooked. Since this is a void *, it can point to anything (such as a device-spe- cific structure, or even empty space), but make sure you pass the same pointer to free_irq(). */ /* From include/linux/irq.h IRQ line status. IRQ types IRQ_TYPE_NONE Default, unspecified type IRQ_TYPE_EDGE_RISING Edge rising type IRQ_TYPE_EDGE_FALLING Edge falling type IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) IRQ_TYPE_LEVEL_HIGH Level high type IRQ_TYPE_LEVEL_LOW Level low type IRQ_TYPE_SENSE_MASK Mask of the above IRQ_TYPE_PROBE Probing in progress From include/linux/irq.h IRQF_DISABLED - keep irqs disabled when calling the action handler */ /* We don't need the interrupt to be shared for now */ /* On AT91 IRQF_DISABLED - recognized IRQF_NOBALANCING - not IRQF_TRIGGER_FALLING, - not */ disable_irq(gpio_to_irq(AT91_PIN_PB24));#if 0 /* TODO: IRQF_DISABLED must work - fix handler */ err = request_irq(irq, handler, IRQF_NOBALANCING | IRQF_TRIGGER_FALLING, "Can", &Can_minors[minor]);#else err = request_irq(irq, handler, IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_FALLING, "Can", &Can_minors[minor]);#endif if( !err ){ DBGprint(DBG_BRANCH,("Requested IRQ: %d @ 0x%lx", irq, (unsigned long)handler)); IRQ_requested[minor] = 1; } DBGout(); return err;}int Can_FreeIrq(int minor, int irq ){ DBGin(); IRQ_requested[minor] = 0; /* printk(" Free IRQ %d minor %d\n", irq, minor); */ free_irq(irq, &Can_minors[minor]); DBGout(); return 0;}/* insert_rxfifo * insert a CAN frame, pointed to by 'frame' * into the active rx_fifos * The driver can handle an rx_fifo for each * process which open() the driver */static void insert_rxfifo(int minor, canmsg_t *frame){msg_fifo_t *RxFifo; /* pointer to the active FIFO */int rx_fifo; /* looping through these fifo indicies */ DBGin(); /* handle all subscribed rx fifos */ for(rx_fifo = 0; rx_fifo < CAN_MAX_OPEN; rx_fifo++) { /* for every rx fifo */ if (CanWaitFlag[minor][rx_fifo] == 1) { /* this FIFO is in use */ RxFifo = &Rx_Buf[minor][rx_fifo]; /* prepare buffer to be used */ (RxFifo->data[RxFifo->head]).flags = frame->flags; (RxFifo->data[RxFifo->head]).id = frame->id; (RxFifo->data[RxFifo->head]).length = frame->length; (RxFifo->data[RxFifo->head]).timestamp = frame->timestamp; memcpy( &(RxFifo->data[RxFifo->head]).data[0], &frame->data[0], frame->length); /* mark just written entry as OK and full */ RxFifo->status = BUF_OK; /* Handle buffer wrap-around */ RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE; if(RxFifo->head == RxFifo->tail) { printk("CAN[%d][%d] RX: FIFO overrun\n", minor, rx_fifo); RxFifo->status = BUF_OVERRUN; } /*---------- kick the select() call -*/ /* This function will wake up all processes that are waiting on this event queue, that are in interruptible sleep */ wake_up_interruptible(&CanWait[minor][rx_fifo]); } } /* end loop fill rx buffers */ DBGout();}/* Read an CAN Frame from the MCP2515 hardware from the numbered RX hardware bufferand store it in the drivers rx queues*/static void mcp251x_hw_rx( struct spi_device *spi, int buf_idx, struct timeval *tv ){/* struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); */struct mcp251x_priv *priv = &realone;u8 *tx_buf = priv->spi_tx_buf;u8 *rx_buf = priv->spi_rx_buf;msg_fifo_t *RxFifo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -