diff options
-rw-r--r-- | package/ucmb/Makefile | 5 | ||||
-rw-r--r-- | package/ucmb/driver/Makefile (renamed from package/ucmb/src/Makefile) | 0 | ||||
-rw-r--r-- | package/ucmb/driver/ucmb.c (renamed from package/ucmb/src/ucmb.c) | 72 | ||||
-rw-r--r-- | package/ucmb/driver/ucmb.h | 38 | ||||
-rw-r--r-- | package/ucmb/src/ucmb.h | 14 |
5 files changed, 100 insertions, 29 deletions
diff --git a/package/ucmb/Makefile b/package/ucmb/Makefile index b0b569e..793fb9e 100644 --- a/package/ucmb/Makefile +++ b/package/ucmb/Makefile @@ -12,9 +12,10 @@ PKG_RELEASE:=1 include $(INCLUDE_DIR)/package.mk + define KernelPackage/ucmb SUBMENU:=Other modules - DEPENDS:=@LINUX_2_6 +kmod-spi-gpio + DEPENDS:=@LINUX_2_6 +kmod-spi-gpio +kmod-crc16 KCONFIG:=CONFIG_SPI=y \ CONFIG_SPI_MASTER=y TITLE:=Microcontroller Message Bus (EXPERIMENTAL) @@ -24,7 +25,7 @@ endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ + $(CP) ./driver/* $(PKG_BUILD_DIR)/ endef define Build/Compile diff --git a/package/ucmb/src/Makefile b/package/ucmb/driver/Makefile index a232a4a..a232a4a 100644 --- a/package/ucmb/src/Makefile +++ b/package/ucmb/driver/Makefile diff --git a/package/ucmb/src/ucmb.c b/package/ucmb/driver/ucmb.c index c2cb1a9..276553a 100644 --- a/package/ucmb/src/ucmb.c +++ b/package/ucmb/driver/ucmb.c @@ -17,10 +17,13 @@ #include <linux/spi/spi_bitbang.h> #include <linux/gfp.h> #include <linux/delay.h> +#include <linux/crc16.h> #define PFX "ucmb: " +#define DEBUG + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microcontroller Message Bus"); @@ -28,6 +31,8 @@ MODULE_AUTHOR("Michael Buesch"); struct ucmb { + unsigned int msg_delay_ms; + /* Misc character device driver */ struct miscdevice mdev; struct file_operations mdev_fops; @@ -45,6 +50,10 @@ struct ucmb_message_hdr { __le16 len; /* Payload length (excluding header) */ } __attribute__((packed)); +struct ucmb_message_footer { + __le16 crc; /* CRC of the header + payload. */ +} __attribute__((packed)); + struct ucmb_status { __le16 magic; /* UCMB_MAGIC */ __le16 code; /* enum ucmb_status_code */ @@ -58,6 +67,7 @@ enum ucmb_status_code { UCMB_STAT_EPROTO, /* Protocol format error */ UCMB_STAT_ENOMEM, /* Out of memory */ UCMB_STAT_E2BIG, /* Message too big */ + UCMB_STAT_ECRC, /* CRC error */ }; @@ -71,6 +81,9 @@ static struct ucmb_platform_data ucmb_list[] = { .gpio_sck = 0, .gpio_miso = 1, .gpio_mosi = 2, + .mode = SPI_MODE_0, + .max_speed_hz = 128000, /* Hz */ + .msg_delay_ms = 1, /* mS */ }, }; @@ -106,6 +119,8 @@ static int ucmb_status_code_to_errno(enum ucmb_status_code code) return -ENOMEM; case UCMB_STAT_E2BIG: return -E2BIG; + case UCMB_STAT_ECRC: + return -EBADMSG; } return -EBUSY; } @@ -115,7 +130,6 @@ static inline struct ucmb * filp_to_ucmb(struct file *filp) return container_of(filp->f_op, struct ucmb, mdev_fops); } -/* FIXME offp */ static ssize_t ucmb_read(struct file *filp, char __user *user_buf, size_t size, loff_t *offp) { @@ -123,13 +137,11 @@ static ssize_t ucmb_read(struct file *filp, char __user *user_buf, u8 *buf; int res, err; struct ucmb_message_hdr hdr; + struct ucmb_message_footer footer; struct ucmb_status status = { .magic = cpu_to_le16(UCMB_MAGIC), }; + u16 crc = 0xFFFF; - err = -E2BIG; - if (size > PAGE_SIZE) - goto out; - if (size > UCMB_MAX_MSG_LEN) - goto out; + size = min_t(size_t, size, PAGE_SIZE); err = -ENOMEM; buf = (char *)__get_free_page(GFP_KERNEL); @@ -139,6 +151,10 @@ static ssize_t ucmb_read(struct file *filp, char __user *user_buf, err = spi_read(ucmb->sdev, (u8 *)&hdr, sizeof(hdr)); if (err) goto out_free; +#ifdef DEBUG + printk(KERN_DEBUG PFX "Received message header 0x%04X 0x%04X\n", + le16_to_cpu(hdr.magic), le16_to_cpu(hdr.len)); +#endif err = -EPROTO; if (hdr.magic != cpu_to_le16(UCMB_MAGIC)) goto out_free; @@ -149,15 +165,29 @@ static ssize_t ucmb_read(struct file *filp, char __user *user_buf, err = spi_read(ucmb->sdev, buf, size); if (err) goto out_free; + err = spi_read(ucmb->sdev, (u8 *)&footer, sizeof(footer)); + if (err) + goto out_free; - err = -EFAULT; - if (copy_to_user(user_buf, buf, size)) + crc = crc16(crc, &hdr, sizeof(hdr)); + crc = crc16(crc, buf, size); + crc ^= 0xFFFF; + if (crc != le16_to_cpu(footer.crc)) { + err = -EPROTO; + status.code = UCMB_STAT_ECRC; goto out_send_status; + } + if (copy_to_user(user_buf, buf, size)) { + err = -EFAULT; + status.code = UCMB_STAT_ENOMEM; + goto out_send_status; + } + + status.code = UCMB_STAT_OK; err = 0; out_send_status: - status.code = err ? UCMB_STAT_ENOMEM : UCMB_STAT_OK; res = spi_write(ucmb->sdev, (u8 *)&status, sizeof(status)); if (res && !err) err = res; @@ -167,7 +197,6 @@ out: return err ? err : size; } -/* FIXME offp */ static ssize_t ucmb_write(struct file *filp, const char __user *user_buf, size_t size, loff_t *offp) { @@ -175,8 +204,10 @@ static ssize_t ucmb_write(struct file *filp, const char __user *user_buf, u8 *buf; int err; struct ucmb_message_hdr hdr = { .magic = cpu_to_le16(UCMB_MAGIC), }; + struct ucmb_message_footer footer = { .crc = 0xFFFF, }; struct ucmb_status status; struct spi_transfer spi_hdr_xfer; + struct spi_transfer spi_footer_xfer; struct spi_transfer spi_data_xfer; struct spi_message spi_msg; @@ -192,6 +223,10 @@ static ssize_t ucmb_write(struct file *filp, const char __user *user_buf, goto out_free; hdr.len = cpu_to_le16(size); + footer.crc = crc16(footer.crc, &hdr, sizeof(hdr)); + footer.crc = crc16(footer.crc, buf, size); + footer.crc ^= 0xFFFF; + spi_message_init(&spi_msg); memset(&spi_hdr_xfer, 0, sizeof(spi_hdr_xfer)); @@ -204,18 +239,28 @@ static ssize_t ucmb_write(struct file *filp, const char __user *user_buf, spi_data_xfer.len = size; spi_message_add_tail(&spi_data_xfer, &spi_msg); + memset(&spi_footer_xfer, 0, sizeof(spi_footer_xfer)); + spi_footer_xfer.tx_buf = &footer; + spi_footer_xfer.len = sizeof(footer); + spi_message_add_tail(&spi_footer_xfer, &spi_msg); + /* Send the message, including header. */ err = spi_sync(ucmb->sdev, &spi_msg); if (err) goto out_free; /* The microcontroller deserves some time to process the message. */ - msleep(1); + if (ucmb->msg_delay_ms) + msleep(ucmb->msg_delay_ms); /* Get the status code. */ err = spi_read(ucmb->sdev, (u8 *)&status, sizeof(status)); if (err) goto out_free; +#ifdef DEBUG + printk(KERN_DEBUG PFX "Sent message. Status report: 0x%04X 0x%04X\n", + le16_to_cpu(status.magic), le16_to_cpu(status.code)); +#endif err = -EPROTO; if (status.magic != cpu_to_le16(UCMB_MAGIC)) goto out_free; @@ -244,6 +289,7 @@ static int __devinit ucmb_probe(struct platform_device *pdev) ucmb = kzalloc(sizeof(struct ucmb), GFP_KERNEL); if (!ucmb) return -ENOMEM; + ucmb->msg_delay_ms = pdata->msg_delay_ms; /* Create the SPI GPIO bus master. */ @@ -280,9 +326,9 @@ static int __devinit ucmb_probe(struct platform_device *pdev) printk(KERN_ERR PFX "Failed to allocate SPI device\n"); goto err_unreg_spi_gpio_pdev; } - ucmb->sdev->max_speed_hz = 500000; + ucmb->sdev->max_speed_hz = pdata->max_speed_hz; ucmb->sdev->chip_select = 0; - ucmb->sdev->mode = SPI_MODE_0; + ucmb->sdev->mode = pdata->mode; strlcpy(ucmb->sdev->modalias, "ucmb", /* We are the SPI driver. */ sizeof(ucmb->sdev->modalias)); ucmb->sdev->controller_data = (void *)pdata->gpio_cs; diff --git a/package/ucmb/driver/ucmb.h b/package/ucmb/driver/ucmb.h new file mode 100644 index 0000000..94fdc64 --- /dev/null +++ b/package/ucmb/driver/ucmb.h @@ -0,0 +1,38 @@ +#ifndef LINUX_UCMB_H_ +#define LINUX_UCMB_H_ + +#include <linux/types.h> + +/** + * struct ucmb_platform_data - UCMB device descriptor + * + * @name: The name of the device. This will also be the name of + * the misc char device. + * + * @gpio_cs: The chipselect GPIO pin. Can be SPI_GPIO_NO_CHIPSELECT. + * @gpio_sck: The clock GPIO pin. + * @gpio_miso: The master-in slave-out GPIO pin. + * @gpio_mosi: The master-out slave-in GPIO pin. + * + * @mode: The SPI bus mode. SPI_MODE_* + * @max_speed_hz: The bus speed, in Hz. If zero the speed is not limited. + * @msg_delay_ms: The message delay time, in milliseconds. + * This is the time the microcontroller takes to process + * one message. + */ +struct ucmb_platform_data { + const char *name; + + unsigned long gpio_cs; + unsigned int gpio_sck; + unsigned int gpio_miso; + unsigned int gpio_mosi; + + u8 mode; + u32 max_speed_hz; + unsigned int msg_delay_ms; + + struct platform_device *pdev; /* internal */ +}; + +#endif /* LINUX_UCMB_H_ */ diff --git a/package/ucmb/src/ucmb.h b/package/ucmb/src/ucmb.h deleted file mode 100644 index cce4e74..0000000 --- a/package/ucmb/src/ucmb.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef LINUX_UCMB_H_ -#define LINUX_UCMB_H_ - -struct ucmb_platform_data { - const char *name; - unsigned long gpio_cs; - unsigned int gpio_sck; - unsigned int gpio_miso; - unsigned int gpio_mosi; - - struct platform_device *pdev; /* internal */ -}; - -#endif /* LINUX_UCMB_H_ */ |