-/* virtual.c
- * Linux CAN-bus device driver.
- * Written for new CAN driver version by Pavel Pisa - OCERA team member
- * email:pisa@cmp.felk.cvut.cz
- * This software is released under the GPL-License.
- * Version lincan-0.2 9 Jul 2003
- */
-
-#include <linux/autoconf.h>
-
-#include <linux/delay.h>
-#include <asm/errno.h>
+/**************************************************************************/
+/* File: virtual.c - virtual chip/board support */
+/* */
+/* LinCAN - (Not only) Linux CAN bus driver */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
+/* Funded by OCERA and FRESCOR IST projects */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
+/* */
+/* LinCAN is free software; you can redistribute it and/or modify it */
+/* under terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2, or (at your option) any */
+/* later version. LinCAN 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 LinCAN; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* To allow use of LinCAN in the compact embedded systems firmware */
+/* and RT-executives (RTEMS for example), main authors agree with next */
+/* special exception: */
+/* */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce */
+/* an application image/executable, does not by itself cause the */
+/* resulting application image/executable to be covered by */
+/* the GNU General Public License. */
+/* This exception does not however invalidate any other reasons */
+/* why the executable file might be covered by the GNU Public License. */
+/* Publication of enhanced or derived LinCAN files is required although. */
+/**************************************************************************/
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
+
+long virtual_bus_latency(struct msgobj_t *obj)
+{
+ long latency;
+ latency=obj->hostchip->baudrate;
+ if(latency){
+ latency=(long)HZ*1000/latency;
+ }
+ return latency;
+}
+
+
/* * * Virtual Chip Functionality * * */
-int virtual_enable_configuration(struct chip_t *chip)
+int virtual_enable_configuration(struct canchip_t *chip)
{
return 0;
}
-int virtual_disable_configuration(struct chip_t *chip)
+int virtual_disable_configuration(struct canchip_t *chip)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_chip_config(struct chip_t *chip)
+int virtual_chip_config(struct canchip_t *chip)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_extended_mask(struct chip_t *chip, unsigned long code, unsigned long mask)
+int virtual_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_baud_rate(struct chip_t *chip, int rate, int clock, int sjw,
+int virtual_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
int sampl_pt, int flags)
{
return 0;
*
* File: src/virtual.c
*/
-void virtual_read(struct chip_t *chip, struct msgobj_t *obj) {
+void virtual_read(struct canchip_t *chip, struct msgobj_t *obj) {
}
* Positive value indicates immediate reception of message.
* File: src/virtual.c
*/
-int virtual_pre_read_config(struct chip_t *chip, struct msgobj_t *obj)
+int virtual_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
+int virtual_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
struct canmsg_t *msg)
{
return 0;
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_send_msg(struct chip_t *chip, struct msgobj_t *obj,
+int virtual_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
struct canmsg_t *msg)
{
return 0;
* Zero value indicates finishing of all issued transmission requests.
* File: src/virtual.c
*/
-int virtual_check_tx_stat(struct chip_t *chip)
+int virtual_check_tx_stat(struct canchip_t *chip)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_set_btregs(struct chip_t *chip, unsigned short btr0,
+int virtual_set_btregs(struct canchip_t *chip, unsigned short btr0,
unsigned short btr1)
{
return 0;
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_start_chip(struct chip_t *chip)
+int virtual_start_chip(struct canchip_t *chip)
{
return 0;
}
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_stop_chip(struct chip_t *chip)
+int virtual_stop_chip(struct canchip_t *chip)
{
return 0;
}
+/**
+ * virtual_attach_to_chip: - attaches to the chip, setups registers and state
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/virtual.c
+ */
+int virtual_attach_to_chip(struct canchip_t *chip)
+{
+ return 0;
+}
+
+/**
+ * virtual_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/virtual.c
+ */
+int virtual_release_chip(struct canchip_t *chip)
+{
+ virtual_stop_chip(chip);
+ return 0;
+}
/**
* virtual_remote_request: - configures message object and asks for RTR message
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_remote_request(struct chip_t *chip, struct msgobj_t *obj)
+int virtual_remote_request(struct canchip_t *chip, struct msgobj_t *obj)
{
CANMSG("virtual_remote_request not implemented\n");
return -ENOSYS;
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_standard_mask(struct chip_t *chip, unsigned short code,
+int virtual_standard_mask(struct canchip_t *chip, unsigned short code,
unsigned short mask)
{
CANMSG("virtual_standard_mask not implemented\n");
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_clear_objects(struct chip_t *chip)
+int virtual_clear_objects(struct canchip_t *chip)
{
CANMSG("virtual_clear_objects not implemented\n");
return -ENOSYS;
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_config_irqs(struct chip_t *chip, short irqs)
+int virtual_config_irqs(struct canchip_t *chip, short irqs)
{
CANMSG("virtual_config_irqs not implemented\n");
return -ENOSYS;
* virtual_irq_write_handler() for transmit events.
* File: src/virtual.c
*/
-void virtual_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
+void virtual_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
{
}
* @irq: interrupt vector number, this value is system specific
* @dev_id: driver private pointer registered at time of request_irq() call.
* The CAN driver uses this pointer to store relationship of interrupt
- * to chip state structure - @struct chip_t
+ * to chip state structure - @struct canchip_t
* @regs: system dependent value pointing to registers stored in exception frame
*
* Interrupt handler is activated when state of CAN controller chip changes,
* message queues.
* File: src/virtual.c
*/
-irqreturn_t virtual_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+int virtual_irq_handler(int irq, struct canchip_t *chip)
+{
+ return CANCHIP_IRQ_HANDLED;
+}
+
+
+void virtual_schedule_next(struct msgobj_t *obj)
{
- return IRQ_HANDLED;
+ int cmd;
+
+ can_preempt_disable();
+
+ can_msgobj_set_fl(obj,TX_REQUEST);
+
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+
+ can_msgobj_clear_fl(obj,TX_REQUEST);
+
+ cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+ if(cmd>=0) {
+ mod_timer(&obj->tx_timeout,
+ jiffies+virtual_bus_latency(obj));
+ DEBUGMSG("virtual: scheduled delivery\n");
+
+ } else
+ can_msgobj_clear_fl(obj,TX_LOCK);
+
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+ DEBUGMSG("TX looping in virtual_schedule_next\n");
+ }
+
+ can_preempt_enable();
+}
+
+
+void virtual_do_tx_timeout(unsigned long data)
+{
+ struct msgobj_t *obj=(struct msgobj_t *)data;
+
+ if(obj->tx_slot) {
+ /* fill CAN message timestamp */
+ can_filltimestamp(&obj->tx_slot->msg.timestamp);
+
+ /* Deliver message to edges */
+ canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+ /* Free transmitted slot */
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot=NULL;
+ DEBUGMSG("virtual: delayed delivery\n");
+ }
+ can_msgobj_clear_fl(obj,TX_LOCK);
+
+ virtual_schedule_next(obj);
}
/**
* @chip: pointer to chip state structure
* @obj: pointer to message object structure
*
+ * Function is responsible for initiating message transmition.
+ * It is responsible for clearing of object TX_REQUEST flag
+ *
* Return Value: negative value reports error.
* File: src/virtual.c
*/
-int virtual_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
+int virtual_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
{
- /* set_bit(OBJ_TX_REQUEST,&obj->flags); */
+ /* can_msgobj_set_fl(obj,TX_REQUEST); */
struct canque_edge_t *qedge;
struct canque_slot_t *slot;
int cmd;
-
- /* Ensure delivery of all ready slots */
-
- while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
- if(cmd==0) {
- canque_filter_msg2edges(obj->qends, &slot->msg);
+
+ can_msgobj_clear_fl(obj,TX_REQUEST);
+
+ #ifndef CAN_WITH_RTL
+ if(!virtual_bus_latency(obj)) {
+ #endif /*CAN_WITH_RTL*/
+ /* Ensure delivery of all ready slots */
+ while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
+ if(cmd==0) {
+ /* fill CAN message timestamp */
+ can_filltimestamp(&slot->msg.timestamp);
+
+ canque_filter_msg2edges(obj->qends, &slot->msg);
+ DEBUGMSG("virtual: direct delivery\n");
+ }
+ canque_free_outslot(obj->qends, qedge, slot);
}
- canque_free_outslot(obj->qends, qedge, slot);
+ #ifndef CAN_WITH_RTL
+ } else {
+ virtual_schedule_next(obj);
}
+ #endif /*CAN_WITH_RTL*/
return 0;
}
candev->nr_82527_chips=0;
candev->nr_sja1000_chips=0;
candev->nr_all_chips=1;
- candev->flags |= PROGRAMMABLE_IRQ*0;
+ candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
return 0;
}
*/
int virtual_init_chip_data(struct candevice_t *candev, int chipnr)
{
- struct chip_t *chip = candev->chip[chipnr];
+ struct canchip_t *chip = candev->chip[chipnr];
chip->chip_type = CHIP_TYPE;
chip->chip_base_addr = 0;
chip->clock = 10000000;
chip->chipspecops->remote_request=virtual_remote_request;
chip->chipspecops->enable_configuration=virtual_enable_configuration;
chip->chipspecops->disable_configuration=virtual_disable_configuration;
+ chip->chipspecops->attach_to_chip=virtual_attach_to_chip;
+ chip->chipspecops->release_chip=virtual_release_chip;
chip->chipspecops->set_btregs=virtual_set_btregs;
chip->chipspecops->start_chip=virtual_start_chip;
chip->chipspecops->stop_chip=virtual_stop_chip;
chip->chipspecops->irq_handler=NULL;
+ chip->chipspecops->irq_accept=NULL;
return 0;
}
* Return Value: The function always returns zero
* File: src/virtual.c
*/
-int virtual_init_obj_data(struct chip_t *chip, int objnr)
+int virtual_init_obj_data(struct canchip_t *chip, int objnr)
{
- chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
- chip->msgobj[objnr]->flags=0;
+ struct msgobj_t *obj=chip->msgobj[objnr];
+ obj->obj_base_addr=chip->chip_base_addr;
+ obj->tx_timeout.function=virtual_do_tx_timeout;
+ obj->tx_timeout.data=(unsigned long)obj;
return 0;
}